diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-08 11:08:03 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-08 11:08:03 -0300 |
commit | 3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb (patch) | |
tree | c8f2808286713805ab138a7c4fc1ccf149d94cd7 | |
parent | 4365a45d681b4e71e3c39148489bb8eae538ccf7 (diff) | |
download | lua-3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb.tar.gz lua-3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb.tar.bz2 lua-3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb.zip |
New syntax 'global function'
-rw-r--r-- | lparser.c | 49 | ||||
-rw-r--r-- | manual/manual.of | 15 | ||||
-rw-r--r-- | testes/errors.lua | 8 | ||||
-rw-r--r-- | testes/goto.lua | 23 |
4 files changed, 82 insertions, 13 deletions
@@ -477,8 +477,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { | |||
477 | ** Find a variable with the given name 'n', handling global variables | 477 | ** Find a variable with the given name 'n', handling global variables |
478 | ** too. | 478 | ** too. |
479 | */ | 479 | */ |
480 | static void singlevar (LexState *ls, expdesc *var) { | 480 | static void buildvar (LexState *ls, TString *varname, expdesc *var) { |
481 | TString *varname = str_checkname(ls); | ||
482 | FuncState *fs = ls->fs; | 481 | FuncState *fs = ls->fs; |
483 | singlevaraux(fs, varname, var, 1); | 482 | singlevaraux(fs, varname, var, 1); |
484 | if (var->k == VGLOBAL) { /* global name? */ | 483 | if (var->k == VGLOBAL) { /* global name? */ |
@@ -501,6 +500,11 @@ static void singlevar (LexState *ls, expdesc *var) { | |||
501 | } | 500 | } |
502 | 501 | ||
503 | 502 | ||
503 | static void singlevar (LexState *ls, expdesc *var) { | ||
504 | buildvar(ls, str_checkname(ls), var); | ||
505 | } | ||
506 | |||
507 | |||
504 | /* | 508 | /* |
505 | ** Adjust the number of results from an expression list 'e' with 'nexps' | 509 | ** Adjust the number of results from an expression list 'e' with 'nexps' |
506 | ** expressions to 'nvars' values. | 510 | ** expressions to 'nvars' values. |
@@ -1727,7 +1731,7 @@ static void localfunc (LexState *ls) { | |||
1727 | 1731 | ||
1728 | 1732 | ||
1729 | static lu_byte getvarattribute (LexState *ls) { | 1733 | static lu_byte getvarattribute (LexState *ls) { |
1730 | /* ATTRIB -> ['<' Name '>'] */ | 1734 | /* attrib -> ['<' NAME '>'] */ |
1731 | if (testnext(ls, '<')) { | 1735 | if (testnext(ls, '<')) { |
1732 | TString *ts = str_checkname(ls); | 1736 | TString *ts = str_checkname(ls); |
1733 | const char *attr = getstr(ts); | 1737 | const char *attr = getstr(ts); |
@@ -1752,7 +1756,7 @@ static void checktoclose (FuncState *fs, int level) { | |||
1752 | 1756 | ||
1753 | 1757 | ||
1754 | static void localstat (LexState *ls) { | 1758 | static void localstat (LexState *ls) { |
1755 | /* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */ | 1759 | /* stat -> LOCAL NAME attrib { ',' NAME attrib } ['=' explist] */ |
1756 | FuncState *fs = ls->fs; | 1760 | FuncState *fs = ls->fs; |
1757 | int toclose = -1; /* index of to-be-closed variable (if any) */ | 1761 | int toclose = -1; /* index of to-be-closed variable (if any) */ |
1758 | Vardesc *var; /* last variable */ | 1762 | Vardesc *var; /* last variable */ |
@@ -1794,8 +1798,8 @@ static void localstat (LexState *ls) { | |||
1794 | 1798 | ||
1795 | 1799 | ||
1796 | static void globalstat (LexState *ls) { | 1800 | static void globalstat (LexState *ls) { |
1801 | /* globalstat -> (GLOBAL) NAME attrib {',' NAME attrib} */ | ||
1797 | FuncState *fs = ls->fs; | 1802 | FuncState *fs = ls->fs; |
1798 | luaX_next(ls); /* skip 'global' */ | ||
1799 | do { | 1803 | do { |
1800 | TString *vname = str_checkname(ls); | 1804 | TString *vname = str_checkname(ls); |
1801 | lu_byte kind = getvarattribute(ls); | 1805 | lu_byte kind = getvarattribute(ls); |
@@ -1807,7 +1811,31 @@ static void globalstat (LexState *ls) { | |||
1807 | new_varkind(ls, vname, kind); | 1811 | new_varkind(ls, vname, kind); |
1808 | fs->nactvar++; /* activate declaration */ | 1812 | fs->nactvar++; /* activate declaration */ |
1809 | } while (testnext(ls, ',')); | 1813 | } while (testnext(ls, ',')); |
1810 | fs->bl->globdec = 1; /* code is in the scope of a global declaration */ | 1814 | } |
1815 | |||
1816 | |||
1817 | static void globalfunc (LexState *ls, int line) { | ||
1818 | /* globalfunc -> (GLOBAL FUNCTION) NAME body */ | ||
1819 | expdesc var, b; | ||
1820 | FuncState *fs = ls->fs; | ||
1821 | TString *fname = str_checkname(ls); | ||
1822 | new_varkind(ls, fname, GDKREG); /* declare global variable */ | ||
1823 | fs->nactvar++; /* enter its scope */ | ||
1824 | buildvar(ls, fname, &var); | ||
1825 | body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */ | ||
1826 | luaK_storevar(fs, &var, &b); | ||
1827 | luaK_fixline(fs, line); /* definition "happens" in the first line */ | ||
1828 | } | ||
1829 | |||
1830 | |||
1831 | static void globalstatfunc (LexState *ls, int line) { | ||
1832 | /* stat -> GLOBAL globalfunc | GLOBAL globalstat */ | ||
1833 | luaX_next(ls); /* skip 'global' */ | ||
1834 | ls->fs->bl->globdec = 1; /* in the scope of a global declaration */ | ||
1835 | if (testnext(ls, TK_FUNCTION)) | ||
1836 | globalfunc(ls, line); | ||
1837 | else | ||
1838 | globalstat(ls); | ||
1811 | } | 1839 | } |
1812 | 1840 | ||
1813 | 1841 | ||
@@ -1930,8 +1958,8 @@ static void statement (LexState *ls) { | |||
1930 | localstat(ls); | 1958 | localstat(ls); |
1931 | break; | 1959 | break; |
1932 | } | 1960 | } |
1933 | case TK_GLOBAL: { /* stat -> globalstat */ | 1961 | case TK_GLOBAL: { /* stat -> globalstatfunc */ |
1934 | globalstat(ls); | 1962 | globalstatfunc(ls, line); |
1935 | break; | 1963 | break; |
1936 | } | 1964 | } |
1937 | case TK_DBCOLON: { /* stat -> label */ | 1965 | case TK_DBCOLON: { /* stat -> label */ |
@@ -1958,8 +1986,9 @@ static void statement (LexState *ls) { | |||
1958 | is not reserved */ | 1986 | is not reserved */ |
1959 | if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) { | 1987 | if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) { |
1960 | int lk = luaX_lookahead(ls); | 1988 | int lk = luaX_lookahead(ls); |
1961 | if (lk == TK_NAME) { /* 'global name'? */ | 1989 | if (lk == TK_NAME || lk == TK_FUNCTION) { |
1962 | globalstat(ls); | 1990 | /* 'global <name>' or 'global function' */ |
1991 | globalstatfunc(ls, line); | ||
1963 | break; | 1992 | break; |
1964 | } | 1993 | } |
1965 | } /* else... */ | 1994 | } /* else... */ |
diff --git a/manual/manual.of b/manual/manual.of index ace5d375..cc71aaad 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -2229,6 +2229,7 @@ The following syntactic sugar simplifies function definitions: | |||
2229 | @Produc{ | 2229 | @Produc{ |
2230 | @producname{stat}@producbody{@Rw{function} funcname funcbody} | 2230 | @producname{stat}@producbody{@Rw{function} funcname funcbody} |
2231 | @producname{stat}@producbody{@Rw{local} @Rw{function} @bnfNter{Name} funcbody} | 2231 | @producname{stat}@producbody{@Rw{local} @Rw{function} @bnfNter{Name} funcbody} |
2232 | @producname{stat}@producbody{@Rw{global} @Rw{function} @bnfNter{Name} funcbody} | ||
2232 | @producname{funcname}@producbody{@bnfNter{Name} @bnfrep{@bnfter{.} @bnfNter{Name}} @bnfopt{@bnfter{:} @bnfNter{Name}}} | 2233 | @producname{funcname}@producbody{@bnfNter{Name} @bnfrep{@bnfter{.} @bnfNter{Name}} @bnfopt{@bnfter{:} @bnfNter{Name}}} |
2233 | } | 2234 | } |
2234 | The statement | 2235 | The statement |
@@ -2247,6 +2248,7 @@ translates to | |||
2247 | @verbatim{ | 2248 | @verbatim{ |
2248 | t.a.b.c.f = function () @rep{body} end | 2249 | t.a.b.c.f = function () @rep{body} end |
2249 | } | 2250 | } |
2251 | |||
2250 | The statement | 2252 | The statement |
2251 | @verbatim{ | 2253 | @verbatim{ |
2252 | local function f () @rep{body} end | 2254 | local function f () @rep{body} end |
@@ -2260,7 +2262,15 @@ not to | |||
2260 | local f = function () @rep{body} end | 2262 | local f = function () @rep{body} end |
2261 | } | 2263 | } |
2262 | (This only makes a difference when the body of the function | 2264 | (This only makes a difference when the body of the function |
2263 | contains references to @id{f}.) | 2265 | contains recursive references to @id{f}.) |
2266 | Similarly, the statement | ||
2267 | @verbatim{ | ||
2268 | global function f () @rep{body} end | ||
2269 | } | ||
2270 | translates to | ||
2271 | @verbatim{ | ||
2272 | global f; f = function () @rep{body} end | ||
2273 | } | ||
2264 | 2274 | ||
2265 | A function definition is an executable expression, | 2275 | A function definition is an executable expression, |
2266 | whose value has type @emph{function}. | 2276 | whose value has type @emph{function}. |
@@ -2323,7 +2333,7 @@ then the function returns with no results. | |||
2323 | @index{multiple return} | 2333 | @index{multiple return} |
2324 | There is a system-dependent limit on the number of values | 2334 | There is a system-dependent limit on the number of values |
2325 | that a function may return. | 2335 | that a function may return. |
2326 | This limit is guaranteed to be greater than 1000. | 2336 | This limit is guaranteed to be at least 1000. |
2327 | 2337 | ||
2328 | The @emphx{colon} syntax | 2338 | The @emphx{colon} syntax |
2329 | is used to emulate @def{methods}, | 2339 | is used to emulate @def{methods}, |
@@ -9569,6 +9579,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.) | |||
9569 | @OrNL @Rw{for} namelist @Rw{in} explist @Rw{do} block @Rw{end} | 9579 | @OrNL @Rw{for} namelist @Rw{in} explist @Rw{do} block @Rw{end} |
9570 | @OrNL @Rw{function} funcname funcbody | 9580 | @OrNL @Rw{function} funcname funcbody |
9571 | @OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody | 9581 | @OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody |
9582 | @OrNL @Rw{global} @Rw{function} @bnfNter{Name} funcbody | ||
9572 | @OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist} | 9583 | @OrNL @Rw{local} attnamelist @bnfopt{@bnfter{=} explist} |
9573 | @OrNL @Rw{global} attnamelist | 9584 | @OrNL @Rw{global} attnamelist |
9574 | } | 9585 | } |
diff --git a/testes/errors.lua b/testes/errors.lua index c80051fc..6c76a99a 100644 --- a/testes/errors.lua +++ b/testes/errors.lua | |||
@@ -489,6 +489,14 @@ if not b then | |||
489 | end | 489 | end |
490 | end]], 5) | 490 | end]], 5) |
491 | 491 | ||
492 | lineerror([[ | ||
493 | _ENV = 1 | ||
494 | global function foo () | ||
495 | local a = 10 | ||
496 | return a | ||
497 | end | ||
498 | ]], 2) | ||
499 | |||
492 | 500 | ||
493 | -- bug in 5.4.0 | 501 | -- bug in 5.4.0 |
494 | lineerror([[ | 502 | lineerror([[ |
diff --git a/testes/goto.lua b/testes/goto.lua index fdfddb85..b41399ff 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
@@ -293,8 +293,9 @@ do | |||
293 | assert(not st and string.find(msg, err)) | 293 | assert(not st and string.find(msg, err)) |
294 | end | 294 | end |
295 | 295 | ||
296 | -- globals must be declared after a global declaration | 296 | -- globals must be declared, after a global declaration |
297 | checkerr("global none; X = 1", "variable 'X'") | 297 | checkerr("global none; X = 1", "variable 'X'") |
298 | checkerr("global none; function XX() end", "variable 'XX'") | ||
298 | 299 | ||
299 | -- global variables cannot be to-be-closed | 300 | -- global variables cannot be to-be-closed |
300 | checkerr("global X<close>", "cannot be") | 301 | checkerr("global X<close>", "cannot be") |
@@ -321,6 +322,26 @@ do | |||
321 | -- "global" reserved, cannot be used as a variable | 322 | -- "global" reserved, cannot be used as a variable |
322 | assert(not load("global = 1; return global")) | 323 | assert(not load("global = 1; return global")) |
323 | end | 324 | end |
325 | |||
326 | local foo = 20 | ||
327 | do | ||
328 | global function foo (x) | ||
329 | if x == 0 then return 1 else return 2 * foo(x - 1) end | ||
330 | end | ||
331 | assert(foo == _ENV.foo and foo(4) == 16) | ||
332 | end | ||
333 | assert(_ENV.foo(4) == 16) | ||
334 | assert(foo == 20) -- local one is in context here | ||
335 | |||
336 | do | ||
337 | global foo; | ||
338 | function foo (x) return end -- Ok after declaration | ||
339 | end | ||
340 | |||
341 | checkerr([[ | ||
342 | global foo <const>; | ||
343 | function foo (x) return end -- ERROR: foo is read-only | ||
344 | ]], "assign to const variable 'foo'") | ||
324 | 345 | ||
325 | end | 346 | end |
326 | 347 | ||