First implementation of global declarations
This commit is contained in:
111
lparser.c
111
lparser.c
@@ -30,8 +30,8 @@
|
||||
|
||||
|
||||
|
||||
/* maximum number of local variables per function (must be smaller
|
||||
than 250, due to the bytecode format) */
|
||||
/* maximum number of variable declarationss per function (must be
|
||||
smaller than 250, due to the bytecode format) */
|
||||
#define MAXVARS 200
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ 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;
|
||||
|
||||
|
||||
@@ -188,10 +189,10 @@ static short registerlocalvar (LexState *ls, FuncState *fs,
|
||||
|
||||
|
||||
/*
|
||||
** Create a new local variable with the given 'name' and given 'kind'.
|
||||
** Create a new variable with the given 'name' and given 'kind'.
|
||||
** Return its index in the function.
|
||||
*/
|
||||
static int new_localvarkind (LexState *ls, TString *name, lu_byte kind) {
|
||||
static int new_varkind (LexState *ls, TString *name, lu_byte kind) {
|
||||
lua_State *L = ls->L;
|
||||
FuncState *fs = ls->fs;
|
||||
Dyndata *dyd = ls->dyd;
|
||||
@@ -211,7 +212,7 @@ static int new_localvarkind (LexState *ls, TString *name, lu_byte kind) {
|
||||
** Create a new local variable with the given 'name' and regular kind.
|
||||
*/
|
||||
static int new_localvar (LexState *ls, TString *name) {
|
||||
return new_localvarkind(ls, name, VDKREG);
|
||||
return new_varkind(ls, name, VDKREG);
|
||||
}
|
||||
|
||||
#define new_localvarliteral(ls,v) \
|
||||
@@ -238,7 +239,7 @@ static Vardesc *getlocalvardesc (FuncState *fs, int vidx) {
|
||||
static lu_byte reglevel (FuncState *fs, int nvar) {
|
||||
while (nvar-- > 0) {
|
||||
Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */
|
||||
if (vd->vd.kind != RDKCTC) /* is in a register? */
|
||||
if (varinreg(vd)) /* is in a register? */
|
||||
return cast_byte(vd->vd.ridx + 1);
|
||||
}
|
||||
return 0; /* no variables in registers */
|
||||
@@ -259,7 +260,7 @@ lu_byte luaY_nvarstack (FuncState *fs) {
|
||||
*/
|
||||
static LocVar *localdebuginfo (FuncState *fs, int vidx) {
|
||||
Vardesc *vd = getlocalvardesc(fs, vidx);
|
||||
if (vd->vd.kind == RDKCTC)
|
||||
if (!varinreg(vd))
|
||||
return NULL; /* no debug info. for constants */
|
||||
else {
|
||||
int idx = vd->vd.pidx;
|
||||
@@ -401,7 +402,9 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) {
|
||||
if (eqstr(n, vd->vd.name)) { /* found? */
|
||||
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
||||
init_exp(var, VCONST, fs->firstlocal + i);
|
||||
else /* real variable */
|
||||
else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST)
|
||||
init_exp(var, VGLOBAL, i);
|
||||
else /* local variable */
|
||||
init_var(fs, var, i);
|
||||
return cast_int(var->k);
|
||||
}
|
||||
@@ -440,25 +443,24 @@ static void marktobeclosed (FuncState *fs) {
|
||||
** 'var' as 'void' as a flag.
|
||||
*/
|
||||
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
||||
if (fs == NULL) /* no more levels? */
|
||||
init_exp(var, VVOID, 0); /* default is global */
|
||||
else {
|
||||
int v = searchvar(fs, n, var); /* look up locals at current level */
|
||||
if (v >= 0) { /* found? */
|
||||
if (v == VLOCAL && !base)
|
||||
markupval(fs, var->u.var.vidx); /* local will be used as an upval */
|
||||
}
|
||||
else { /* not found as local at current level; try upvalues */
|
||||
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
||||
if (idx < 0) { /* not found? */
|
||||
int v = searchvar(fs, n, var); /* look up locals at current level */
|
||||
if (v >= 0) { /* found? */
|
||||
if (v == VLOCAL && !base)
|
||||
markupval(fs, var->u.var.vidx); /* local will be used as an upval */
|
||||
}
|
||||
else { /* not found as local at current level; try upvalues */
|
||||
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
||||
if (idx < 0) { /* not found? */
|
||||
if (fs->prev != NULL) /* more levels? */
|
||||
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
|
||||
if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */
|
||||
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
||||
else /* it is a global or a constant */
|
||||
return; /* don't need to do anything at this level */
|
||||
}
|
||||
init_exp(var, VUPVAL, idx); /* new or old upvalue */
|
||||
else /* no more levels */
|
||||
init_exp(var, VGLOBAL, -1); /* global by default */
|
||||
if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */
|
||||
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
||||
else /* it is a global or a constant */
|
||||
return; /* don't need to do anything at this level */
|
||||
}
|
||||
init_exp(var, VUPVAL, idx); /* new or old upvalue */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,10 +473,15 @@ static void singlevar (LexState *ls, expdesc *var) {
|
||||
TString *varname = str_checkname(ls);
|
||||
FuncState *fs = ls->fs;
|
||||
singlevaraux(fs, varname, var, 1);
|
||||
if (var->k == VVOID) { /* global name? */
|
||||
if (var->k == VGLOBAL) { /* global name? */
|
||||
expdesc key;
|
||||
/* global by default in the scope of a global declaration? */
|
||||
if (var->u.info == -1 && fs->bl->globdec)
|
||||
luaK_semerror(ls, "variable '%s' not declared", getstr(varname));
|
||||
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
||||
lua_assert(var->k != VVOID); /* this one must exist */
|
||||
if (var->k == VGLOBAL)
|
||||
luaK_semerror(ls, "_ENV is global when accessing variable '%s'",
|
||||
getstr(varname));
|
||||
luaK_exp2anyregup(fs, var); /* but could be a constant */
|
||||
codestring(&key, varname); /* key is variable name */
|
||||
luaK_indexed(fs, var, &key); /* env[varname] */
|
||||
@@ -664,8 +671,13 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
|
||||
bl->firstlabel = fs->ls->dyd->label.n;
|
||||
bl->firstgoto = fs->ls->dyd->gt.n;
|
||||
bl->upval = 0;
|
||||
/* inherit 'insidetbc' from enclosing block */
|
||||
bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc);
|
||||
bl->previous = fs->bl;
|
||||
/* 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));
|
||||
}
|
||||
@@ -1600,7 +1612,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
||||
int base = fs->freereg;
|
||||
new_localvarliteral(ls, "(for state)");
|
||||
new_localvarliteral(ls, "(for state)");
|
||||
new_localvarkind(ls, varname, RDKCONST); /* control variable */
|
||||
new_varkind(ls, varname, RDKCONST); /* control variable */
|
||||
checknext(ls, '=');
|
||||
exp1(ls); /* initial value */
|
||||
checknext(ls, ',');
|
||||
@@ -1627,7 +1639,7 @@ static void forlist (LexState *ls, TString *indexname) {
|
||||
new_localvarliteral(ls, "(for state)"); /* iterator function */
|
||||
new_localvarliteral(ls, "(for state)"); /* state */
|
||||
new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */
|
||||
new_localvarkind(ls, indexname, RDKCONST); /* control variable */
|
||||
new_varkind(ls, indexname, RDKCONST); /* control variable */
|
||||
/* other declared variables */
|
||||
while (testnext(ls, ',')) {
|
||||
new_localvar(ls, str_checkname(ls));
|
||||
@@ -1702,7 +1714,7 @@ static void localfunc (LexState *ls) {
|
||||
}
|
||||
|
||||
|
||||
static lu_byte getlocalattribute (LexState *ls) {
|
||||
static lu_byte getvarattribute (LexState *ls) {
|
||||
/* ATTRIB -> ['<' Name '>'] */
|
||||
if (testnext(ls, '<')) {
|
||||
TString *ts = str_checkname(ls);
|
||||
@@ -1738,8 +1750,8 @@ static void localstat (LexState *ls) {
|
||||
expdesc e;
|
||||
do {
|
||||
TString *vname = str_checkname(ls);
|
||||
lu_byte kind = getlocalattribute(ls);
|
||||
vidx = new_localvarkind(ls, vname, kind);
|
||||
lu_byte kind = getvarattribute(ls);
|
||||
vidx = new_varkind(ls, vname, kind);
|
||||
if (kind == RDKTOCLOSE) { /* to-be-closed? */
|
||||
if (toclose != -1) /* one already present? */
|
||||
luaK_semerror(ls, "multiple to-be-closed variables in local list");
|
||||
@@ -1769,6 +1781,24 @@ static void localstat (LexState *ls) {
|
||||
}
|
||||
|
||||
|
||||
static void globalstat (LexState *ls) {
|
||||
FuncState *fs = ls->fs;
|
||||
luaX_next(ls); /* skip 'global' */
|
||||
do {
|
||||
TString *vname = str_checkname(ls);
|
||||
lu_byte kind = getvarattribute(ls);
|
||||
if (kind == RDKTOCLOSE)
|
||||
luaK_semerror(ls, "global variable ('%s') cannot be to-be-closed",
|
||||
getstr(vname));
|
||||
/* adjust kind for global variable */
|
||||
kind = (kind == VDKREG) ? GDKREG : GDKCONST;
|
||||
new_varkind(ls, vname, kind);
|
||||
fs->nactvar++; /* activate declaration */
|
||||
} while (testnext(ls, ','));
|
||||
fs->bl->globdec = 1; /* code is in the scope of a global declaration */
|
||||
}
|
||||
|
||||
|
||||
static int funcname (LexState *ls, expdesc *v) {
|
||||
/* funcname -> NAME {fieldsel} [':' NAME] */
|
||||
int ismethod = 0;
|
||||
@@ -1888,6 +1918,10 @@ static void statement (LexState *ls) {
|
||||
localstat(ls);
|
||||
break;
|
||||
}
|
||||
case TK_GLOBAL: { /* stat -> globalstat */
|
||||
globalstat(ls);
|
||||
break;
|
||||
}
|
||||
case TK_DBCOLON: { /* stat -> label */
|
||||
luaX_next(ls); /* skip double colon */
|
||||
labelstat(ls, str_checkname(ls), line);
|
||||
@@ -1907,6 +1941,17 @@ static void statement (LexState *ls) {
|
||||
gotostat(ls, line);
|
||||
break;
|
||||
}
|
||||
case TK_NAME: {
|
||||
/* compatibility code to parse global keyword when "global"
|
||||
is not reserved */
|
||||
if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) {
|
||||
int lk = luaX_lookahead(ls);
|
||||
if (lk == TK_NAME) { /* 'global name'? */
|
||||
globalstat(ls);
|
||||
break;
|
||||
}
|
||||
} /* else... */
|
||||
} /* FALLTHROUGH */
|
||||
default: { /* stat -> func | assignment */
|
||||
exprstat(ls);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user