ensures that all local variables are declared inside some block,

opening a new block at 'open_func'
This commit is contained in:
Roberto Ierusalimschy 2011-02-07 17:00:30 -02:00
parent f079749287
commit fd6c1f4898
1 changed files with 39 additions and 45 deletions

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lparser.c,v 2.98 2011/02/07 12:28:27 roberto Exp roberto $ ** $Id: lparser.c,v 2.99 2011/02/07 17:14:50 roberto Exp roberto $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -46,7 +46,7 @@ typedef struct BlockCnt {
int firstgoto; /* index of first pending goto in this block */ int firstgoto; /* index of first pending goto in this block */
lu_byte nactvar; /* # active locals outside the block */ lu_byte nactvar; /* # active locals outside the block */
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 isbreakable; /* true if `block' is a loop */ lu_byte isloop; /* true if `block' is a loop */
} BlockCnt; } BlockCnt;
@ -251,8 +251,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/ */
static void markupval (FuncState *fs, int level) { static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl; BlockCnt *bl = fs->bl;
while (bl && bl->nactvar > level) bl = bl->previous; while (bl->nactvar > level) bl = bl->previous;
if (bl) bl->upval = 1; bl->upval = 1;
} }
@ -411,9 +411,9 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) {
} }
static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
bl->breaklist = NO_JUMP; bl->breaklist = NO_JUMP;
bl->isbreakable = isbreakable; bl->isloop = isloop;
bl->nactvar = fs->nactvar; bl->nactvar = fs->nactvar;
bl->firstlabel = fs->ls->dyd->label.n; bl->firstlabel = fs->ls->dyd->label.n;
bl->firstgoto = fs->ls->dyd->gt.n; bl->firstgoto = fs->ls->dyd->gt.n;
@ -426,18 +426,25 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
static void leaveblock (FuncState *fs) { static void leaveblock (FuncState *fs) {
BlockCnt *bl = fs->bl; BlockCnt *bl = fs->bl;
LexState *ls = fs->ls;
fs->bl = bl->previous; fs->bl = bl->previous;
removevars(fs, bl->nactvar); removevars(fs, bl->nactvar);
fs->ls->dyd->label.n = bl->firstlabel; /* remove local labels */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
movegotosout(fs, bl); if (bl->previous) /* inner block? */
if (bl->upval) { movegotosout(fs, bl); /* update pending gotos to outer block */
else if (bl->firstgoto < ls->dyd->gt.n) { /* check pending gotos */
Labeldesc *gt = &ls->dyd->gt.arr[bl->firstgoto];
const char *msg = luaO_pushfstring(ls->L,
"label " LUA_QS " (<goto> at line %d) undefined",
getstr(gt->name), gt->line);
luaX_syntaxerror(ls, msg);
}
if (bl->previous && bl->upval) {
/* create a 'jump to here' to close upvalues */ /* create a 'jump to here' to close upvalues */
int j = luaK_jump(fs); int j = luaK_jump(fs);
luaK_patchclose(fs, j, bl->nactvar); luaK_patchclose(fs, j, bl->nactvar);
luaK_patchtohere(fs, j); luaK_patchtohere(fs, j);
} }
/* a block either controls scope or breaks (never both) */
lua_assert(!bl->isbreakable || !bl->upval);
lua_assert(bl->nactvar == fs->nactvar); lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = fs->nactvar; /* free registers */ fs->freereg = fs->nactvar; /* free registers */
luaK_patchtohere(fs, bl->breaklist); luaK_patchtohere(fs, bl->breaklist);
@ -464,7 +471,7 @@ static void codeclosure (LexState *ls, Proto *clp, expdesc *v) {
} }
static void open_func (LexState *ls, FuncState *fs) { static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
lua_State *L = ls->L; lua_State *L = ls->L;
Proto *f; Proto *f;
fs->prev = ls->fs; /* linked list of funcstates */ fs->prev = ls->fs; /* linked list of funcstates */
@ -493,6 +500,7 @@ static void open_func (LexState *ls, FuncState *fs) {
/* anchor table of constants (to avoid being collected) */ /* anchor table of constants (to avoid being collected) */
sethvalue2s(L, L->top, fs->h); sethvalue2s(L, L->top, fs->h);
incr_top(L); incr_top(L);
enterblock(fs, bl, 0);
} }
@ -501,7 +509,7 @@ static void close_func (LexState *ls) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
Proto *f = fs->f; Proto *f = fs->f;
luaK_ret(fs, 0, 0); /* final return */ luaK_ret(fs, 0, 0); /* final return */
removevars(fs, 0); leaveblock(fs);
luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
f->sizecode = fs->pc; f->sizecode = fs->pc;
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
@ -528,35 +536,20 @@ static void close_func (LexState *ls) {
** opens the main function, which is a regular vararg function with an ** opens the main function, which is a regular vararg function with an
** upvalue named LUA_ENV ** upvalue named LUA_ENV
*/ */
static void open_mainfunc (LexState *ls, FuncState *fs) { static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) {
expdesc v; expdesc v;
open_func(ls, fs); open_func(ls, fs, bl);
fs->f->is_vararg = 1; /* main function is always vararg */ fs->f->is_vararg = 1; /* main function is always vararg */
init_exp(&v, VLOCAL, 0); init_exp(&v, VLOCAL, 0);
newupvalue(fs, ls->envn, &v); /* create environment upvalue */ newupvalue(fs, ls->envn, &v); /* create environment upvalue */
} }
static void mainblock (LexState *ls, FuncState *fs) {
BlockCnt bl;
enterblock(fs, &bl, 0);
statlist(ls); /* read main block */
if (bl.firstgoto < ls->dyd->gt.n) { /* check pending gotos */
Labeldesc *gt = &ls->dyd->gt.arr[bl.firstgoto];
const char *msg = luaO_pushfstring(ls->L,
"label " LUA_QS " (<goto> at line %d) undefined",
getstr(gt->name), gt->line);
luaX_syntaxerror(ls, msg);
}
bl.upval = 0; /* RETURN will close any pending upvalue */
leaveblock(fs);
}
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name) { Dyndata *dyd, const char *name) {
LexState lexstate; LexState lexstate;
FuncState funcstate; FuncState funcstate;
BlockCnt bl;
TString *tname = luaS_new(L, name); TString *tname = luaS_new(L, name);
setsvalue2s(L, L->top, tname); /* push name to protect it */ setsvalue2s(L, L->top, tname); /* push name to protect it */
incr_top(L); incr_top(L);
@ -564,9 +557,9 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lexstate.dyd = dyd; lexstate.dyd = dyd;
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
luaX_setinput(L, &lexstate, z, tname); luaX_setinput(L, &lexstate, z, tname);
open_mainfunc(&lexstate, &funcstate); open_mainfunc(&lexstate, &funcstate, &bl);
luaX_next(&lexstate); /* read first token */ luaX_next(&lexstate); /* read first token */
mainblock(&lexstate, &funcstate); statlist(&lexstate); /* main body */
check(&lexstate, TK_EOS); check(&lexstate, TK_EOS);
close_func(&lexstate); close_func(&lexstate);
L->top--; /* pop name */ L->top--; /* pop name */
@ -753,19 +746,20 @@ static void parlist (LexState *ls) {
} }
static void body (LexState *ls, expdesc *e, int needself, int line) { static void body (LexState *ls, expdesc *e, int ismethod, int line) {
/* body -> `(' parlist `)' block END */ /* body -> `(' parlist `)' block END */
FuncState new_fs; FuncState new_fs;
open_func(ls, &new_fs); BlockCnt bl;
open_func(ls, &new_fs, &bl);
new_fs.f->linedefined = line; new_fs.f->linedefined = line;
checknext(ls, '('); checknext(ls, '(');
if (needself) { if (ismethod) {
new_localvarliteral(ls, "self"); new_localvarliteral(ls, "self"); /* create 'self' parameter */
adjustlocalvars(ls, 1); adjustlocalvars(ls, 1);
} }
parlist(ls); parlist(ls);
checknext(ls, ')'); checknext(ls, ')');
mainblock(ls, &new_fs); statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber; new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line); check_match(ls, TK_END, TK_FUNCTION, line);
codeclosure(ls, new_fs.f, e); codeclosure(ls, new_fs.f, e);
@ -1163,7 +1157,7 @@ static void breakstat (LexState *ls) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
BlockCnt *bl = fs->bl; BlockCnt *bl = fs->bl;
int upval = 0; int upval = 0;
while (bl && !bl->isbreakable) { while (bl && !bl->isloop) {
upval |= bl->upval; upval |= bl->upval;
bl = bl->previous; bl = bl->previous;
} }
@ -1426,25 +1420,25 @@ static void localstat (LexState *ls) {
static int funcname (LexState *ls, expdesc *v) { static int funcname (LexState *ls, expdesc *v) {
/* funcname -> NAME {fieldsel} [`:' NAME] */ /* funcname -> NAME {fieldsel} [`:' NAME] */
int needself = 0; int ismethod = 0;
singlevar(ls, v); singlevar(ls, v);
while (ls->t.token == '.') while (ls->t.token == '.')
fieldsel(ls, v); fieldsel(ls, v);
if (ls->t.token == ':') { if (ls->t.token == ':') {
needself = 1; ismethod = 1;
fieldsel(ls, v); fieldsel(ls, v);
} }
return needself; return ismethod;
} }
static void funcstat (LexState *ls, int line) { static void funcstat (LexState *ls, int line) {
/* funcstat -> FUNCTION funcname body */ /* funcstat -> FUNCTION funcname body */
int needself; int ismethod;
expdesc v, b; expdesc v, b;
luaX_next(ls); /* skip FUNCTION */ luaX_next(ls); /* skip FUNCTION */
needself = funcname(ls, &v); ismethod = funcname(ls, &v);
body(ls, &b, needself, line); body(ls, &b, ismethod, line);
luaK_storevar(ls->fs, &v, &b); luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ luaK_fixline(ls->fs, line); /* definition `happens' in the first line */
} }