Checks for read-only globals
This commit is contained in:
3
lcode.c
3
lcode.c
@@ -1315,8 +1315,8 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
|||||||
luaK_exp2anyreg(fs, t); /* put it in a register */
|
luaK_exp2anyreg(fs, t); /* put it in a register */
|
||||||
if (t->k == VUPVAL) {
|
if (t->k == VUPVAL) {
|
||||||
lu_byte temp = cast_byte(t->u.info); /* upvalue index */
|
lu_byte temp = cast_byte(t->u.info); /* upvalue index */
|
||||||
lua_assert(isKstr(fs, k));
|
|
||||||
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
|
t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
|
||||||
|
lua_assert(isKstr(fs, k));
|
||||||
t->u.ind.idx = cast(short, k->u.info); /* literal short string */
|
t->u.ind.idx = cast(short, k->u.info); /* literal short string */
|
||||||
t->k = VINDEXUP;
|
t->k = VINDEXUP;
|
||||||
}
|
}
|
||||||
@@ -1336,6 +1336,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
|||||||
t->k = VINDEXED;
|
t->k = VINDEXED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
t->u.ind.vidx = -1; /* by default, not a declared global */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
24
lparser.c
24
lparser.c
@@ -200,7 +200,7 @@ static int new_varkind (LexState *ls, TString *name, lu_byte kind) {
|
|||||||
luaY_checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
|
luaY_checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
|
||||||
MAXVARS, "local variables");
|
MAXVARS, "local variables");
|
||||||
luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
|
luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
|
||||||
dyd->actvar.size, Vardesc, SHRT_MAX, "local variables");
|
dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarationss");
|
||||||
var = &dyd->actvar.arr[dyd->actvar.n++];
|
var = &dyd->actvar.arr[dyd->actvar.n++];
|
||||||
var->vd.kind = kind; /* default */
|
var->vd.kind = kind; /* default */
|
||||||
var->vd.name = name;
|
var->vd.name = name;
|
||||||
@@ -276,7 +276,7 @@ static LocVar *localdebuginfo (FuncState *fs, int vidx) {
|
|||||||
static void init_var (FuncState *fs, expdesc *e, int vidx) {
|
static void init_var (FuncState *fs, expdesc *e, int vidx) {
|
||||||
e->f = e->t = NO_JUMP;
|
e->f = e->t = NO_JUMP;
|
||||||
e->k = VLOCAL;
|
e->k = VLOCAL;
|
||||||
e->u.var.vidx = cast(unsigned short, vidx);
|
e->u.var.vidx = cast(short, vidx);
|
||||||
e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx;
|
e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,8 +304,16 @@ static void check_readonly (LexState *ls, expdesc *e) {
|
|||||||
varname = up->name;
|
varname = up->name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VINDEXUP: case VINDEXSTR: case VINDEXED: {
|
||||||
|
int vidx = e->u.ind.vidx;
|
||||||
|
/* is it a read-only declared global? */
|
||||||
|
if (vidx != -1 && ls->dyd->actvar.arr[vidx].vd.kind == GDKCONST)
|
||||||
|
varname = ls->dyd->actvar.arr[vidx].vd.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return; /* other cases cannot be read-only */
|
lua_assert(e->k == VINDEXI); /* this one doesn't need any check */
|
||||||
|
return; /* integer index cannot be read-only */
|
||||||
}
|
}
|
||||||
if (varname)
|
if (varname)
|
||||||
luaK_semerror(ls, "attempt to assign to const variable '%s'",
|
luaK_semerror(ls, "attempt to assign to const variable '%s'",
|
||||||
@@ -391,7 +399,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Look for an active local variable with the name 'n' in the
|
** Look for an active variable with the name 'n' in the
|
||||||
** function 'fs'. If found, initialize 'var' with it and return
|
** function 'fs'. If found, initialize 'var' with it and return
|
||||||
** its expression kind; otherwise return -1.
|
** its expression kind; otherwise return -1.
|
||||||
*/
|
*/
|
||||||
@@ -403,7 +411,7 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) {
|
|||||||
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
||||||
init_exp(var, VCONST, fs->firstlocal + i);
|
init_exp(var, VCONST, fs->firstlocal + i);
|
||||||
else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST)
|
else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST)
|
||||||
init_exp(var, VGLOBAL, i);
|
init_exp(var, VGLOBAL, fs->firstlocal + i);
|
||||||
else /* local variable */
|
else /* local variable */
|
||||||
init_var(fs, var, i);
|
init_var(fs, var, i);
|
||||||
return cast_int(var->k);
|
return cast_int(var->k);
|
||||||
@@ -475,8 +483,11 @@ static void singlevar (LexState *ls, expdesc *var) {
|
|||||||
singlevaraux(fs, varname, var, 1);
|
singlevaraux(fs, varname, var, 1);
|
||||||
if (var->k == VGLOBAL) { /* global name? */
|
if (var->k == VGLOBAL) { /* global name? */
|
||||||
expdesc key;
|
expdesc key;
|
||||||
|
int info = var->u.info;
|
||||||
|
lua_assert(info == -1 ||
|
||||||
|
eqstr(ls->dyd->actvar.arr[info].vd.name, varname));
|
||||||
/* global by default in the scope of a global declaration? */
|
/* global by default in the scope of a global declaration? */
|
||||||
if (var->u.info == -1 && fs->bl->globdec)
|
if (info == -1 && fs->bl->globdec)
|
||||||
luaK_semerror(ls, "variable '%s' not declared", getstr(varname));
|
luaK_semerror(ls, "variable '%s' not declared", getstr(varname));
|
||||||
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
||||||
if (var->k == VGLOBAL)
|
if (var->k == VGLOBAL)
|
||||||
@@ -485,6 +496,7 @@ static void singlevar (LexState *ls, expdesc *var) {
|
|||||||
luaK_exp2anyregup(fs, var); /* but could be a constant */
|
luaK_exp2anyregup(fs, var); /* but could be a constant */
|
||||||
codestring(&key, varname); /* key is variable name */
|
codestring(&key, varname); /* key is variable name */
|
||||||
luaK_indexed(fs, var, &key); /* env[varname] */
|
luaK_indexed(fs, var, &key); /* env[varname] */
|
||||||
|
var->u.ind.vidx = cast(short, info); /* mark it as a declared global */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,11 +77,12 @@ typedef struct expdesc {
|
|||||||
int info; /* for generic use */
|
int info; /* for generic use */
|
||||||
struct { /* for indexed variables */
|
struct { /* for indexed variables */
|
||||||
short idx; /* index (R or "long" K) */
|
short idx; /* index (R or "long" K) */
|
||||||
|
short vidx; /* index in 'actvar.arr' or -1 if not a declared global */
|
||||||
lu_byte t; /* table (register or upvalue) */
|
lu_byte t; /* table (register or upvalue) */
|
||||||
} ind;
|
} ind;
|
||||||
struct { /* for local variables */
|
struct { /* for local variables */
|
||||||
lu_byte ridx; /* register holding the variable */
|
lu_byte ridx; /* register holding the variable */
|
||||||
unsigned short vidx; /* compiler index (in 'actvar.arr') */
|
short vidx; /* index in 'actvar.arr' */
|
||||||
} var;
|
} var;
|
||||||
} u;
|
} u;
|
||||||
int t; /* patch list of 'exit when true' */
|
int t; /* patch list of 'exit when true' */
|
||||||
@@ -101,7 +102,7 @@ typedef struct expdesc {
|
|||||||
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
||||||
|
|
||||||
|
|
||||||
/* description of an active local variable */
|
/* description of an active variable */
|
||||||
typedef union Vardesc {
|
typedef union Vardesc {
|
||||||
struct {
|
struct {
|
||||||
TValuefields; /* constant value (if it is a compile-time constant) */
|
TValuefields; /* constant value (if it is a compile-time constant) */
|
||||||
|
|||||||
@@ -178,6 +178,8 @@ A = nil
|
|||||||
|
|
||||||
|
|
||||||
do -- constants
|
do -- constants
|
||||||
|
global assert<const>, load, string, X
|
||||||
|
X = 1 -- not a constant
|
||||||
local a<const>, b, c<const> = 10, 20, 30
|
local a<const>, b, c<const> = 10, 20, 30
|
||||||
b = a + c + b -- 'b' is not constant
|
b = a + c + b -- 'b' is not constant
|
||||||
assert(a == 10 and b == 60 and c == 30)
|
assert(a == 10 and b == 60 and c == 30)
|
||||||
@@ -191,6 +193,9 @@ do -- constants
|
|||||||
checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
|
checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
|
||||||
checkro("foo", "local foo <const> = 10; function foo() end")
|
checkro("foo", "local foo <const> = 10; function foo() end")
|
||||||
checkro("foo", "local foo <const> = {}; function foo() end")
|
checkro("foo", "local foo <const> = {}; function foo() end")
|
||||||
|
checkro("foo", "global foo <const>; function foo() end")
|
||||||
|
checkro("XX", "global XX <const>; XX = 10")
|
||||||
|
checkro("XX", "local _ENV; global XX <const>; XX = 10")
|
||||||
|
|
||||||
checkro("z", [[
|
checkro("z", [[
|
||||||
local a, z <const>, b = 10;
|
local a, z <const>, b = 10;
|
||||||
@@ -201,6 +206,11 @@ do -- constants
|
|||||||
local a, var1 <const> = 10;
|
local a, var1 <const> = 10;
|
||||||
function foo() a = 20; z = function () var1 = 12; end end
|
function foo() a = 20; z = function () var1 = 12; end end
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
checkro("var1", [[
|
||||||
|
global a, var1 <const>, z;
|
||||||
|
local function foo() a = 20; z = function () var1 = 12; end end
|
||||||
|
]])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user