New syntax 'global function'
This commit is contained in:
49
lparser.c
49
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
|
** Find a variable with the given name 'n', handling global variables
|
||||||
** too.
|
** too.
|
||||||
*/
|
*/
|
||||||
static void singlevar (LexState *ls, expdesc *var) {
|
static void buildvar (LexState *ls, TString *varname, expdesc *var) {
|
||||||
TString *varname = str_checkname(ls);
|
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
singlevaraux(fs, varname, var, 1);
|
singlevaraux(fs, varname, var, 1);
|
||||||
if (var->k == VGLOBAL) { /* global name? */
|
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'
|
** Adjust the number of results from an expression list 'e' with 'nexps'
|
||||||
** expressions to 'nvars' values.
|
** expressions to 'nvars' values.
|
||||||
@@ -1727,7 +1731,7 @@ static void localfunc (LexState *ls) {
|
|||||||
|
|
||||||
|
|
||||||
static lu_byte getvarattribute (LexState *ls) {
|
static lu_byte getvarattribute (LexState *ls) {
|
||||||
/* ATTRIB -> ['<' Name '>'] */
|
/* attrib -> ['<' NAME '>'] */
|
||||||
if (testnext(ls, '<')) {
|
if (testnext(ls, '<')) {
|
||||||
TString *ts = str_checkname(ls);
|
TString *ts = str_checkname(ls);
|
||||||
const char *attr = getstr(ts);
|
const char *attr = getstr(ts);
|
||||||
@@ -1752,7 +1756,7 @@ static void checktoclose (FuncState *fs, int level) {
|
|||||||
|
|
||||||
|
|
||||||
static void localstat (LexState *ls) {
|
static void localstat (LexState *ls) {
|
||||||
/* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */
|
/* stat -> LOCAL NAME attrib { ',' NAME attrib } ['=' explist] */
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
int toclose = -1; /* index of to-be-closed variable (if any) */
|
int toclose = -1; /* index of to-be-closed variable (if any) */
|
||||||
Vardesc *var; /* last variable */
|
Vardesc *var; /* last variable */
|
||||||
@@ -1794,8 +1798,8 @@ static void localstat (LexState *ls) {
|
|||||||
|
|
||||||
|
|
||||||
static void globalstat (LexState *ls) {
|
static void globalstat (LexState *ls) {
|
||||||
|
/* globalstat -> (GLOBAL) NAME attrib {',' NAME attrib} */
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
luaX_next(ls); /* skip 'global' */
|
|
||||||
do {
|
do {
|
||||||
TString *vname = str_checkname(ls);
|
TString *vname = str_checkname(ls);
|
||||||
lu_byte kind = getvarattribute(ls);
|
lu_byte kind = getvarattribute(ls);
|
||||||
@@ -1807,7 +1811,31 @@ static void globalstat (LexState *ls) {
|
|||||||
new_varkind(ls, vname, kind);
|
new_varkind(ls, vname, kind);
|
||||||
fs->nactvar++; /* activate declaration */
|
fs->nactvar++; /* activate declaration */
|
||||||
} while (testnext(ls, ','));
|
} 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);
|
localstat(ls);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_GLOBAL: { /* stat -> globalstat */
|
case TK_GLOBAL: { /* stat -> globalstatfunc */
|
||||||
globalstat(ls);
|
globalstatfunc(ls, line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_DBCOLON: { /* stat -> label */
|
case TK_DBCOLON: { /* stat -> label */
|
||||||
@@ -1958,8 +1986,9 @@ static void statement (LexState *ls) {
|
|||||||
is not reserved */
|
is not reserved */
|
||||||
if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) {
|
if (eqstr(ls->t.seminfo.ts, luaS_newliteral(ls->L, "global"))) {
|
||||||
int lk = luaX_lookahead(ls);
|
int lk = luaX_lookahead(ls);
|
||||||
if (lk == TK_NAME) { /* 'global name'? */
|
if (lk == TK_NAME || lk == TK_FUNCTION) {
|
||||||
globalstat(ls);
|
/* 'global <name>' or 'global function' */
|
||||||
|
globalstatfunc(ls, line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} /* else... */
|
} /* else... */
|
||||||
|
|||||||
@@ -2229,6 +2229,7 @@ The following syntactic sugar simplifies function definitions:
|
|||||||
@Produc{
|
@Produc{
|
||||||
@producname{stat}@producbody{@Rw{function} funcname funcbody}
|
@producname{stat}@producbody{@Rw{function} funcname funcbody}
|
||||||
@producname{stat}@producbody{@Rw{local} @Rw{function} @bnfNter{Name} 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}}}
|
@producname{funcname}@producbody{@bnfNter{Name} @bnfrep{@bnfter{.} @bnfNter{Name}} @bnfopt{@bnfter{:} @bnfNter{Name}}}
|
||||||
}
|
}
|
||||||
The statement
|
The statement
|
||||||
@@ -2247,6 +2248,7 @@ translates to
|
|||||||
@verbatim{
|
@verbatim{
|
||||||
t.a.b.c.f = function () @rep{body} end
|
t.a.b.c.f = function () @rep{body} end
|
||||||
}
|
}
|
||||||
|
|
||||||
The statement
|
The statement
|
||||||
@verbatim{
|
@verbatim{
|
||||||
local function f () @rep{body} end
|
local function f () @rep{body} end
|
||||||
@@ -2260,7 +2262,15 @@ not to
|
|||||||
local f = function () @rep{body} end
|
local f = function () @rep{body} end
|
||||||
}
|
}
|
||||||
(This only makes a difference when the body of the function
|
(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,
|
A function definition is an executable expression,
|
||||||
whose value has type @emph{function}.
|
whose value has type @emph{function}.
|
||||||
@@ -2323,7 +2333,7 @@ then the function returns with no results.
|
|||||||
@index{multiple return}
|
@index{multiple return}
|
||||||
There is a system-dependent limit on the number of values
|
There is a system-dependent limit on the number of values
|
||||||
that a function may return.
|
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
|
The @emphx{colon} syntax
|
||||||
is used to emulate @def{methods},
|
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{for} namelist @Rw{in} explist @Rw{do} block @Rw{end}
|
||||||
@OrNL @Rw{function} funcname funcbody
|
@OrNL @Rw{function} funcname funcbody
|
||||||
@OrNL @Rw{local} @Rw{function} @bnfNter{Name} 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{local} attnamelist @bnfopt{@bnfter{=} explist}
|
||||||
@OrNL @Rw{global} attnamelist
|
@OrNL @Rw{global} attnamelist
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -489,6 +489,14 @@ if not b then
|
|||||||
end
|
end
|
||||||
end]], 5)
|
end]], 5)
|
||||||
|
|
||||||
|
lineerror([[
|
||||||
|
_ENV = 1
|
||||||
|
global function foo ()
|
||||||
|
local a = 10
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
]], 2)
|
||||||
|
|
||||||
|
|
||||||
-- bug in 5.4.0
|
-- bug in 5.4.0
|
||||||
lineerror([[
|
lineerror([[
|
||||||
|
|||||||
@@ -293,8 +293,9 @@ do
|
|||||||
assert(not st and string.find(msg, err))
|
assert(not st and string.find(msg, err))
|
||||||
end
|
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; X = 1", "variable 'X'")
|
||||||
|
checkerr("global none; function XX() end", "variable 'XX'")
|
||||||
|
|
||||||
-- global variables cannot be to-be-closed
|
-- global variables cannot be to-be-closed
|
||||||
checkerr("global X<close>", "cannot be")
|
checkerr("global X<close>", "cannot be")
|
||||||
@@ -322,6 +323,26 @@ do
|
|||||||
assert(not load("global = 1; return global"))
|
assert(not load("global = 1; return global"))
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
print'OK'
|
print'OK'
|
||||||
|
|||||||
Reference in New Issue
Block a user