First implementation for 'const' variables · lua/lua@d9f40e3 · GitHub
Skip to content

Commit d9f40e3

Browse files
committed
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'.
1 parent 347d696 commit d9f40e3

7 files changed

Lines changed: 205 additions & 56 deletions

File tree

‎lcode.c‎

Lines changed: 21 additions & 15 deletions

‎lparser.c‎

Lines changed: 89 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ static void init_exp (expdesc *e, expkind k, int i) {
156156
}
157157

158158

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+
159166
static void codestring (LexState *ls, expdesc *e, TString *s) {
160167
init_exp(e, VK, luaK_stringK(ls->fs, s));
161168
}
@@ -187,31 +194,82 @@ static int registerlocalvar (LexState *ls, TString *varname) {
187194
/*
188195
** Create a new local variable with the given 'name'.
189196
*/
190-
static void new_localvar (LexState *ls, TString *name) {
197+
static Vardesc *new_localvar (LexState *ls, TString *name) {
191198
FuncState *fs = ls->fs;
192199
Dyndata *dyd = ls->dyd;
200+
Vardesc *var;
193201
int reg = registerlocalvar(ls, name);
194202
checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
195203
MAXVARS, "local variables");
196204
luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
197205
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;
199211
}
200212

201213
#define new_localvarliteral(ls,v) \
202214
new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1));
203215

204216

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+
205226
/*
206227
** Get the debug-information entry for current variable 'i'.
207228
*/
208229
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;
210231
lua_assert(idx < fs->nlocvars);
211232
return &fs->f->locvars[idx];
212233
}
213234

214235

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+
215273
/*
216274
** Start the scope for the last 'nvars' created variables.
217275
** (debug info.)
@@ -259,7 +317,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
259317
while (oldsize < f->sizeupvalues)
260318
f->upvalues[oldsize++].name = NULL;
261319
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);
263321
f->upvalues[fs->nups].name = name;
264322
luaC_objbarrier(fs->ls->L, f, name);
265323
return fs->nups++;
@@ -304,7 +362,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
304362
else {
305363
int v = searchvar(fs, n); /* look up locals at current level */
306364
if (v >= 0) { /* found? */
307-
init_exp(var, VLOCAL, v); /* variable is local */
365+
init_var(var, VLOCAL, v); /* variable is local */
308366
if (!base)
309367
markupval(fs, v); /* local will be used as an upval */
310368
}
@@ -317,7 +375,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
317375
/* else was LOCAL or UPVAL */
318376
idx = newupvalue(fs, n, var); /* will be a new upvalue */
319377
}
320-
init_exp(var, VUPVAL, idx); /* new or old upvalue */
378+
init_var(var, VUPVAL, idx); /* new or old upvalue */
321379
}
322380
}
323381
}
@@ -1199,20 +1257,20 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
11991257
for (; lh; lh = lh->prev) { /* check all previous assignments */
12001258
if (vkisindexed(lh->v.k)) { /* assignment to table field? */
12011259
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) {
12031261
conflict = 1; /* table is the upvalue being assigned now */
12041262
lh->v.k = VINDEXSTR;
12051263
lh->v.u.ind.t = extra; /* assignment will use safe copy */
12061264
}
12071265
}
12081266
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) {
12101268
conflict = 1; /* table is the local being assigned now */
12111269
lh->v.u.ind.t = extra; /* assignment will use safe copy */
12121270
}
12131271
/* is index the local being assigned? */
12141272
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) {
12161274
conflict = 1;
12171275
lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
12181276
}
@@ -1222,7 +1280,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
12221280
if (conflict) {
12231281
/* copy upvalue/local value to a temporary (in position 'extra') */
12241282
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);
12261284
luaK_reserveregs(fs, 1);
12271285
}
12281286
}
@@ -1237,6 +1295,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
12371295
static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) {
12381296
expdesc e;
12391297
check_condition(ls, vkisvar(lh->v.k), "syntax error");
1298+
check_readonly(ls, &lh->v);
12401299
if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */
12411300
struct LHS_assign nv;
12421301
nv.prev = lh;
@@ -1615,28 +1674,38 @@ static void commonlocalstat (LexState *ls) {
16151674
}
16161675

16171676

1618-
static void tocloselocalstat (LexState *ls) {
1677+
static void tocloselocalstat (LexState *ls, Vardesc *var) {
16191678
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;
16201688
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)));
16241689
testnext(ls, '>');
1625-
new_localvar(ls, str_checkname(ls));
1690+
var = new_localvar(ls, str_checkname(ls));
16261691
checknext(ls, '=');
16271692
exp1(ls);
1628-
markupval(fs, fs->nactvar);
1629-
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
16301693
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)));
16321701
}
16331702

16341703

16351704
static void localstat (LexState *ls) {
16361705
/* stat -> LOCAL NAME {',' NAME} ['=' explist]
16371706
| LOCAL *toclose NAME '=' exp */
16381707
if (testnext(ls, '<'))
1639-
tocloselocalstat(ls);
1708+
attriblocalstat(ls);
16401709
else
16411710
commonlocalstat(ls);
16421711
}
@@ -1801,7 +1870,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
18011870
expdesc v;
18021871
open_func(ls, fs, &bl);
18031872
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... */
18051874
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
18061875
luaX_next(ls); /* read first token */
18071876
statlist(ls); /* parse main body */

‎lparser.h‎

Lines changed: 9 additions & 4 deletions

0 commit comments

Comments
 (0)