diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-05-17 11:11:44 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-05-17 11:11:44 -0300 |
commit | d9f40e3f6fb61650240c47d548bee69b24b07859 (patch) | |
tree | ab01022b3e3bc6bdb800423c97095a9423e0a798 /lparser.c | |
parent | 347d6961ac14213264c7176e3d125c9ba8475b01 (diff) | |
download | lua-d9f40e3f6fb61650240c47d548bee69b24b07859.tar.gz lua-d9f40e3f6fb61650240c47d548bee69b24b07859.tar.bz2 lua-d9f40e3f6fb61650240c47d548bee69b24b07859.zip |
First implementation for 'const' variables
A variable can be declared const, which means it cannot be assigned to,
with the syntax 'local <const> name = exp'.
Diffstat (limited to 'lparser.c')
-rw-r--r-- | lparser.c | 109 |
1 files changed, 89 insertions, 20 deletions
@@ -156,6 +156,13 @@ static void init_exp (expdesc *e, expkind k, int i) { | |||
156 | } | 156 | } |
157 | 157 | ||
158 | 158 | ||
159 | static void init_var (expdesc *e, expkind k, int i) { | ||
160 | e->f = e->t = NO_JUMP; | ||
161 | e->k = k; | ||
162 | e->u.var.idx = i; | ||
163 | } | ||
164 | |||
165 | |||
159 | static void codestring (LexState *ls, expdesc *e, TString *s) { | 166 | static void codestring (LexState *ls, expdesc *e, TString *s) { |
160 | init_exp(e, VK, luaK_stringK(ls->fs, s)); | 167 | init_exp(e, VK, luaK_stringK(ls->fs, s)); |
161 | } | 168 | } |
@@ -187,32 +194,83 @@ static int registerlocalvar (LexState *ls, TString *varname) { | |||
187 | /* | 194 | /* |
188 | ** Create a new local variable with the given 'name'. | 195 | ** Create a new local variable with the given 'name'. |
189 | */ | 196 | */ |
190 | static void new_localvar (LexState *ls, TString *name) { | 197 | static Vardesc *new_localvar (LexState *ls, TString *name) { |
191 | FuncState *fs = ls->fs; | 198 | FuncState *fs = ls->fs; |
192 | Dyndata *dyd = ls->dyd; | 199 | Dyndata *dyd = ls->dyd; |
200 | Vardesc *var; | ||
193 | int reg = registerlocalvar(ls, name); | 201 | int reg = registerlocalvar(ls, name); |
194 | checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, | 202 | checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, |
195 | MAXVARS, "local variables"); | 203 | MAXVARS, "local variables"); |
196 | luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, | 204 | luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, |
197 | dyd->actvar.size, Vardesc, MAX_INT, "local variables"); | 205 | dyd->actvar.size, Vardesc, MAX_INT, "local variables"); |
198 | dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); | 206 | var = &dyd->actvar.arr[dyd->actvar.n++]; |
207 | var->idx = cast(short, reg); | ||
208 | var->name = name; | ||
209 | var->ro = 0; | ||
210 | return var; | ||
199 | } | 211 | } |
200 | 212 | ||
201 | #define new_localvarliteral(ls,v) \ | 213 | #define new_localvarliteral(ls,v) \ |
202 | new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); | 214 | new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); |
203 | 215 | ||
204 | 216 | ||
217 | |||
218 | /* | ||
219 | ** Return the "variable description" (Vardesc) of a given | ||
220 | ** variable | ||
221 | */ | ||
222 | static Vardesc *getlocalvardesc (FuncState *fs, int i) { | ||
223 | return &fs->ls->dyd->actvar.arr[fs->firstlocal + i]; | ||
224 | } | ||
225 | |||
205 | /* | 226 | /* |
206 | ** Get the debug-information entry for current variable 'i'. | 227 | ** Get the debug-information entry for current variable 'i'. |
207 | */ | 228 | */ |
208 | static LocVar *getlocvar (FuncState *fs, int i) { | 229 | static LocVar *getlocvar (FuncState *fs, int i) { |
209 | int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; | 230 | int idx = getlocalvardesc(fs, i)->idx; |
210 | lua_assert(idx < fs->nlocvars); | 231 | lua_assert(idx < fs->nlocvars); |
211 | return &fs->f->locvars[idx]; | 232 | return &fs->f->locvars[idx]; |
212 | } | 233 | } |
213 | 234 | ||
214 | 235 | ||
215 | /* | 236 | /* |
237 | ** Return the "variable description" (Vardesc) of a given | ||
238 | ** variable or upvalue | ||
239 | */ | ||
240 | static Vardesc *getvardesc (FuncState *fs, expdesc *e) { | ||
241 | if (e->k == VLOCAL) | ||
242 | return getlocalvardesc(fs, e->u.var.idx); | ||
243 | else if (e->k != VUPVAL) | ||
244 | return NULL; /* not a local variable */ | ||
245 | else { /* upvalue: must go up all levels up to the original local */ | ||
246 | int idx = e->u.var.idx; | ||
247 | for (;;) { | ||
248 | Upvaldesc *up = &fs->f->upvalues[idx]; | ||
249 | fs = fs->prev; /* must look at the previous level */ | ||
250 | idx = up->idx; /* at this index */ | ||
251 | if (fs == NULL) { /* no more levels? (can happen only with _ENV) */ | ||
252 | lua_assert(strcmp(getstr(up->name), LUA_ENV) == 0); | ||
253 | return NULL; | ||
254 | } | ||
255 | else if (up->instack) /* got to the original level? */ | ||
256 | return getlocalvardesc(fs, idx); | ||
257 | /* else repeat for previous level */ | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | static void check_readonly (LexState *ls, expdesc *e) { | ||
264 | Vardesc *vardesc = getvardesc(ls->fs, e); | ||
265 | if (vardesc && vardesc->ro) { /* is variable local and const? */ | ||
266 | const char *msg = luaO_pushfstring(ls->L, | ||
267 | "assignment to const variable '%s'", getstr(vardesc->name)); | ||
268 | luaK_semerror(ls, msg); /* error */ | ||
269 | } | ||
270 | } | ||
271 | |||
272 | |||
273 | /* | ||
216 | ** Start the scope for the last 'nvars' created variables. | 274 | ** Start the scope for the last 'nvars' created variables. |
217 | ** (debug info.) | 275 | ** (debug info.) |
218 | */ | 276 | */ |
@@ -259,7 +317,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { | |||
259 | while (oldsize < f->sizeupvalues) | 317 | while (oldsize < f->sizeupvalues) |
260 | f->upvalues[oldsize++].name = NULL; | 318 | f->upvalues[oldsize++].name = NULL; |
261 | f->upvalues[fs->nups].instack = (v->k == VLOCAL); | 319 | f->upvalues[fs->nups].instack = (v->k == VLOCAL); |
262 | f->upvalues[fs->nups].idx = cast_byte(v->u.info); | 320 | f->upvalues[fs->nups].idx = cast_byte(v->u.var.idx); |
263 | f->upvalues[fs->nups].name = name; | 321 | f->upvalues[fs->nups].name = name; |
264 | luaC_objbarrier(fs->ls->L, f, name); | 322 | luaC_objbarrier(fs->ls->L, f, name); |
265 | return fs->nups++; | 323 | return fs->nups++; |
@@ -304,7 +362,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { | |||
304 | else { | 362 | else { |
305 | int v = searchvar(fs, n); /* look up locals at current level */ | 363 | int v = searchvar(fs, n); /* look up locals at current level */ |
306 | if (v >= 0) { /* found? */ | 364 | if (v >= 0) { /* found? */ |
307 | init_exp(var, VLOCAL, v); /* variable is local */ | 365 | init_var(var, VLOCAL, v); /* variable is local */ |
308 | if (!base) | 366 | if (!base) |
309 | markupval(fs, v); /* local will be used as an upval */ | 367 | markupval(fs, v); /* local will be used as an upval */ |
310 | } | 368 | } |
@@ -317,7 +375,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { | |||
317 | /* else was LOCAL or UPVAL */ | 375 | /* else was LOCAL or UPVAL */ |
318 | idx = newupvalue(fs, n, var); /* will be a new upvalue */ | 376 | idx = newupvalue(fs, n, var); /* will be a new upvalue */ |
319 | } | 377 | } |
320 | init_exp(var, VUPVAL, idx); /* new or old upvalue */ | 378 | init_var(var, VUPVAL, idx); /* new or old upvalue */ |
321 | } | 379 | } |
322 | } | 380 | } |
323 | } | 381 | } |
@@ -1199,20 +1257,20 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { | |||
1199 | for (; lh; lh = lh->prev) { /* check all previous assignments */ | 1257 | for (; lh; lh = lh->prev) { /* check all previous assignments */ |
1200 | if (vkisindexed(lh->v.k)) { /* assignment to table field? */ | 1258 | if (vkisindexed(lh->v.k)) { /* assignment to table field? */ |
1201 | if (lh->v.k == VINDEXUP) { /* is table an upvalue? */ | 1259 | if (lh->v.k == VINDEXUP) { /* is table an upvalue? */ |
1202 | if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) { | 1260 | if (v->k == VUPVAL && lh->v.u.ind.t == v->u.var.idx) { |
1203 | conflict = 1; /* table is the upvalue being assigned now */ | 1261 | conflict = 1; /* table is the upvalue being assigned now */ |
1204 | lh->v.k = VINDEXSTR; | 1262 | lh->v.k = VINDEXSTR; |
1205 | lh->v.u.ind.t = extra; /* assignment will use safe copy */ | 1263 | lh->v.u.ind.t = extra; /* assignment will use safe copy */ |
1206 | } | 1264 | } |
1207 | } | 1265 | } |
1208 | else { /* table is a register */ | 1266 | else { /* table is a register */ |
1209 | if (v->k == VLOCAL && lh->v.u.ind.t == v->u.info) { | 1267 | if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.idx) { |
1210 | conflict = 1; /* table is the local being assigned now */ | 1268 | conflict = 1; /* table is the local being assigned now */ |
1211 | lh->v.u.ind.t = extra; /* assignment will use safe copy */ | 1269 | lh->v.u.ind.t = extra; /* assignment will use safe copy */ |
1212 | } | 1270 | } |
1213 | /* is index the local being assigned? */ | 1271 | /* is index the local being assigned? */ |
1214 | if (lh->v.k == VINDEXED && v->k == VLOCAL && | 1272 | if (lh->v.k == VINDEXED && v->k == VLOCAL && |
1215 | lh->v.u.ind.idx == v->u.info) { | 1273 | lh->v.u.ind.idx == v->u.var.idx) { |
1216 | conflict = 1; | 1274 | conflict = 1; |
1217 | lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ | 1275 | lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ |
1218 | } | 1276 | } |
@@ -1222,7 +1280,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { | |||
1222 | if (conflict) { | 1280 | if (conflict) { |
1223 | /* copy upvalue/local value to a temporary (in position 'extra') */ | 1281 | /* copy upvalue/local value to a temporary (in position 'extra') */ |
1224 | OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; | 1282 | OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; |
1225 | luaK_codeABC(fs, op, extra, v->u.info, 0); | 1283 | luaK_codeABC(fs, op, extra, v->u.var.idx, 0); |
1226 | luaK_reserveregs(fs, 1); | 1284 | luaK_reserveregs(fs, 1); |
1227 | } | 1285 | } |
1228 | } | 1286 | } |
@@ -1237,6 +1295,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { | |||
1237 | static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { | 1295 | static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { |
1238 | expdesc e; | 1296 | expdesc e; |
1239 | check_condition(ls, vkisvar(lh->v.k), "syntax error"); | 1297 | check_condition(ls, vkisvar(lh->v.k), "syntax error"); |
1298 | check_readonly(ls, &lh->v); | ||
1240 | if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */ | 1299 | if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */ |
1241 | struct LHS_assign nv; | 1300 | struct LHS_assign nv; |
1242 | nv.prev = lh; | 1301 | nv.prev = lh; |
@@ -1615,20 +1674,30 @@ static void commonlocalstat (LexState *ls) { | |||
1615 | } | 1674 | } |
1616 | 1675 | ||
1617 | 1676 | ||
1618 | static void tocloselocalstat (LexState *ls) { | 1677 | static void tocloselocalstat (LexState *ls, Vardesc *var) { |
1619 | FuncState *fs = ls->fs; | 1678 | FuncState *fs = ls->fs; |
1679 | var->ro = 1; /* to-be-closed variables are always read-only */ | ||
1680 | markupval(fs, fs->nactvar); | ||
1681 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | ||
1682 | luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); | ||
1683 | } | ||
1684 | |||
1685 | |||
1686 | static void attriblocalstat (LexState *ls) { | ||
1687 | Vardesc *var; | ||
1620 | TString *attr = str_checkname(ls); | 1688 | TString *attr = str_checkname(ls); |
1621 | if (strcmp(getstr(attr), "toclose") != 0) | ||
1622 | luaK_semerror(ls, | ||
1623 | luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); | ||
1624 | testnext(ls, '>'); | 1689 | testnext(ls, '>'); |
1625 | new_localvar(ls, str_checkname(ls)); | 1690 | var = new_localvar(ls, str_checkname(ls)); |
1626 | checknext(ls, '='); | 1691 | checknext(ls, '='); |
1627 | exp1(ls); | 1692 | exp1(ls); |
1628 | markupval(fs, fs->nactvar); | ||
1629 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | ||
1630 | adjustlocalvars(ls, 1); | 1693 | adjustlocalvars(ls, 1); |
1631 | luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); | 1694 | if (strcmp(getstr(attr), "const") == 0) |
1695 | var->ro = 1; /* set variable as read-only */ | ||
1696 | else if (strcmp(getstr(attr), "toclose") == 0) | ||
1697 | tocloselocalstat(ls, var); | ||
1698 | else | ||
1699 | luaK_semerror(ls, | ||
1700 | luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); | ||
1632 | } | 1701 | } |
1633 | 1702 | ||
1634 | 1703 | ||
@@ -1636,7 +1705,7 @@ static void localstat (LexState *ls) { | |||
1636 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] | 1705 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] |
1637 | | LOCAL *toclose NAME '=' exp */ | 1706 | | LOCAL *toclose NAME '=' exp */ |
1638 | if (testnext(ls, '<')) | 1707 | if (testnext(ls, '<')) |
1639 | tocloselocalstat(ls); | 1708 | attriblocalstat(ls); |
1640 | else | 1709 | else |
1641 | commonlocalstat(ls); | 1710 | commonlocalstat(ls); |
1642 | } | 1711 | } |
@@ -1801,7 +1870,7 @@ static void mainfunc (LexState *ls, FuncState *fs) { | |||
1801 | expdesc v; | 1870 | expdesc v; |
1802 | open_func(ls, fs, &bl); | 1871 | open_func(ls, fs, &bl); |
1803 | setvararg(fs, 0); /* main function is always declared vararg */ | 1872 | setvararg(fs, 0); /* main function is always declared vararg */ |
1804 | init_exp(&v, VLOCAL, 0); /* create and... */ | 1873 | init_var(&v, VLOCAL, 0); /* create and... */ |
1805 | newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ | 1874 | newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ |
1806 | luaX_next(ls); /* read first token */ | 1875 | luaX_next(ls); /* read first token */ |
1807 | statlist(ls); /* parse main body */ | 1876 | statlist(ls); /* parse main body */ |