diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-05 16:24:59 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-05 16:24:59 -0300 |
| commit | be8120906304a8658fab998587b969e0e42f5650 (patch) | |
| tree | 81cf2d38522b10468d09763fc25d261486008197 /lparser.c | |
| parent | e05590591410a5e007a1e3f1691f6c1cf9d8fe45 (diff) | |
| download | lua-be8120906304a8658fab998587b969e0e42f5650.tar.gz lua-be8120906304a8658fab998587b969e0e42f5650.tar.bz2 lua-be8120906304a8658fab998587b969e0e42f5650.zip | |
First implementation of global declarations
Diffstat (limited to 'lparser.c')
| -rw-r--r-- | lparser.c | 111 |
1 files changed, 78 insertions, 33 deletions
| @@ -30,8 +30,8 @@ | |||
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | /* maximum number of local variables per function (must be smaller | 33 | /* maximum number of variable declarationss per function (must be |
| 34 | than 250, due to the bytecode format) */ | 34 | smaller than 250, due to the bytecode format) */ |
| 35 | #define MAXVARS 200 | 35 | #define MAXVARS 200 |
| 36 | 36 | ||
| 37 | 37 | ||
| @@ -54,6 +54,7 @@ typedef struct BlockCnt { | |||
| 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
| 55 | lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */ | 55 | lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */ |
| 56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ | 56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ |
| 57 | lu_byte globdec; /* true if inside the scope of any global declaration */ | ||
| 57 | } BlockCnt; | 58 | } BlockCnt; |
| 58 | 59 | ||
| 59 | 60 | ||
| @@ -188,10 +189,10 @@ static short registerlocalvar (LexState *ls, FuncState *fs, | |||
| 188 | 189 | ||
| 189 | 190 | ||
| 190 | /* | 191 | /* |
| 191 | ** Create a new local variable with the given 'name' and given 'kind'. | 192 | ** Create a new variable with the given 'name' and given 'kind'. |
| 192 | ** Return its index in the function. | 193 | ** Return its index in the function. |
| 193 | */ | 194 | */ |
| 194 | static int new_localvarkind (LexState *ls, TString *name, lu_byte kind) { | 195 | static int new_varkind (LexState *ls, TString *name, lu_byte kind) { |
| 195 | lua_State *L = ls->L; | 196 | lua_State *L = ls->L; |
| 196 | FuncState *fs = ls->fs; | 197 | FuncState *fs = ls->fs; |
| 197 | Dyndata *dyd = ls->dyd; | 198 | Dyndata *dyd = ls->dyd; |
| @@ -211,7 +212,7 @@ static int new_localvarkind (LexState *ls, TString *name, lu_byte kind) { | |||
| 211 | ** Create a new local variable with the given 'name' and regular kind. | 212 | ** Create a new local variable with the given 'name' and regular kind. |
| 212 | */ | 213 | */ |
| 213 | static int new_localvar (LexState *ls, TString *name) { | 214 | static int new_localvar (LexState *ls, TString *name) { |
| 214 | return new_localvarkind(ls, name, VDKREG); | 215 | return new_varkind(ls, name, VDKREG); |
| 215 | } | 216 | } |
| 216 | 217 | ||
| 217 | #define new_localvarliteral(ls,v) \ | 218 | #define new_localvarliteral(ls,v) \ |
| @@ -238,7 +239,7 @@ static Vardesc *getlocalvardesc (FuncState *fs, int vidx) { | |||
| 238 | static lu_byte reglevel (FuncState *fs, int nvar) { | 239 | static lu_byte reglevel (FuncState *fs, int nvar) { |
| 239 | while (nvar-- > 0) { | 240 | while (nvar-- > 0) { |
| 240 | Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */ | 241 | Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */ |
| 241 | if (vd->vd.kind != RDKCTC) /* is in a register? */ | 242 | if (varinreg(vd)) /* is in a register? */ |
| 242 | return cast_byte(vd->vd.ridx + 1); | 243 | return cast_byte(vd->vd.ridx + 1); |
| 243 | } | 244 | } |
| 244 | return 0; /* no variables in registers */ | 245 | return 0; /* no variables in registers */ |
| @@ -259,7 +260,7 @@ lu_byte luaY_nvarstack (FuncState *fs) { | |||
| 259 | */ | 260 | */ |
| 260 | static LocVar *localdebuginfo (FuncState *fs, int vidx) { | 261 | static LocVar *localdebuginfo (FuncState *fs, int vidx) { |
| 261 | Vardesc *vd = getlocalvardesc(fs, vidx); | 262 | Vardesc *vd = getlocalvardesc(fs, vidx); |
| 262 | if (vd->vd.kind == RDKCTC) | 263 | if (!varinreg(vd)) |
| 263 | return NULL; /* no debug info. for constants */ | 264 | return NULL; /* no debug info. for constants */ |
| 264 | else { | 265 | else { |
| 265 | int idx = vd->vd.pidx; | 266 | int idx = vd->vd.pidx; |
| @@ -401,7 +402,9 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) { | |||
| 401 | if (eqstr(n, vd->vd.name)) { /* found? */ | 402 | if (eqstr(n, vd->vd.name)) { /* found? */ |
| 402 | if (vd->vd.kind == RDKCTC) /* compile-time constant? */ | 403 | if (vd->vd.kind == RDKCTC) /* compile-time constant? */ |
| 403 | init_exp(var, VCONST, fs->firstlocal + i); | 404 | init_exp(var, VCONST, fs->firstlocal + i); |
| 404 | else /* real variable */ | 405 | else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST) |
| 406 | init_exp(var, VGLOBAL, i); | ||
| 407 | else /* local variable */ | ||
| 405 | init_var(fs, var, i); | 408 | init_var(fs, var, i); |
| 406 | return cast_int(var->k); | 409 | return cast_int(var->k); |
| 407 | } | 410 | } |
| @@ -440,25 +443,24 @@ static void marktobeclosed (FuncState *fs) { | |||
| 440 | ** 'var' as 'void' as a flag. | 443 | ** 'var' as 'void' as a flag. |
| 441 | */ | 444 | */ |
| 442 | static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { | 445 | static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { |
| 443 | if (fs == NULL) /* no more levels? */ | 446 | int v = searchvar(fs, n, var); /* look up locals at current level */ |
| 444 | init_exp(var, VVOID, 0); /* default is global */ | 447 | if (v >= 0) { /* found? */ |
| 445 | else { | 448 | if (v == VLOCAL && !base) |
| 446 | int v = searchvar(fs, n, var); /* look up locals at current level */ | 449 | markupval(fs, var->u.var.vidx); /* local will be used as an upval */ |
| 447 | if (v >= 0) { /* found? */ | 450 | } |
| 448 | if (v == VLOCAL && !base) | 451 | else { /* not found as local at current level; try upvalues */ |
| 449 | markupval(fs, var->u.var.vidx); /* local will be used as an upval */ | 452 | int idx = searchupvalue(fs, n); /* try existing upvalues */ |
| 450 | } | 453 | if (idx < 0) { /* not found? */ |
| 451 | else { /* not found as local at current level; try upvalues */ | 454 | if (fs->prev != NULL) /* more levels? */ |
| 452 | int idx = searchupvalue(fs, n); /* try existing upvalues */ | ||
| 453 | if (idx < 0) { /* not found? */ | ||
| 454 | singlevaraux(fs->prev, n, var, 0); /* try upper levels */ | 455 | singlevaraux(fs->prev, n, var, 0); /* try upper levels */ |
| 455 | if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */ | 456 | else /* no more levels */ |
| 456 | idx = newupvalue(fs, n, var); /* will be a new upvalue */ | 457 | init_exp(var, VGLOBAL, -1); /* global by default */ |
| 457 | else /* it is a global or a constant */ | 458 | if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */ |
| 458 | return; /* don't need to do anything at this level */ | 459 | idx = newupvalue(fs, n, var); /* will be a new upvalue */ |
| 459 | } | 460 | else /* it is a global or a constant */ |
| 460 | init_exp(var, VUPVAL, idx); /* new or old upvalue */ | 461 | return; /* don't need to do anything at this level */ |
| 461 | } | 462 | } |
| 463 | init_exp(var, VUPVAL, idx); /* new or old upvalue */ | ||
| 462 | } | 464 | } |
| 463 | } | 465 | } |
| 464 | 466 | ||
| @@ -471,10 +473,15 @@ static void singlevar (LexState *ls, expdesc *var) { | |||
| 471 | TString *varname = str_checkname(ls); | 473 | TString *varname = str_checkname(ls); |
| 472 | FuncState *fs = ls->fs; | 474 | FuncState *fs = ls->fs; |
| 473 | singlevaraux(fs, varname, var, 1); | 475 | singlevaraux(fs, varname, var, 1); |
| 474 | if (var->k == VVOID) { /* global name? */ | 476 | if (var->k == VGLOBAL) { /* global name? */ |
| 475 | expdesc key; | 477 | expdesc key; |
| 478 | /* global by default in the scope of a global declaration? */ | ||
| 479 | if (var->u.info == -1 && fs->bl->globdec) | ||
| 480 | luaK_semerror(ls, "variable '%s' not declared", getstr(varname)); | ||
| 476 | singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ | 481 | singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ |
| 477 | lua_assert(var->k != VVOID); /* this one must exist */ | 482 | if (var->k == VGLOBAL) |
| 483 | luaK_semerror(ls, "_ENV is global when accessing variable '%s'", | ||
| 484 | getstr(varname)); | ||
| 478 | luaK_exp2anyregup(fs, var); /* but could be a constant */ | 485 | luaK_exp2anyregup(fs, var); /* but could be a constant */ |
| 479 | codestring(&key, varname); /* key is variable name */ | 486 | codestring(&key, varname); /* key is variable name */ |
| 480 | luaK_indexed(fs, var, &key); /* env[varname] */ | 487 | luaK_indexed(fs, var, &key); /* env[varname] */ |
| @@ -664,8 +671,13 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { | |||
| 664 | bl->firstlabel = fs->ls->dyd->label.n; | 671 | bl->firstlabel = fs->ls->dyd->label.n; |
| 665 | bl->firstgoto = fs->ls->dyd->gt.n; | 672 | bl->firstgoto = fs->ls->dyd->gt.n; |
| 666 | bl->upval = 0; | 673 | bl->upval = 0; |
| 674 | /* inherit 'insidetbc' from enclosing block */ | ||
| 667 | bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); | 675 | bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); |
| 668 | bl->previous = fs->bl; | 676 | /* inherit 'globdec' from enclosing block or enclosing function */ |
| 677 | bl->globdec = fs->bl != NULL ? fs->bl->globdec | ||
| 678 | : fs->prev != NULL ? fs->prev->bl->globdec | ||
| 679 | : 0; /* chunk's first block */ | ||
| 680 | bl->previous = fs->bl; /* link block in function's block list */ | ||
| 669 | fs->bl = bl; | 681 | fs->bl = bl; |
| 670 | lua_assert(fs->freereg == luaY_nvarstack(fs)); | 682 | lua_assert(fs->freereg == luaY_nvarstack(fs)); |
| 671 | } | 683 | } |
| @@ -1600,7 +1612,7 @@ static void fornum (LexState *ls, TString *varname, int line) { | |||
| 1600 | int base = fs->freereg; | 1612 | int base = fs->freereg; |
| 1601 | new_localvarliteral(ls, "(for state)"); | 1613 | new_localvarliteral(ls, "(for state)"); |
| 1602 | new_localvarliteral(ls, "(for state)"); | 1614 | new_localvarliteral(ls, "(for state)"); |
| 1603 | new_localvarkind(ls, varname, RDKCONST); /* control variable */ | 1615 | new_varkind(ls, varname, RDKCONST); /* control variable */ |
| 1604 | checknext(ls, '='); | 1616 | checknext(ls, '='); |
| 1605 | exp1(ls); /* initial value */ | 1617 | exp1(ls); /* initial value */ |
| 1606 | checknext(ls, ','); | 1618 | checknext(ls, ','); |
| @@ -1627,7 +1639,7 @@ static void forlist (LexState *ls, TString *indexname) { | |||
| 1627 | new_localvarliteral(ls, "(for state)"); /* iterator function */ | 1639 | new_localvarliteral(ls, "(for state)"); /* iterator function */ |
| 1628 | new_localvarliteral(ls, "(for state)"); /* state */ | 1640 | new_localvarliteral(ls, "(for state)"); /* state */ |
| 1629 | new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */ | 1641 | new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */ |
| 1630 | new_localvarkind(ls, indexname, RDKCONST); /* control variable */ | 1642 | new_varkind(ls, indexname, RDKCONST); /* control variable */ |
| 1631 | /* other declared variables */ | 1643 | /* other declared variables */ |
| 1632 | while (testnext(ls, ',')) { | 1644 | while (testnext(ls, ',')) { |
| 1633 | new_localvar(ls, str_checkname(ls)); | 1645 | new_localvar(ls, str_checkname(ls)); |
| @@ -1702,7 +1714,7 @@ static void localfunc (LexState *ls) { | |||
| 1702 | } | 1714 | } |
| 1703 | 1715 | ||
| 1704 | 1716 | ||
| 1705 | static lu_byte getlocalattribute (LexState *ls) { | 1717 | static lu_byte getvarattribute (LexState *ls) { |
| 1706 | /* ATTRIB -> ['<' Name '>'] */ | 1718 | /* ATTRIB -> ['<' Name '>'] */ |
| 1707 | if (testnext(ls, '<')) { | 1719 | if (testnext(ls, '<')) { |
| 1708 | TString *ts = str_checkname(ls); | 1720 | TString *ts = str_checkname(ls); |
| @@ -1738,8 +1750,8 @@ static void localstat (LexState *ls) { | |||
| 1738 | expdesc e; | 1750 | expdesc e; |
| 1739 | do { | 1751 | do { |
| 1740 | TString *vname = str_checkname(ls); | 1752 | TString *vname = str_checkname(ls); |
| 1741 | lu_byte kind = getlocalattribute(ls); | 1753 | lu_byte kind = getvarattribute(ls); |
| 1742 | vidx = new_localvarkind(ls, vname, kind); | 1754 | vidx = new_varkind(ls, vname, kind); |
| 1743 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ | 1755 | if (kind == RDKTOCLOSE) { /* to-be-closed? */ |
| 1744 | if (toclose != -1) /* one already present? */ | 1756 | if (toclose != -1) /* one already present? */ |
| 1745 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); | 1757 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); |
| @@ -1769,6 +1781,24 @@ static void localstat (LexState *ls) { | |||
| 1769 | } | 1781 | } |
| 1770 | 1782 | ||
| 1771 | 1783 | ||
| 1784 | static void globalstat (LexState *ls) { | ||
| 1785 | FuncState *fs = ls->fs; | ||
| 1786 | luaX_next(ls); /* skip 'global' */ | ||
| 1787 | do { | ||
| 1788 | TString *vname = str_checkname(ls); | ||
| 1789 | lu_byte kind = getvarattribute(ls); | ||
| 1790 | if (kind == RDKTOCLOSE) | ||
| 1791 | luaK_semerror(ls, "global variable ('%s') cannot be to-be-closed", | ||
| 1792 | getstr(vname)); | ||
| 1793 | /* adjust kind for global variable */ | ||
| 1794 | kind = (kind == VDKREG) ? GDKREG : GDKCONST; | ||
| 1795 | new_varkind(ls, vname, kind); | ||
| 1796 | fs->nactvar++; /* activate declaration */ | ||
| 1797 | } while (testnext(ls, ',')); | ||
| 1798 | fs->bl->globdec = 1; /* code is in the scope of a global declaration */ | ||
| 1799 | } | ||
| 1800 | |||
| 1801 | |||
| 1772 | static int funcname (LexState *ls, expdesc *v) { | 1802 | static int funcname (LexState *ls, expdesc *v) { |
| 1773 | /* funcname -> NAME {fieldsel} [':' NAME] */ | 1803 | /* funcname -> NAME {fieldsel} [':' NAME] */ |
| 1774 | int ismethod = 0; | 1804 | int ismethod = 0; |
| @@ -1888,6 +1918,10 @@ static void statement (LexState *ls) { | |||
| 1888 | localstat(ls); | 1918 | localstat(ls); |
| 1889 | break; | 1919 | break; |
| 1890 | } | 1920 | } |
| 1921 | case TK_GLOBAL: { /* stat -> globalstat */ | ||
| 1922 | globalstat(ls); | ||
| 1923 | break; | ||
| 1924 | } | ||
| 1891 | case TK_DBCOLON: { /* stat -> label */ | 1925 | case TK_DBCOLON: { /* stat -> label */ |
| 1892 | luaX_next(ls); /* skip double colon */ | 1926 | luaX_next(ls); /* skip double colon */ |
| 1893 | labelstat(ls, str_checkname(ls), line); | 1927 | labelstat(ls, str_checkname(ls), line); |
| @@ -1907,6 +1941,17 @@ static void statement (LexState *ls) { | |||
| 1907 | gotostat(ls, line); | 1941 | gotostat(ls, line); |
| 1908 | break; | 1942 | break; |
| 1909 | } | 1943 | } |
| 1944 | case TK_NAME: { | ||
| 1945 | /* compatibility code to parse global keyword when "global" | ||
| 1946 | is not reserved */ | ||
| 1947 | if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) { | ||
| 1948 | int lk = luaX_lookahead(ls); | ||
| 1949 | if (lk == TK_NAME) { /* 'global name'? */ | ||
| 1950 | globalstat(ls); | ||
| 1951 | break; | ||
| 1952 | } | ||
| 1953 | } /* else... */ | ||
| 1954 | } /* FALLTHROUGH */ | ||
| 1910 | default: { /* stat -> func | assignment */ | 1955 | default: { /* stat -> func | assignment */ |
| 1911 | exprstat(ls); | 1956 | exprstat(ls); |
| 1912 | break; | 1957 | break; |
