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 | |
| parent | e05590591410a5e007a1e3f1691f6c1cf9d8fe45 (diff) | |
| download | lua-be8120906304a8658fab998587b969e0e42f5650.tar.gz lua-be8120906304a8658fab998587b969e0e42f5650.tar.bz2 lua-be8120906304a8658fab998587b969e0e42f5650.zip | |
First implementation of global declarations
| -rw-r--r-- | llex.c | 7 | ||||
| -rw-r--r-- | llex.h | 4 | ||||
| -rw-r--r-- | lparser.c | 111 | ||||
| -rw-r--r-- | lparser.h | 15 | ||||
| -rw-r--r-- | ltests.h | 1 | ||||
| -rw-r--r-- | luaconf.h | 6 | ||||
| -rw-r--r-- | manual/manual.of | 184 | ||||
| -rw-r--r-- | testes/db.lua | 1 | ||||
| -rw-r--r-- | testes/goto.lua | 44 | ||||
| -rw-r--r-- | testes/math.lua | 16 |
10 files changed, 272 insertions, 117 deletions
| @@ -40,11 +40,16 @@ | |||
| 40 | 40 | ||
| 41 | #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') | 41 | #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') |
| 42 | 42 | ||
| 43 | #if defined(LUA_COMPAT_GLOBAL) | ||
| 44 | #define GLOBALLEX ".g" /* not recognizable by the scanner */ | ||
| 45 | #else | ||
| 46 | #define GLOBALLEX "global" | ||
| 47 | #endif | ||
| 43 | 48 | ||
| 44 | /* ORDER RESERVED */ | 49 | /* ORDER RESERVED */ |
| 45 | static const char *const luaX_tokens [] = { | 50 | static const char *const luaX_tokens [] = { |
| 46 | "and", "break", "do", "else", "elseif", | 51 | "and", "break", "do", "else", "elseif", |
| 47 | "end", "false", "for", "function", "goto", "if", | 52 | "end", "false", "for", "function", GLOBALLEX, "goto", "if", |
| 48 | "in", "local", "nil", "not", "or", "repeat", | 53 | "in", "local", "nil", "not", "or", "repeat", |
| 49 | "return", "then", "true", "until", "while", | 54 | "return", "then", "true", "until", "while", |
| 50 | "//", "..", "...", "==", ">=", "<=", "~=", | 55 | "//", "..", "...", "==", ">=", "<=", "~=", |
| @@ -33,8 +33,8 @@ enum RESERVED { | |||
| 33 | /* terminal symbols denoted by reserved words */ | 33 | /* terminal symbols denoted by reserved words */ |
| 34 | TK_AND = FIRST_RESERVED, TK_BREAK, | 34 | TK_AND = FIRST_RESERVED, TK_BREAK, |
| 35 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, | 35 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, |
| 36 | TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, | 36 | TK_GLOBAL, TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, |
| 37 | TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, | 37 | TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, |
| 38 | /* other terminal symbols */ | 38 | /* other terminal symbols */ |
| 39 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, | 39 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, |
| 40 | TK_SHL, TK_SHR, | 40 | TK_SHL, TK_SHR, |
| @@ -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; |
| @@ -37,6 +37,9 @@ typedef enum { | |||
| 37 | info = result register */ | 37 | info = result register */ |
| 38 | VLOCAL, /* local variable; var.ridx = register index; | 38 | VLOCAL, /* local variable; var.ridx = register index; |
| 39 | var.vidx = relative index in 'actvar.arr' */ | 39 | var.vidx = relative index in 'actvar.arr' */ |
| 40 | VGLOBAL, /* global variable; | ||
| 41 | info = relative index in 'actvar.arr' (or -1 for | ||
| 42 | implicit declaration) */ | ||
| 40 | VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ | 43 | VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ |
| 41 | VCONST, /* compile-time <const> variable; | 44 | VCONST, /* compile-time <const> variable; |
| 42 | info = absolute index in 'actvar.arr' */ | 45 | info = absolute index in 'actvar.arr' */ |
| @@ -87,10 +90,16 @@ typedef struct expdesc { | |||
| 87 | 90 | ||
| 88 | 91 | ||
| 89 | /* kinds of variables */ | 92 | /* kinds of variables */ |
| 90 | #define VDKREG 0 /* regular */ | 93 | #define VDKREG 0 /* regular local */ |
| 91 | #define RDKCONST 1 /* constant */ | 94 | #define RDKCONST 1 /* local constant */ |
| 92 | #define RDKTOCLOSE 2 /* to-be-closed */ | 95 | #define RDKTOCLOSE 2 /* to-be-closed */ |
| 93 | #define RDKCTC 3 /* compile-time constant */ | 96 | #define RDKCTC 3 /* local compile-time constant */ |
| 97 | #define GDKREG 4 /* regular global */ | ||
| 98 | #define GDKCONST 5 /* global constant */ | ||
| 99 | |||
| 100 | /* variables that live in registers */ | ||
| 101 | #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) | ||
| 102 | |||
| 94 | 103 | ||
| 95 | /* description of an active local variable */ | 104 | /* description of an active local variable */ |
| 96 | typedef union Vardesc { | 105 | typedef union Vardesc { |
| @@ -14,6 +14,7 @@ | |||
| 14 | /* test Lua with compatibility code */ | 14 | /* test Lua with compatibility code */ |
| 15 | #define LUA_COMPAT_MATHLIB | 15 | #define LUA_COMPAT_MATHLIB |
| 16 | #define LUA_COMPAT_LT_LE | 16 | #define LUA_COMPAT_LT_LE |
| 17 | #undef LUA_COMPAT_GLOBAL | ||
| 17 | 18 | ||
| 18 | 19 | ||
| 19 | #define LUA_DEBUG | 20 | #define LUA_DEBUG |
| @@ -356,6 +356,12 @@ | |||
| 356 | */ | 356 | */ |
| 357 | 357 | ||
| 358 | /* | 358 | /* |
| 359 | @@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word | ||
| 360 | */ | ||
| 361 | #define LUA_COMPAT_GLOBAL | ||
| 362 | |||
| 363 | |||
| 364 | /* | ||
| 359 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. | 365 | @@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. |
| 360 | ** You can define it to get all options, or change specific options | 366 | ** You can define it to get all options, or change specific options |
| 361 | ** to fit your specific needs. | 367 | ** to fit your specific needs. |
diff --git a/manual/manual.of b/manual/manual.of index 7cd0d4db..ace5d375 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -213,11 +213,88 @@ of a given value @seeF{type}. | |||
| 213 | 213 | ||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | @sect2{globalenv| @title{Environments and the Global Environment} | 216 | @sect2{globalenv| @title{Scopes, Variables, and Environments} |
| 217 | @index{visibility} | ||
| 218 | |||
| 219 | A variable name refers to a global or a local variable according | ||
| 220 | to the declaration that is in context at that point of the code. | ||
| 221 | (For the purposes of this discussion, | ||
| 222 | a function's formal parameter is equivalent to a local variable.) | ||
| 223 | |||
| 224 | All chunks start with an implicit declaration @T{global *}, | ||
| 225 | which declares all free names as global variables; | ||
| 226 | this implicit declaration becomes void inside the scope of any other | ||
| 227 | @Rw{global} declaration, regardless of the names being declared. | ||
| 228 | @verbatim{ | ||
| 229 | X = 1 -- Ok, global by default | ||
| 230 | do | ||
| 231 | global Y -- voids implicit initial declaration | ||
| 232 | X = 1 -- ERROR, X not declared | ||
| 233 | Y = 1 -- Ok, Y declared as global | ||
| 234 | end | ||
| 235 | X = 2 -- Ok, global by default again | ||
| 236 | } | ||
| 237 | So, outside any global declaration, | ||
| 238 | Lua works as @x{global-by-default}. | ||
| 239 | Inside any global declaration, | ||
| 240 | Lua works without a default: | ||
| 241 | All variables must be declared. | ||
| 242 | |||
| 243 | Lua is a lexically scoped language. | ||
| 244 | The scope of a variable declaration begins at the first statement after | ||
| 245 | the declaration and lasts until the last non-void statement | ||
| 246 | of the innermost block that includes the declaration. | ||
| 247 | (@emph{Void statements} are labels and empty statements.) | ||
| 248 | |||
| 249 | A declaration shadows any declaration for the same name that | ||
| 250 | is in context at the point of the declaration. Inside this | ||
| 251 | shadow, any outer declaration for that name is void. | ||
| 252 | See the next example: | ||
| 253 | @verbatim{ | ||
| 254 | global print, x | ||
| 255 | x = 10 -- global variable | ||
| 256 | do -- new block | ||
| 257 | local x = x -- new 'x', with value 10 | ||
| 258 | print(x) --> 10 | ||
| 259 | x = x+1 | ||
| 260 | do -- another block | ||
| 261 | local x = x+1 -- another 'x' | ||
| 262 | print(x) --> 12 | ||
| 263 | end | ||
| 264 | print(x) --> 11 | ||
| 265 | end | ||
| 266 | print(x) --> 10 (the global one) | ||
| 267 | } | ||
| 268 | |||
| 269 | Notice that, in a declaration like @T{local x = x}, | ||
| 270 | the new @id{x} being declared is not in scope yet, | ||
| 271 | and so the @id{x} in the left-hand side refers to the outside variable. | ||
| 272 | |||
| 273 | Because of the @x{lexical scoping} rules, | ||
| 274 | local variables can be freely accessed by functions | ||
| 275 | defined inside their scope. | ||
| 276 | A local variable used by an inner function is called an @def{upvalue} | ||
| 277 | (or @emphx{external local variable}, or simply @emphx{external variable}) | ||
| 278 | inside the inner function. | ||
| 279 | |||
| 280 | Notice that each execution of a @Rw{local} statement | ||
| 281 | defines new local variables. | ||
| 282 | Consider the following example: | ||
| 283 | @verbatim{ | ||
| 284 | a = {} | ||
| 285 | local x = 20 | ||
| 286 | for i = 1, 10 do | ||
| 287 | local y = 0 | ||
| 288 | a[i] = function () y = y + 1; return x + y end | ||
| 289 | end | ||
| 290 | } | ||
| 291 | The loop creates ten closures | ||
| 292 | (that is, ten instances of the anonymous function). | ||
| 293 | Each of these closures uses a different @id{y} variable, | ||
| 294 | while all of them share the same @id{x}. | ||
| 217 | 295 | ||
| 218 | As we will discuss further in @refsec{variables} and @refsec{assignment}, | 296 | As we will discuss further in @refsec{variables} and @refsec{assignment}, |
| 219 | any reference to a free name | 297 | any reference to a global variable @id{var} |
| 220 | (that is, a name not bound to any declaration) @id{var} | ||
| 221 | is syntactically translated to @T{_ENV.var}. | 298 | is syntactically translated to @T{_ENV.var}. |
| 222 | Moreover, every chunk is compiled in the scope of | 299 | Moreover, every chunk is compiled in the scope of |
| 223 | an external local variable named @id{_ENV} @see{chunks}, | 300 | an external local variable named @id{_ENV} @see{chunks}, |
| @@ -225,12 +302,14 @@ so @id{_ENV} itself is never a free name in a chunk. | |||
| 225 | 302 | ||
| 226 | Despite the existence of this external @id{_ENV} variable and | 303 | Despite the existence of this external @id{_ENV} variable and |
| 227 | the translation of free names, | 304 | the translation of free names, |
| 228 | @id{_ENV} is a completely regular name. | 305 | @id{_ENV} is a regular name. |
| 229 | In particular, | 306 | In particular, |
| 230 | you can define new variables and parameters with that name. | 307 | you can define new variables and parameters with that name. |
| 231 | Each reference to a free name uses the @id{_ENV} that is | 308 | (However, you should not define @id{_ENV} as a global variable, |
| 232 | visible at that point in the program, | 309 | otherwise @T{_ENV.var} would translate to |
| 233 | following the usual visibility rules of Lua @see{visibility}. | 310 | @T{_ENV._ENV.var} and so on, in an infinite loop.) |
| 311 | Each reference to a global variable name uses the @id{_ENV} that is | ||
| 312 | visible at that point in the program. | ||
| 234 | 313 | ||
| 235 | Any table used as the value of @id{_ENV} is called an @def{environment}. | 314 | Any table used as the value of @id{_ENV} is called an @def{environment}. |
| 236 | 315 | ||
| @@ -244,8 +323,8 @@ When Lua loads a chunk, | |||
| 244 | the default value for its @id{_ENV} variable | 323 | the default value for its @id{_ENV} variable |
| 245 | is the global environment @seeF{load}. | 324 | is the global environment @seeF{load}. |
| 246 | Therefore, by default, | 325 | Therefore, by default, |
| 247 | free names in Lua code refer to entries in the global environment | 326 | global variables in Lua code refer to entries in the global environment |
| 248 | and, therefore, they are also called @def{global variables}. | 327 | and, therefore, they act as conventional global variables. |
| 249 | Moreover, all standard libraries are loaded in the global environment | 328 | Moreover, all standard libraries are loaded in the global environment |
| 250 | and some functions there operate on that environment. | 329 | and some functions there operate on that environment. |
| 251 | You can use @Lid{load} (or @Lid{loadfile}) | 330 | You can use @Lid{load} (or @Lid{loadfile}) |
| @@ -1198,17 +1277,15 @@ global variables, local variables, and table fields. | |||
| 1198 | 1277 | ||
| 1199 | A single name can denote a global variable or a local variable | 1278 | A single name can denote a global variable or a local variable |
| 1200 | (or a function's formal parameter, | 1279 | (or a function's formal parameter, |
| 1201 | which is a particular kind of local variable): | 1280 | which is a particular kind of local variable) @see{globalenv}: |
| 1202 | @Produc{ | 1281 | @Produc{ |
| 1203 | @producname{var}@producbody{@bnfNter{Name}} | 1282 | @producname{var}@producbody{@bnfNter{Name}} |
| 1204 | } | 1283 | } |
| 1205 | @bnfNter{Name} denotes identifiers @see{lexical}. | 1284 | @bnfNter{Name} denotes identifiers @see{lexical}. |
| 1206 | 1285 | ||
| 1207 | Any variable name is assumed to be global unless explicitly declared | 1286 | Because variables are @emph{lexically scoped}, |
| 1208 | as a local @see{localvar}. | ||
| 1209 | @x{Local variables} are @emph{lexically scoped}: | ||
| 1210 | local variables can be freely accessed by functions | 1287 | local variables can be freely accessed by functions |
| 1211 | defined inside their scope @see{visibility}. | 1288 | defined inside their scope @see{globalenv}. |
| 1212 | 1289 | ||
| 1213 | Before the first assignment to a variable, its value is @nil. | 1290 | Before the first assignment to a variable, its value is @nil. |
| 1214 | 1291 | ||
| @@ -1227,8 +1304,6 @@ The syntax @id{var.Name} is just syntactic sugar for | |||
| 1227 | 1304 | ||
| 1228 | An access to a global variable @id{x} | 1305 | An access to a global variable @id{x} |
| 1229 | is equivalent to @id{_ENV.x}. | 1306 | is equivalent to @id{_ENV.x}. |
| 1230 | Due to the way that chunks are compiled, | ||
| 1231 | the variable @id{_ENV} itself is never global @see{globalenv}. | ||
| 1232 | 1307 | ||
| 1233 | } | 1308 | } |
| 1234 | 1309 | ||
| @@ -1571,17 +1646,18 @@ Function calls are explained in @See{functioncall}. | |||
| 1571 | 1646 | ||
| 1572 | } | 1647 | } |
| 1573 | 1648 | ||
| 1574 | @sect3{localvar| @title{Local Declarations} | 1649 | @sect3{localvar| @title{Variable Declarations} |
| 1575 | @x{Local variables} can be declared anywhere inside a block. | 1650 | Local and global variables can be declared anywhere inside a block. |
| 1576 | The declaration can include an initialization: | 1651 | The declaration for locals can include an initialization: |
| 1577 | @Produc{ | 1652 | @Produc{ |
| 1578 | @producname{stat}@producbody{@Rw{local} attnamelist @bnfopt{@bnfter{=} explist}} | 1653 | @producname{stat}@producbody{@Rw{local} attnamelist @bnfopt{@bnfter{=} explist}} |
| 1654 | @producname{stat}@producbody{@Rw{global} attnamelist} | ||
| 1579 | @producname{attnamelist}@producbody{ | 1655 | @producname{attnamelist}@producbody{ |
| 1580 | @bnfNter{Name} attrib @bnfrep{@bnfter{,} @bnfNter{Name} attrib}} | 1656 | @bnfNter{Name} attrib @bnfrep{@bnfter{,} @bnfNter{Name} attrib}} |
| 1581 | } | 1657 | } |
| 1582 | If present, an initial assignment has the same semantics | 1658 | If present, an initial assignment has the same semantics |
| 1583 | of a multiple assignment @see{assignment}. | 1659 | of a multiple assignment @see{assignment}. |
| 1584 | Otherwise, all variables are initialized with @nil. | 1660 | Otherwise, all local variables are initialized with @nil. |
| 1585 | 1661 | ||
| 1586 | Each variable name may be postfixed by an attribute | 1662 | Each variable name may be postfixed by an attribute |
| 1587 | (a name between angle brackets): | 1663 | (a name between angle brackets): |
| @@ -1595,11 +1671,22 @@ that is, a variable that cannot be assigned to | |||
| 1595 | after its initialization; | 1671 | after its initialization; |
| 1596 | and @id{close}, which declares a to-be-closed variable @see{to-be-closed}. | 1672 | and @id{close}, which declares a to-be-closed variable @see{to-be-closed}. |
| 1597 | A list of variables can contain at most one to-be-closed variable. | 1673 | A list of variables can contain at most one to-be-closed variable. |
| 1674 | Only local variables can have the @id{close} attribute. | ||
| 1675 | |||
| 1676 | Note that, for global variables, | ||
| 1677 | the @emph{read-only} atribute is only a syntactical restriction: | ||
| 1678 | @verbatim{ | ||
| 1679 | global X <const> | ||
| 1680 | X = 1 -- ERROR | ||
| 1681 | _ENV.X = 1 -- Ok | ||
| 1682 | foo() -- 'foo' can freely change the global X | ||
| 1683 | } | ||
| 1598 | 1684 | ||
| 1599 | A chunk is also a block @see{chunks}, | 1685 | A chunk is also a block @see{chunks}, |
| 1600 | and so local variables can be declared in a chunk outside any explicit block. | 1686 | and so variables can be declared in a chunk outside any explicit block. |
| 1601 | 1687 | ||
| 1602 | The visibility rules for local variables are explained in @See{visibility}. | 1688 | The visibility rules for variable declarations |
| 1689 | are explained in @See{globalenv}. | ||
| 1603 | 1690 | ||
| 1604 | } | 1691 | } |
| 1605 | 1692 | ||
| @@ -2356,58 +2443,6 @@ return x,y,f() -- returns x, y, and all results from f(). | |||
| 2356 | 2443 | ||
| 2357 | } | 2444 | } |
| 2358 | 2445 | ||
| 2359 | @sect2{visibility| @title{Visibility Rules} | ||
| 2360 | |||
| 2361 | @index{visibility} | ||
| 2362 | Lua is a lexically scoped language. | ||
| 2363 | The scope of a local variable begins at the first statement after | ||
| 2364 | its declaration and lasts until the last non-void statement | ||
| 2365 | of the innermost block that includes the declaration. | ||
| 2366 | (@emph{Void statements} are labels and empty statements.) | ||
| 2367 | Consider the following example: | ||
| 2368 | @verbatim{ | ||
| 2369 | x = 10 -- global variable | ||
| 2370 | do -- new block | ||
| 2371 | local x = x -- new 'x', with value 10 | ||
| 2372 | print(x) --> 10 | ||
| 2373 | x = x+1 | ||
| 2374 | do -- another block | ||
| 2375 | local x = x+1 -- another 'x' | ||
| 2376 | print(x) --> 12 | ||
| 2377 | end | ||
| 2378 | print(x) --> 11 | ||
| 2379 | end | ||
| 2380 | print(x) --> 10 (the global one) | ||
| 2381 | } | ||
| 2382 | |||
| 2383 | Notice that, in a declaration like @T{local x = x}, | ||
| 2384 | the new @id{x} being declared is not in scope yet, | ||
| 2385 | and so the second @id{x} refers to the outside variable. | ||
| 2386 | |||
| 2387 | Because of the @x{lexical scoping} rules, | ||
| 2388 | local variables can be freely accessed by functions | ||
| 2389 | defined inside their scope. | ||
| 2390 | A local variable used by an inner function is called an @def{upvalue} | ||
| 2391 | (or @emphx{external local variable}, or simply @emphx{external variable}) | ||
| 2392 | inside the inner function. | ||
| 2393 | |||
| 2394 | Notice that each execution of a @Rw{local} statement | ||
| 2395 | defines new local variables. | ||
| 2396 | Consider the following example: | ||
| 2397 | @verbatim{ | ||
| 2398 | a = {} | ||
| 2399 | local x = 20 | ||
| 2400 | for i = 1, 10 do | ||
| 2401 | local y = 0 | ||
| 2402 | a[i] = function () y = y + 1; return x + y end | ||
| 2403 | end | ||
| 2404 | } | ||
| 2405 | The loop creates ten closures | ||
| 2406 | (that is, ten instances of the anonymous function). | ||
| 2407 | Each of these closures uses a different @id{y} variable, | ||
| 2408 | while all of them share the same @id{x}. | ||
| 2409 | |||
| 2410 | } | ||
| 2411 | 2446 | ||
| 2412 | } | 2447 | } |
| 2413 | 2448 | ||
| @@ -9535,6 +9570,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.) | |||
| 9535 | @OrNL @Rw{function} funcname funcbody | 9570 | @OrNL @Rw{function} funcname funcbody |
| 9536 | @OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody | 9571 | @OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody |
| 9537 | @OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist} | 9572 | @OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist} |
| 9573 | @OrNL @Rw{global} attnamelist | ||
| 9538 | } | 9574 | } |
| 9539 | 9575 | ||
| 9540 | @producname{attnamelist}@producbody{ | 9576 | @producname{attnamelist}@producbody{ |
diff --git a/testes/db.lua b/testes/db.lua index e4982c20..ae204c41 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
| @@ -349,6 +349,7 @@ end, "crl") | |||
| 349 | 349 | ||
| 350 | 350 | ||
| 351 | function f(a,b) | 351 | function f(a,b) |
| 352 | global collectgarbage, assert, g, string | ||
| 352 | collectgarbage() | 353 | collectgarbage() |
| 353 | local _, x = debug.getlocal(1, 1) | 354 | local _, x = debug.getlocal(1, 1) |
| 354 | local _, y = debug.getlocal(1, 2) | 355 | local _, y = debug.getlocal(1, 2) |
diff --git a/testes/goto.lua b/testes/goto.lua index eca68516..fdfddb85 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | -- $Id: testes/goto.lua $ | 1 | -- $Id: testes/goto.lua $ |
| 2 | -- See Copyright Notice in file lua.h | 2 | -- See Copyright Notice in file lua.h |
| 3 | 3 | ||
| 4 | print("testing goto and global declarations") | ||
| 5 | |||
| 4 | collectgarbage() | 6 | collectgarbage() |
| 5 | 7 | ||
| 6 | local function errmsg (code, m) | 8 | local function errmsg (code, m) |
| @@ -280,7 +282,47 @@ end | |||
| 280 | 282 | ||
| 281 | 283 | ||
| 282 | foo() | 284 | foo() |
| 283 | -------------------------------------------------------------------------------- | 285 | -------------------------------------------------------------------------- |
| 284 | 286 | ||
| 287 | do | ||
| 288 | global print, load, T<const>; global assert<const> | ||
| 289 | global string | ||
| 290 | |||
| 291 | local function checkerr (code, err) | ||
| 292 | local st, msg = load(code) | ||
| 293 | assert(not st and string.find(msg, err)) | ||
| 294 | end | ||
| 295 | |||
| 296 | -- globals must be declared after a global declaration | ||
| 297 | checkerr("global none; X = 1", "variable 'X'") | ||
| 298 | |||
| 299 | -- global variables cannot be to-be-closed | ||
| 300 | checkerr("global X<close>", "cannot be") | ||
| 301 | |||
| 302 | do | ||
| 303 | local X = 10 | ||
| 304 | do global X; X = 20 end | ||
| 305 | assert(X == 10) -- local X | ||
| 306 | end | ||
| 307 | assert(_ENV.X == 20) -- global X | ||
| 308 | |||
| 309 | -- '_ENV' cannot be global | ||
| 310 | checkerr("global _ENV, a; a = 10", "variable 'a'") | ||
| 311 | |||
| 312 | -- global declarations inside functions | ||
| 313 | checkerr([[ | ||
| 314 | global none | ||
| 315 | local function foo () XXX = 1 end --< ERROR]], "variable 'XXX'") | ||
| 316 | |||
| 317 | if not T then -- when not in "test mode", "global" isn't reserved | ||
| 318 | assert(load("global = 1; return global")() == 1) | ||
| 319 | print " ('global' is not a reserved word)" | ||
| 320 | else | ||
| 321 | -- "global" reserved, cannot be used as a variable | ||
| 322 | assert(not load("global = 1; return global")) | ||
| 323 | end | ||
| 324 | |||
| 325 | end | ||
| 285 | 326 | ||
| 286 | print'OK' | 327 | print'OK' |
| 328 | |||
diff --git a/testes/math.lua b/testes/math.lua index 88a57ce7..242579b1 100644 --- a/testes/math.lua +++ b/testes/math.lua | |||
| @@ -3,6 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | print("testing numbers and math lib") | 4 | print("testing numbers and math lib") |
| 5 | 5 | ||
| 6 | local math = require "math" | ||
| 7 | local string = require "string" | ||
| 8 | |||
| 9 | global none | ||
| 10 | |||
| 11 | global print, assert, pcall, type, pairs, load | ||
| 12 | global tonumber, tostring, select | ||
| 13 | |||
| 6 | local minint <const> = math.mininteger | 14 | local minint <const> = math.mininteger |
| 7 | local maxint <const> = math.maxinteger | 15 | local maxint <const> = math.maxinteger |
| 8 | 16 | ||
| @@ -184,7 +192,7 @@ do | |||
| 184 | for i = -3, 3 do -- variables avoid constant folding | 192 | for i = -3, 3 do -- variables avoid constant folding |
| 185 | for j = -3, 3 do | 193 | for j = -3, 3 do |
| 186 | -- domain errors (0^(-n)) are not portable | 194 | -- domain errors (0^(-n)) are not portable |
| 187 | if not _port or i ~= 0 or j > 0 then | 195 | if not _ENV._port or i ~= 0 or j > 0 then |
| 188 | assert(eq(i^j, 1 / i^(-j))) | 196 | assert(eq(i^j, 1 / i^(-j))) |
| 189 | end | 197 | end |
| 190 | end | 198 | end |
| @@ -430,7 +438,7 @@ for i = 2,36 do | |||
| 430 | assert(tonumber('\t10000000000\t', i) == i10) | 438 | assert(tonumber('\t10000000000\t', i) == i10) |
| 431 | end | 439 | end |
| 432 | 440 | ||
| 433 | if not _soft then | 441 | if not _ENV._soft then |
| 434 | -- tests with very long numerals | 442 | -- tests with very long numerals |
| 435 | assert(tonumber("0x"..string.rep("f", 13)..".0") == 2.0^(4*13) - 1) | 443 | assert(tonumber("0x"..string.rep("f", 13)..".0") == 2.0^(4*13) - 1) |
| 436 | assert(tonumber("0x"..string.rep("f", 150)..".0") == 2.0^(4*150) - 1) | 444 | assert(tonumber("0x"..string.rep("f", 150)..".0") == 2.0^(4*150) - 1) |
| @@ -632,7 +640,7 @@ assert(maxint % -2 == -1) | |||
| 632 | 640 | ||
| 633 | -- non-portable tests because Windows C library cannot compute | 641 | -- non-portable tests because Windows C library cannot compute |
| 634 | -- fmod(1, huge) correctly | 642 | -- fmod(1, huge) correctly |
| 635 | if not _port then | 643 | if not _ENV._port then |
| 636 | local function anan (x) assert(isNaN(x)) end -- assert Not a Number | 644 | local function anan (x) assert(isNaN(x)) end -- assert Not a Number |
| 637 | anan(0.0 % 0) | 645 | anan(0.0 % 0) |
| 638 | anan(1.3 % 0) | 646 | anan(1.3 % 0) |
| @@ -779,6 +787,7 @@ assert(a == '10' and b == '20') | |||
| 779 | 787 | ||
| 780 | do | 788 | do |
| 781 | print("testing -0 and NaN") | 789 | print("testing -0 and NaN") |
| 790 | global rawset, undef | ||
| 782 | local mz <const> = -0.0 | 791 | local mz <const> = -0.0 |
| 783 | local z <const> = 0.0 | 792 | local z <const> = 0.0 |
| 784 | assert(mz == z) | 793 | assert(mz == z) |
| @@ -1074,6 +1083,7 @@ do | |||
| 1074 | -- different numbers should print differently. | 1083 | -- different numbers should print differently. |
| 1075 | -- check pairs of floats with minimum detectable difference | 1084 | -- check pairs of floats with minimum detectable difference |
| 1076 | local p = floatbits - 1 | 1085 | local p = floatbits - 1 |
| 1086 | global ipairs | ||
| 1077 | for i = 1, maxexp - 1 do | 1087 | for i = 1, maxexp - 1 do |
| 1078 | for _, i in ipairs{-i, i} do | 1088 | for _, i in ipairs{-i, i} do |
| 1079 | local x = 2^i | 1089 | local x = 2^i |
