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 */ |
