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:
Roberto Ierusalimschy
2025-05-20 17:36:05 -03:00
parent 6d53701c7a
commit be05c44481
4 changed files with 45 additions and 15 deletions

View File

@@ -54,7 +54,6 @@ typedef struct BlockCnt {
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 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;
@@ -399,22 +398,35 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
/*
** Look for an active variable with the name 'n' in the
** 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) {
int i;
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
Vardesc *vd = getlocalvardesc(fs, i);
if (vd->vd.name == NULL) { /* 'global *'? */
if (var->u.info == -1) { /* no previous collective declaration? */
var->u.info = fs->firstlocal + i; /* will use this one as default */
if (varglobal(vd)) { /* global declaration? */
if (vd->vd.name == NULL) { /* collective declaration? */
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? */
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
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 */
init_var(fs, var, i);
return cast_int(var->k);
@@ -486,7 +498,7 @@ static void buildvar (LexState *ls, TString *varname, expdesc *var) {
expdesc key;
int info = var->u.info;
/* 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));
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
if (var->k == VGLOBAL)
@@ -692,10 +704,6 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
bl->upval = 0;
/* inherit 'insidetbc' from enclosing block */
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 */
fs->bl = bl;
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) {
/* stat -> GLOBAL globalfunc | GLOBAL globalstat */
luaX_next(ls); /* skip 'global' */
ls->fs->bl->globdec = 1; /* in the scope of a global declaration */
if (testnext(ls, TK_FUNCTION))
globalfunc(ls, line);
else