aboutsummaryrefslogtreecommitdiff
path: root/lparser.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-05-17 11:11:44 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-05-17 11:11:44 -0300
commitd9f40e3f6fb61650240c47d548bee69b24b07859 (patch)
treeab01022b3e3bc6bdb800423c97095a9423e0a798 /lparser.c
parent347d6961ac14213264c7176e3d125c9ba8475b01 (diff)
downloadlua-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.c109
1 files changed, 89 insertions, 20 deletions
diff --git a/lparser.c b/lparser.c
index 4e6c27fe..7c23710a 100644
--- a/lparser.c
+++ b/lparser.c
@@ -156,6 +156,13 @@ static void init_exp (expdesc *e, expkind k, int i) {
156} 156}
157 157
158 158
159static 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
159static void codestring (LexState *ls, expdesc *e, TString *s) { 166static 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*/
190static void new_localvar (LexState *ls, TString *name) { 197static 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*/
222static 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*/
208static LocVar *getlocvar (FuncState *fs, int i) { 229static 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*/
240static 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
263static 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) {
1237static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { 1295static 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
1618static void tocloselocalstat (LexState *ls) { 1677static 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
1686static 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 */