aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-05-08 11:08:03 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-05-08 11:08:03 -0300
commit3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb (patch)
treec8f2808286713805ab138a7c4fc1ccf149d94cd7
parent4365a45d681b4e71e3c39148489bb8eae538ccf7 (diff)
downloadlua-3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb.tar.gz
lua-3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb.tar.bz2
lua-3f0ea90aa8b8493485637f6e8d2a070a1ac0d5cb.zip
New syntax 'global function'
-rw-r--r--lparser.c49
-rw-r--r--manual/manual.of15
-rw-r--r--testes/errors.lua8
-rw-r--r--testes/goto.lua23
4 files changed, 82 insertions, 13 deletions
diff --git a/lparser.c b/lparser.c
index 61ce0908..a11f1dd3 100644
--- a/lparser.c
+++ b/lparser.c
@@ -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*/
480static void singlevar (LexState *ls, expdesc *var) { 480static 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
503static 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
1729static lu_byte getvarattribute (LexState *ls) { 1733static 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
1754static void localstat (LexState *ls) { 1758static 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
1796static void globalstat (LexState *ls) { 1800static 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
1817static 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
1831static 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}
2234The statement 2235The statement
@@ -2247,6 +2248,7 @@ translates to
2247@verbatim{ 2248@verbatim{
2248t.a.b.c.f = function () @rep{body} end 2249t.a.b.c.f = function () @rep{body} end
2249} 2250}
2251
2250The statement 2252The statement
2251@verbatim{ 2253@verbatim{
2252local function f () @rep{body} end 2254local function f () @rep{body} end
@@ -2260,7 +2262,15 @@ not to
2260local f = function () @rep{body} end 2262local 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
2263contains references to @id{f}.) 2265contains recursive references to @id{f}.)
2266Similarly, the statement
2267@verbatim{
2268global function f () @rep{body} end
2269}
2270translates to
2271@verbatim{
2272global f; f = function () @rep{body} end
2273}
2264 2274
2265A function definition is an executable expression, 2275A function definition is an executable expression,
2266whose value has type @emph{function}. 2276whose value has type @emph{function}.
@@ -2323,7 +2333,7 @@ then the function returns with no results.
2323@index{multiple return} 2333@index{multiple return}
2324There is a system-dependent limit on the number of values 2334There is a system-dependent limit on the number of values
2325that a function may return. 2335that a function may return.
2326This limit is guaranteed to be greater than 1000. 2336This limit is guaranteed to be at least 1000.
2327 2337
2328The @emphx{colon} syntax 2338The @emphx{colon} syntax
2329is used to emulate @def{methods}, 2339is 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
490end]], 5) 490end]], 5)
491 491
492lineerror([[
493_ENV = 1
494global function foo ()
495 local a = 10
496 return a
497end
498]], 2)
499
492 500
493-- bug in 5.4.0 501-- bug in 5.4.0
494lineerror([[ 502lineerror([[
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
325end 346end
326 347