New way to control preambular declaration
Validity of the preambular global declaration in controled together with all declarations, when checking variable names.
This commit is contained in:
33
lparser.c
33
lparser.c
@@ -54,7 +54,6 @@ typedef struct BlockCnt {
|
|||||||
lu_byte upval; /* true if some variable in the block is an upvalue */
|
lu_byte upval; /* true if some variable in the block is an upvalue */
|
||||||
lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */
|
lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */
|
||||||
lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */
|
lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */
|
||||||
lu_byte globdec; /* true if inside the scope of any global declaration */
|
|
||||||
} BlockCnt;
|
} BlockCnt;
|
||||||
|
|
||||||
|
|
||||||
@@ -399,22 +398,35 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|||||||
/*
|
/*
|
||||||
** Look for an active 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. While searching,
|
||||||
|
** var->u.info==-1 means that the preambular global declaration is
|
||||||
|
** active (the default while there is no other global declaration);
|
||||||
|
** var->u.info==-2 means there is no active collective declaration
|
||||||
|
** (some previous global declaration but no collective declaration);
|
||||||
|
** and var->u.info>=0 points to the inner-most (the first one found)
|
||||||
|
** collective declaration, if there is one.
|
||||||
*/
|
*/
|
||||||
static int searchvar (FuncState *fs, TString *n, expdesc *var) {
|
static int searchvar (FuncState *fs, TString *n, expdesc *var) {
|
||||||
int i;
|
int i;
|
||||||
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
|
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
|
||||||
Vardesc *vd = getlocalvardesc(fs, i);
|
Vardesc *vd = getlocalvardesc(fs, i);
|
||||||
if (vd->vd.name == NULL) { /* 'global *'? */
|
if (varglobal(vd)) { /* global declaration? */
|
||||||
if (var->u.info == -1) { /* no previous collective declaration? */
|
if (vd->vd.name == NULL) { /* collective declaration? */
|
||||||
var->u.info = fs->firstlocal + i; /* will use this one as default */
|
if (var->u.info < 0) /* no previous collective declaration? */
|
||||||
|
var->u.info = fs->firstlocal + i; /* this is the first one */
|
||||||
|
}
|
||||||
|
else { /* global name */
|
||||||
|
if (eqstr(n, vd->vd.name)) { /* found? */
|
||||||
|
init_exp(var, VGLOBAL, fs->firstlocal + i);
|
||||||
|
return VGLOBAL;
|
||||||
|
}
|
||||||
|
else if (var->u.info == -1) /* active preambular declaration? */
|
||||||
|
var->u.info = -2; /* invalidate preambular declaration */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (eqstr(n, vd->vd.name)) { /* found? */
|
else if (eqstr(n, vd->vd.name)) { /* found? */
|
||||||
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)
|
|
||||||
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);
|
||||||
@@ -486,7 +498,7 @@ static void buildvar (LexState *ls, TString *varname, expdesc *var) {
|
|||||||
expdesc key;
|
expdesc key;
|
||||||
int info = var->u.info;
|
int info = var->u.info;
|
||||||
/* global by default in the scope of a global declaration? */
|
/* global by default in the scope of a global declaration? */
|
||||||
if (info == -1 && fs->bl->globdec)
|
if (info == -2)
|
||||||
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)
|
||||||
@@ -692,10 +704,6 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
|
|||||||
bl->upval = 0;
|
bl->upval = 0;
|
||||||
/* inherit 'insidetbc' from enclosing block */
|
/* inherit 'insidetbc' from enclosing block */
|
||||||
bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc);
|
bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc);
|
||||||
/* inherit 'globdec' from enclosing block or enclosing function */
|
|
||||||
bl->globdec = fs->bl != NULL ? fs->bl->globdec
|
|
||||||
: fs->prev != NULL ? fs->prev->bl->globdec
|
|
||||||
: 0; /* chunk's first block */
|
|
||||||
bl->previous = fs->bl; /* link block in function's block list */
|
bl->previous = fs->bl; /* link block in function's block list */
|
||||||
fs->bl = bl;
|
fs->bl = bl;
|
||||||
lua_assert(fs->freereg == luaY_nvarstack(fs));
|
lua_assert(fs->freereg == luaY_nvarstack(fs));
|
||||||
@@ -1855,7 +1863,6 @@ static void globalfunc (LexState *ls, int line) {
|
|||||||
static void globalstatfunc (LexState *ls, int line) {
|
static void globalstatfunc (LexState *ls, int line) {
|
||||||
/* stat -> GLOBAL globalfunc | GLOBAL globalstat */
|
/* stat -> GLOBAL globalfunc | GLOBAL globalstat */
|
||||||
luaX_next(ls); /* skip 'global' */
|
luaX_next(ls); /* skip 'global' */
|
||||||
ls->fs->bl->globdec = 1; /* in the scope of a global declaration */
|
|
||||||
if (testnext(ls, TK_FUNCTION))
|
if (testnext(ls, TK_FUNCTION))
|
||||||
globalfunc(ls, line);
|
globalfunc(ls, line);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ typedef struct expdesc {
|
|||||||
/* variables that live in registers */
|
/* variables that live in registers */
|
||||||
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
||||||
|
|
||||||
|
/* test for global variables */
|
||||||
|
#define varglobal(v) ((v)->vd.kind >= GDKREG)
|
||||||
|
|
||||||
|
|
||||||
/* description of an active variable */
|
/* description of an active variable */
|
||||||
typedef union Vardesc {
|
typedef union Vardesc {
|
||||||
|
|||||||
@@ -349,9 +349,11 @@ end, "crl")
|
|||||||
|
|
||||||
|
|
||||||
function f(a,b)
|
function f(a,b)
|
||||||
global collectgarbage, assert, g, string
|
-- declare some globals to check that they don't interfere with 'getlocal'
|
||||||
|
global collectgarbage
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
local _, x = debug.getlocal(1, 1)
|
local _, x = debug.getlocal(1, 1)
|
||||||
|
global assert, g, string
|
||||||
local _, y = debug.getlocal(1, 2)
|
local _, y = debug.getlocal(1, 2)
|
||||||
assert(x == a and y == b)
|
assert(x == a and y == b)
|
||||||
assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
|
assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
|
||||||
@@ -387,7 +389,9 @@ function g (...)
|
|||||||
f(AAAA,B)
|
f(AAAA,B)
|
||||||
assert(AAAA == "pera" and B == "manga")
|
assert(AAAA == "pera" and B == "manga")
|
||||||
do
|
do
|
||||||
|
global *
|
||||||
local B = 13
|
local B = 13
|
||||||
|
global<const> assert
|
||||||
local x,y = debug.getlocal(1,5)
|
local x,y = debug.getlocal(1,5)
|
||||||
assert(x == 'B' and y == 13)
|
assert(x == 'B' and y == 13)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -364,7 +364,23 @@ do
|
|||||||
print(X) -- Ok to use
|
print(X) -- Ok to use
|
||||||
Y = 1 -- ERROR
|
Y = 1 -- ERROR
|
||||||
]], "assign to const variable 'Y'")
|
]], "assign to const variable 'Y'")
|
||||||
|
|
||||||
|
checkerr([[
|
||||||
|
global *;
|
||||||
|
Y = X -- Ok to use
|
||||||
|
global<const> *;
|
||||||
|
Y = 1 -- ERROR
|
||||||
|
]], "assign to const variable 'Y'")
|
||||||
|
|
||||||
|
global *
|
||||||
|
Y = 10
|
||||||
|
assert(_ENV.Y == 10)
|
||||||
|
global<const> *
|
||||||
|
local x = Y
|
||||||
|
global *
|
||||||
|
Y = x + Y
|
||||||
|
assert(_ENV.Y == 20)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
print'OK'
|
print'OK'
|
||||||
|
|||||||
Reference in New Issue
Block a user