-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparselabels.cpp
More file actions
151 lines (129 loc) · 4.81 KB
/
parselabels.cpp
File metadata and controls
151 lines (129 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
** $Id: lparser.c $
** Lua Parser - Label and Goto Management
** See Copyright Notice in lua.h
*/
#define lparser_c
#define LUA_CORE
#include "lprefix.h"
#include <cstring>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
/* because all strings are unified by the scanner, the parser
can use pointer equality for string equality */
inline bool eqstr(const TString* a, const TString* b) noexcept {
return (a) == (b);
}
/*
** nodes for block list (list of active blocks)
*/
typedef struct BlockCnt {
struct BlockCnt *previous; /* chain */
int firstlabel; /* index of first label in this block */
int firstgoto; /* index of first pending goto in this block */
short nactvar; /* number of active declarations at block entry */
lu_byte upval; /* true if some variable in the block is an upvalue */
lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */
lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */
} BlockCnt;
/*
** Generates an error that a goto jumps into the scope of some
** variable declaration.
*/
l_noret LexState::jumpscopeerror(FuncState *funcState, Labeldesc *gt) {
TString *tsname = funcState->getlocalvardesc(gt->nactvar)->vd.name;
const char *varname = (tsname != nullptr) ? getstr(tsname) : "*";
semerror("<goto %s> at line %d jumps into the scope of '%s'",
getstr(gt->name), gt->line, varname); /* raise the error */
}
/*
** Closes the goto at index 'g' to given 'label' and removes it
** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
** The goto needs a CLOSE if it jumps out of a block with upvalues,
** or out of the scope of some variable and the block has upvalues
** (signaled by parameter 'bup').
*/
void LexState::closegoto(FuncState *funcState, int g, Labeldesc *label, int bup) {
int i;
Labellist *gl = &getDyndata()->gt; /* list of gotos */
Labeldesc *gt = &(*gl)[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
jumpscopeerror(funcState, gt);
if (gt->close ||
(label->nactvar < gt->nactvar && bup)) { /* needs close? */
lu_byte stklevel = funcState->reglevel(label->nactvar);
/* move jump to CLOSE position */
funcState->getProto()->getCode()[gt->pc + 1] = funcState->getProto()->getCode()[gt->pc];
/* put CLOSE instruction at original position */
funcState->getProto()->getCode()[gt->pc] = CREATE_ABCk(OP_CLOSE, stklevel, 0, 0, 0);
gt->pc++; /* must point to jump instruction */
}
funcState->patchlist(gt->pc, label->pc); /* goto jumps to label */
for (i = g; i < gl->getN() - 1; i++) /* remove goto from pending list */
(*gl)[i] = (*gl)[i + 1];
gl->setN(gl->getN() - 1);
}
/*
** Search for an active label with the given name, starting at
** index 'ilb' (so that it can search for all labels in current block
** or all labels in current function).
*/
Labeldesc *LexState::findlabel(TString *name, int ilb) {
Dyndata *dynData = getDyndata();
for (; ilb < dynData->label.getN(); ilb++) {
Labeldesc *lb = &dynData->label[ilb];
if (eqstr(lb->name, name)) /* correct label? */
return lb;
}
return nullptr; /* label not found */
}
/*
** Adds a new label/goto in the corresponding list.
*/
int LexState::newlabelentry(FuncState *funcState, Labellist *l, TString *name, int line, int pc) {
int n = l->getN();
Labeldesc* desc = l->allocateNew(); /* LuaVector automatically grows */
desc->name = name;
desc->line = line;
desc->nactvar = funcState->getNumActiveVars();
desc->close = 0;
desc->pc = pc;
return n;
}
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
void LexState::createlabel(FuncState *funcState, TString *name, int line, int last) {
// FuncState passed as parameter
Labellist *ll = &getDyndata()->label;
int l = newlabelentry(funcState, ll, name, line, funcState->getlabel());
if (last) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
(*ll)[l].nactvar = funcState->getBlock()->nactvar;
}
}
/*
** generates an error for an undefined 'goto'.
*/
l_noret LexState::undefgoto([[maybe_unused]] FuncState *funcState, Labeldesc *gt) {
/* breaks are checked when created, cannot be undefined */
lua_assert(!eqstr(gt->name, getBreakName()));
semerror("no visible label '%s' for <goto> at line %d",
getstr(gt->name), gt->line);
}