Pārlūkot izejas kodu

New syntax 'global function'

Roberto Ierusalimschy 2 mēneši atpakaļ
vecāks
revīzija
3f0ea90aa8
4 mainītis faili ar 82 papildinājumiem un 13 dzēšanām
  1. 39 10
      lparser.c
  2. 13 2
      manual/manual.of
  3. 8 0
      testes/errors.lua
  4. 22 1
      testes/goto.lua

+ 39 - 10
lparser.c

@@ -477,8 +477,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
 ** Find a variable with the given name 'n', handling global variables
 ** too.
 */
-static void singlevar (LexState *ls, expdesc *var) {
-  TString *varname = str_checkname(ls);
+static void buildvar (LexState *ls, TString *varname, expdesc *var) {
   FuncState *fs = ls->fs;
   singlevaraux(fs, varname, var, 1);
   if (var->k == VGLOBAL) {  /* global name? */
@@ -501,6 +500,11 @@ static void singlevar (LexState *ls, expdesc *var) {
 }
 
 
+static void singlevar (LexState *ls, expdesc *var) {
+  buildvar(ls, str_checkname(ls), var);
+}
+
+
 /*
 ** Adjust the number of results from an expression list 'e' with 'nexps'
 ** expressions to 'nvars' values.
@@ -1727,7 +1731,7 @@ static void localfunc (LexState *ls) {
 
 
 static lu_byte getvarattribute (LexState *ls) {
-  /* ATTRIB -> ['<' Name '>'] */
+  /* attrib -> ['<' NAME '>'] */
   if (testnext(ls, '<')) {
     TString *ts = str_checkname(ls);
     const char *attr = getstr(ts);
@@ -1752,7 +1756,7 @@ static void checktoclose (FuncState *fs, int level) {
 
 
 static void localstat (LexState *ls) {
-  /* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */
+  /* stat -> LOCAL NAME attrib { ',' NAME attrib } ['=' explist] */
   FuncState *fs = ls->fs;
   int toclose = -1;  /* index of to-be-closed variable (if any) */
   Vardesc *var;  /* last variable */
@@ -1794,8 +1798,8 @@ static void localstat (LexState *ls) {
 
 
 static void globalstat (LexState *ls) {
+  /* globalstat -> (GLOBAL) NAME attrib {',' NAME attrib} */
   FuncState *fs = ls->fs;
-  luaX_next(ls);  /* skip 'global' */
   do {
     TString *vname = str_checkname(ls);
     lu_byte kind = getvarattribute(ls);
@@ -1807,7 +1811,31 @@ static void globalstat (LexState *ls) {
     new_varkind(ls, vname, kind);
     fs->nactvar++;  /* activate declaration */
   } while (testnext(ls, ','));
-  fs->bl->globdec = 1;  /* code is in the scope of a global declaration */
+}
+
+
+static void globalfunc (LexState *ls, int line) {
+  /* globalfunc -> (GLOBAL FUNCTION) NAME body */
+  expdesc var, b;
+  FuncState *fs = ls->fs;
+  TString *fname = str_checkname(ls);
+  new_varkind(ls, fname, GDKREG);  /* declare global variable */
+  fs->nactvar++;  /* enter its scope */
+  buildvar(ls, fname, &var);
+  body(ls, &b, 0, ls->linenumber);  /* compile and return closure in 'b' */
+  luaK_storevar(fs, &var, &b);
+  luaK_fixline(fs, line);  /* definition "happens" in the first line */
+}
+
+
+static void globalstatfunc (LexState *ls, int line) {
+  /* stat -> GLOBAL globalfunc | GLOBAL globalstat */
+  luaX_next(ls);  /* skip 'global' */
+  ls->fs->bl->globdec = 1;  /* in the scope of a global declaration */
+  if (testnext(ls, TK_FUNCTION))
+    globalfunc(ls, line);
+  else
+    globalstat(ls);
 }
 
 
@@ -1930,8 +1958,8 @@ static void statement (LexState *ls) {
         localstat(ls);
       break;
     }
-    case TK_GLOBAL: {  /* stat -> globalstat */
-      globalstat(ls);
+    case TK_GLOBAL: {  /* stat -> globalstatfunc */
+      globalstatfunc(ls, line);
       break;
     }
     case TK_DBCOLON: {  /* stat -> label */
@@ -1958,8 +1986,9 @@ static void statement (LexState *ls) {
          is not reserved */
       if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) {
         int lk = luaX_lookahead(ls);
-        if (lk == TK_NAME) {  /* 'global name'? */
-          globalstat(ls);
+        if (lk == TK_NAME || lk == TK_FUNCTION) {
+          /* 'global <name>' or 'global function' */
+          globalstatfunc(ls, line);
           break;
         }
       }  /* else... */

+ 13 - 2
manual/manual.of

@@ -2229,6 +2229,7 @@ The following syntactic sugar simplifies function definitions:
 @Produc{
 @producname{stat}@producbody{@Rw{function} funcname funcbody}
 @producname{stat}@producbody{@Rw{local} @Rw{function} @bnfNter{Name} funcbody}
+@producname{stat}@producbody{@Rw{global} @Rw{function} @bnfNter{Name} funcbody}
 @producname{funcname}@producbody{@bnfNter{Name} @bnfrep{@bnfter{.} @bnfNter{Name}} @bnfopt{@bnfter{:} @bnfNter{Name}}}
 }
 The statement
@@ -2247,6 +2248,7 @@ translates to
 @verbatim{
 t.a.b.c.f = function () @rep{body} end
 }
+
 The statement
 @verbatim{
 local function f () @rep{body} end
@@ -2260,7 +2262,15 @@ not to
 local f = function () @rep{body} end
 }
 (This only makes a difference when the body of the function
-contains references to @id{f}.)
+contains recursive references to @id{f}.)
+Similarly, the statement
+@verbatim{
+global function f () @rep{body} end
+}
+translates to
+@verbatim{
+global f; f = function () @rep{body} end
+}
 
 A function definition is an executable expression,
 whose value has type @emph{function}.
@@ -2323,7 +2333,7 @@ then the function returns with no results.
 @index{multiple return}
 There is a system-dependent limit on the number of values
 that a function may return.
-This limit is guaranteed to be greater than 1000.
+This limit is guaranteed to be at least 1000.
 
 The @emphx{colon} syntax
 is used to emulate @def{methods},
@@ -9569,6 +9579,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.)
 @OrNL   @Rw{for} namelist @Rw{in} explist @Rw{do} block @Rw{end}
 @OrNL	@Rw{function} funcname funcbody
 @OrNL	@Rw{local} @Rw{function} @bnfNter{Name} funcbody
+@OrNL	@Rw{global} @Rw{function} @bnfNter{Name} funcbody
 @OrNL	@Rw{local} attnamelist @bnfopt{@bnfter{=} explist}
 @OrNL	@Rw{global} attnamelist
 }

+ 8 - 0
testes/errors.lua

@@ -489,6 +489,14 @@ if not b then
   end
 end]], 5)
 
+lineerror([[
+_ENV = 1
+global function foo ()
+  local a = 10
+  return a
+end
+]], 2)
+
 
 -- bug in 5.4.0
 lineerror([[

+ 22 - 1
testes/goto.lua

@@ -293,8 +293,9 @@ do
     assert(not st and string.find(msg, err))
   end
 
-  -- globals must be declared after a global declaration
+  -- globals must be declared, after a global declaration
   checkerr("global none; X = 1", "variable 'X'")
+  checkerr("global none; function XX() end", "variable 'XX'")
 
   -- global variables cannot be to-be-closed
   checkerr("global X<close>", "cannot be")
@@ -321,6 +322,26 @@ do
     -- "global" reserved, cannot be used as a variable
     assert(not load("global = 1; return global"))
   end
+
+  local foo = 20
+  do
+    global function foo (x)
+      if x == 0 then return 1 else return 2 * foo(x - 1) end
+    end
+    assert(foo == _ENV.foo and foo(4) == 16)
+  end
+  assert(_ENV.foo(4) == 16)
+  assert(foo == 20)   -- local one is in context here
+
+  do
+    global foo;
+    function foo (x) return end   -- Ok after declaration
+  end
+
+  checkerr([[
+    global foo <const>;
+    function foo (x) return end   -- ERROR: foo is read-only
+  ]], "assign to const variable 'foo'")
   
 end