diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-02-07 17:00:30 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-02-07 17:00:30 -0200 |
commit | fd6c1f489862d8ecf7055ca18898fffd006711fa (patch) | |
tree | 8993adcebcf891bf32976d86dc7ff5d5023e1e65 | |
parent | f0797492875dec5bf7a23b9172809bc92c0c04cd (diff) | |
download | lua-fd6c1f489862d8ecf7055ca18898fffd006711fa.tar.gz lua-fd6c1f489862d8ecf7055ca18898fffd006711fa.tar.bz2 lua-fd6c1f489862d8ecf7055ca18898fffd006711fa.zip |
ensures that all local variables are declared inside some block,
opening a new block at 'open_func'
-rw-r--r-- | lparser.c | 84 |
1 files changed, 39 insertions, 45 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.c,v 2.98 2011/02/07 12:28:27 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 2.99 2011/02/07 17:14:50 roberto Exp roberto $ |
3 | ** Lua Parser | 3 | ** Lua Parser |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -46,7 +46,7 @@ typedef struct BlockCnt { | |||
46 | int firstgoto; /* index of first pending goto in this block */ | 46 | int firstgoto; /* index of first pending goto in this block */ |
47 | lu_byte nactvar; /* # active locals outside the block */ | 47 | lu_byte nactvar; /* # active locals outside the block */ |
48 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 48 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
49 | lu_byte isbreakable; /* true if `block' is a loop */ | 49 | lu_byte isloop; /* true if `block' is a loop */ |
50 | } BlockCnt; | 50 | } BlockCnt; |
51 | 51 | ||
52 | 52 | ||
@@ -251,8 +251,8 @@ static int searchvar (FuncState *fs, TString *n) { | |||
251 | */ | 251 | */ |
252 | static void markupval (FuncState *fs, int level) { | 252 | static void markupval (FuncState *fs, int level) { |
253 | BlockCnt *bl = fs->bl; | 253 | BlockCnt *bl = fs->bl; |
254 | while (bl && bl->nactvar > level) bl = bl->previous; | 254 | while (bl->nactvar > level) bl = bl->previous; |
255 | if (bl) bl->upval = 1; | 255 | bl->upval = 1; |
256 | } | 256 | } |
257 | 257 | ||
258 | 258 | ||
@@ -411,9 +411,9 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) { | |||
411 | } | 411 | } |
412 | 412 | ||
413 | 413 | ||
414 | static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { | 414 | static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { |
415 | bl->breaklist = NO_JUMP; | 415 | bl->breaklist = NO_JUMP; |
416 | bl->isbreakable = isbreakable; | 416 | bl->isloop = isloop; |
417 | bl->nactvar = fs->nactvar; | 417 | bl->nactvar = fs->nactvar; |
418 | bl->firstlabel = fs->ls->dyd->label.n; | 418 | bl->firstlabel = fs->ls->dyd->label.n; |
419 | bl->firstgoto = fs->ls->dyd->gt.n; | 419 | bl->firstgoto = fs->ls->dyd->gt.n; |
@@ -426,18 +426,25 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) { | |||
426 | 426 | ||
427 | static void leaveblock (FuncState *fs) { | 427 | static void leaveblock (FuncState *fs) { |
428 | BlockCnt *bl = fs->bl; | 428 | BlockCnt *bl = fs->bl; |
429 | LexState *ls = fs->ls; | ||
429 | fs->bl = bl->previous; | 430 | fs->bl = bl->previous; |
430 | removevars(fs, bl->nactvar); | 431 | removevars(fs, bl->nactvar); |
431 | fs->ls->dyd->label.n = bl->firstlabel; /* remove local labels */ | 432 | ls->dyd->label.n = bl->firstlabel; /* remove local labels */ |
432 | movegotosout(fs, bl); | 433 | if (bl->previous) /* inner block? */ |
433 | if (bl->upval) { | 434 | movegotosout(fs, bl); /* update pending gotos to outer block */ |
435 | else if (bl->firstgoto < ls->dyd->gt.n) { /* check pending gotos */ | ||
436 | Labeldesc *gt = &ls->dyd->gt.arr[bl->firstgoto]; | ||
437 | const char *msg = luaO_pushfstring(ls->L, | ||
438 | "label " LUA_QS " (<goto> at line %d) undefined", | ||
439 | getstr(gt->name), gt->line); | ||
440 | luaX_syntaxerror(ls, msg); | ||
441 | } | ||
442 | if (bl->previous && bl->upval) { | ||
434 | /* create a 'jump to here' to close upvalues */ | 443 | /* create a 'jump to here' to close upvalues */ |
435 | int j = luaK_jump(fs); | 444 | int j = luaK_jump(fs); |
436 | luaK_patchclose(fs, j, bl->nactvar); | 445 | luaK_patchclose(fs, j, bl->nactvar); |
437 | luaK_patchtohere(fs, j); | 446 | luaK_patchtohere(fs, j); |
438 | } | 447 | } |
439 | /* a block either controls scope or breaks (never both) */ | ||
440 | lua_assert(!bl->isbreakable || !bl->upval); | ||
441 | lua_assert(bl->nactvar == fs->nactvar); | 448 | lua_assert(bl->nactvar == fs->nactvar); |
442 | fs->freereg = fs->nactvar; /* free registers */ | 449 | fs->freereg = fs->nactvar; /* free registers */ |
443 | luaK_patchtohere(fs, bl->breaklist); | 450 | luaK_patchtohere(fs, bl->breaklist); |
@@ -464,7 +471,7 @@ static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { | |||
464 | } | 471 | } |
465 | 472 | ||
466 | 473 | ||
467 | static void open_func (LexState *ls, FuncState *fs) { | 474 | static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { |
468 | lua_State *L = ls->L; | 475 | lua_State *L = ls->L; |
469 | Proto *f; | 476 | Proto *f; |
470 | fs->prev = ls->fs; /* linked list of funcstates */ | 477 | fs->prev = ls->fs; /* linked list of funcstates */ |
@@ -493,6 +500,7 @@ static void open_func (LexState *ls, FuncState *fs) { | |||
493 | /* anchor table of constants (to avoid being collected) */ | 500 | /* anchor table of constants (to avoid being collected) */ |
494 | sethvalue2s(L, L->top, fs->h); | 501 | sethvalue2s(L, L->top, fs->h); |
495 | incr_top(L); | 502 | incr_top(L); |
503 | enterblock(fs, bl, 0); | ||
496 | } | 504 | } |
497 | 505 | ||
498 | 506 | ||
@@ -501,7 +509,7 @@ static void close_func (LexState *ls) { | |||
501 | FuncState *fs = ls->fs; | 509 | FuncState *fs = ls->fs; |
502 | Proto *f = fs->f; | 510 | Proto *f = fs->f; |
503 | luaK_ret(fs, 0, 0); /* final return */ | 511 | luaK_ret(fs, 0, 0); /* final return */ |
504 | removevars(fs, 0); | 512 | leaveblock(fs); |
505 | luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); | 513 | luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); |
506 | f->sizecode = fs->pc; | 514 | f->sizecode = fs->pc; |
507 | luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); | 515 | luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); |
@@ -528,35 +536,20 @@ static void close_func (LexState *ls) { | |||
528 | ** opens the main function, which is a regular vararg function with an | 536 | ** opens the main function, which is a regular vararg function with an |
529 | ** upvalue named LUA_ENV | 537 | ** upvalue named LUA_ENV |
530 | */ | 538 | */ |
531 | static void open_mainfunc (LexState *ls, FuncState *fs) { | 539 | static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) { |
532 | expdesc v; | 540 | expdesc v; |
533 | open_func(ls, fs); | 541 | open_func(ls, fs, bl); |
534 | fs->f->is_vararg = 1; /* main function is always vararg */ | 542 | fs->f->is_vararg = 1; /* main function is always vararg */ |
535 | init_exp(&v, VLOCAL, 0); | 543 | init_exp(&v, VLOCAL, 0); |
536 | newupvalue(fs, ls->envn, &v); /* create environment upvalue */ | 544 | newupvalue(fs, ls->envn, &v); /* create environment upvalue */ |
537 | } | 545 | } |
538 | 546 | ||
539 | 547 | ||
540 | static void mainblock (LexState *ls, FuncState *fs) { | ||
541 | BlockCnt bl; | ||
542 | enterblock(fs, &bl, 0); | ||
543 | statlist(ls); /* read main block */ | ||
544 | if (bl.firstgoto < ls->dyd->gt.n) { /* check pending gotos */ | ||
545 | Labeldesc *gt = &ls->dyd->gt.arr[bl.firstgoto]; | ||
546 | const char *msg = luaO_pushfstring(ls->L, | ||
547 | "label " LUA_QS " (<goto> at line %d) undefined", | ||
548 | getstr(gt->name), gt->line); | ||
549 | luaX_syntaxerror(ls, msg); | ||
550 | } | ||
551 | bl.upval = 0; /* RETURN will close any pending upvalue */ | ||
552 | leaveblock(fs); | ||
553 | } | ||
554 | |||
555 | |||
556 | Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, | 548 | Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, |
557 | Dyndata *dyd, const char *name) { | 549 | Dyndata *dyd, const char *name) { |
558 | LexState lexstate; | 550 | LexState lexstate; |
559 | FuncState funcstate; | 551 | FuncState funcstate; |
552 | BlockCnt bl; | ||
560 | TString *tname = luaS_new(L, name); | 553 | TString *tname = luaS_new(L, name); |
561 | setsvalue2s(L, L->top, tname); /* push name to protect it */ | 554 | setsvalue2s(L, L->top, tname); /* push name to protect it */ |
562 | incr_top(L); | 555 | incr_top(L); |
@@ -564,9 +557,9 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, | |||
564 | lexstate.dyd = dyd; | 557 | lexstate.dyd = dyd; |
565 | dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; | 558 | dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; |
566 | luaX_setinput(L, &lexstate, z, tname); | 559 | luaX_setinput(L, &lexstate, z, tname); |
567 | open_mainfunc(&lexstate, &funcstate); | 560 | open_mainfunc(&lexstate, &funcstate, &bl); |
568 | luaX_next(&lexstate); /* read first token */ | 561 | luaX_next(&lexstate); /* read first token */ |
569 | mainblock(&lexstate, &funcstate); | 562 | statlist(&lexstate); /* main body */ |
570 | check(&lexstate, TK_EOS); | 563 | check(&lexstate, TK_EOS); |
571 | close_func(&lexstate); | 564 | close_func(&lexstate); |
572 | L->top--; /* pop name */ | 565 | L->top--; /* pop name */ |
@@ -753,19 +746,20 @@ static void parlist (LexState *ls) { | |||
753 | } | 746 | } |
754 | 747 | ||
755 | 748 | ||
756 | static void body (LexState *ls, expdesc *e, int needself, int line) { | 749 | static void body (LexState *ls, expdesc *e, int ismethod, int line) { |
757 | /* body -> `(' parlist `)' block END */ | 750 | /* body -> `(' parlist `)' block END */ |
758 | FuncState new_fs; | 751 | FuncState new_fs; |
759 | open_func(ls, &new_fs); | 752 | BlockCnt bl; |
753 | open_func(ls, &new_fs, &bl); | ||
760 | new_fs.f->linedefined = line; | 754 | new_fs.f->linedefined = line; |
761 | checknext(ls, '('); | 755 | checknext(ls, '('); |
762 | if (needself) { | 756 | if (ismethod) { |
763 | new_localvarliteral(ls, "self"); | 757 | new_localvarliteral(ls, "self"); /* create 'self' parameter */ |
764 | adjustlocalvars(ls, 1); | 758 | adjustlocalvars(ls, 1); |
765 | } | 759 | } |
766 | parlist(ls); | 760 | parlist(ls); |
767 | checknext(ls, ')'); | 761 | checknext(ls, ')'); |
768 | mainblock(ls, &new_fs); | 762 | statlist(ls); |
769 | new_fs.f->lastlinedefined = ls->linenumber; | 763 | new_fs.f->lastlinedefined = ls->linenumber; |
770 | check_match(ls, TK_END, TK_FUNCTION, line); | 764 | check_match(ls, TK_END, TK_FUNCTION, line); |
771 | codeclosure(ls, new_fs.f, e); | 765 | codeclosure(ls, new_fs.f, e); |
@@ -1163,7 +1157,7 @@ static void breakstat (LexState *ls) { | |||
1163 | FuncState *fs = ls->fs; | 1157 | FuncState *fs = ls->fs; |
1164 | BlockCnt *bl = fs->bl; | 1158 | BlockCnt *bl = fs->bl; |
1165 | int upval = 0; | 1159 | int upval = 0; |
1166 | while (bl && !bl->isbreakable) { | 1160 | while (bl && !bl->isloop) { |
1167 | upval |= bl->upval; | 1161 | upval |= bl->upval; |
1168 | bl = bl->previous; | 1162 | bl = bl->previous; |
1169 | } | 1163 | } |
@@ -1426,25 +1420,25 @@ static void localstat (LexState *ls) { | |||
1426 | 1420 | ||
1427 | static int funcname (LexState *ls, expdesc *v) { | 1421 | static int funcname (LexState *ls, expdesc *v) { |
1428 | /* funcname -> NAME {fieldsel} [`:' NAME] */ | 1422 | /* funcname -> NAME {fieldsel} [`:' NAME] */ |
1429 | int needself = 0; | 1423 | int ismethod = 0; |
1430 | singlevar(ls, v); | 1424 | singlevar(ls, v); |
1431 | while (ls->t.token == '.') | 1425 | while (ls->t.token == '.') |
1432 | fieldsel(ls, v); | 1426 | fieldsel(ls, v); |
1433 | if (ls->t.token == ':') { | 1427 | if (ls->t.token == ':') { |
1434 | needself = 1; | 1428 | ismethod = 1; |
1435 | fieldsel(ls, v); | 1429 | fieldsel(ls, v); |
1436 | } | 1430 | } |
1437 | return needself; | 1431 | return ismethod; |
1438 | } | 1432 | } |
1439 | 1433 | ||
1440 | 1434 | ||
1441 | static void funcstat (LexState *ls, int line) { | 1435 | static void funcstat (LexState *ls, int line) { |
1442 | /* funcstat -> FUNCTION funcname body */ | 1436 | /* funcstat -> FUNCTION funcname body */ |
1443 | int needself; | 1437 | int ismethod; |
1444 | expdesc v, b; | 1438 | expdesc v, b; |
1445 | luaX_next(ls); /* skip FUNCTION */ | 1439 | luaX_next(ls); /* skip FUNCTION */ |
1446 | needself = funcname(ls, &v); | 1440 | ismethod = funcname(ls, &v); |
1447 | body(ls, &b, needself, line); | 1441 | body(ls, &b, ismethod, line); |
1448 | luaK_storevar(ls->fs, &v, &b); | 1442 | luaK_storevar(ls->fs, &v, &b); |
1449 | luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ | 1443 | luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ |
1450 | } | 1444 | } |