mirror of https://github.com/rusefi/lua.git
ensures that all local variables are declared inside some block,
opening a new block at 'open_func'
This commit is contained in:
parent
f079749287
commit
fd6c1f4898
84
lparser.c
84
lparser.c
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue