aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lcode.c16
-rw-r--r--lcode.h2
-rw-r--r--ldebug.c8
-rw-r--r--ldebug.h1
-rw-r--r--ljumptab.h1
-rw-r--r--lopcodes.c1
-rw-r--r--lopcodes.h2
-rw-r--r--lopnames.h1
-rw-r--r--lparser.c19
-rw-r--r--lvm.c6
-rw-r--r--manual/manual.of14
-rw-r--r--testes/goto.lua21
-rw-r--r--testes/memerr.lua4
13 files changed, 87 insertions, 9 deletions
diff --git a/lcode.c b/lcode.c
index f09edb5f..d82f8263 100644
--- a/lcode.c
+++ b/lcode.c
@@ -706,6 +706,22 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) {
706 706
707 707
708/* 708/*
709** Get the value of 'var' in a register and generate an opcode to check
710** whether that register is nil. 'k' is the index of the variable name
711** in the list of constants. If its value cannot be encoded in Bx, a 0
712** will use '?' for the name.
713*/
714void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k, int line) {
715 luaK_exp2anyreg(fs, var);
716 luaK_fixline(fs, line);
717 k = (k >= MAXARG_Bx) ? 0 : k + 1;
718 luaK_codeABx(fs, OP_ERRNNIL, var->u.info, k);
719 luaK_fixline(fs, line);
720 freeexp(fs, var);
721}
722
723
724/*
709** Convert a constant in 'v' into an expression description 'e' 725** Convert a constant in 'v' into an expression description 'e'
710*/ 726*/
711static void const2exp (TValue *v, expdesc *e) { 727static void const2exp (TValue *v, expdesc *e) {
diff --git a/lcode.h b/lcode.h
index f6397a3c..09e5c802 100644
--- a/lcode.h
+++ b/lcode.h
@@ -68,6 +68,8 @@ LUAI_FUNC int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C,
68LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); 68LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
69LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 69LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
70LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); 70LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
71LUAI_FUNC void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k,
72 int line);
71LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 73LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
72LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); 74LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
73LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); 75LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
diff --git a/ldebug.c b/ldebug.c
index 9110f437..abead91c 100644
--- a/ldebug.c
+++ b/ldebug.c
@@ -814,6 +814,14 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
814} 814}
815 815
816 816
817l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k) {
818 const char *globalname = "?"; /* default name if k == 0 */
819 if (k > 0)
820 kname(cl->p, k - 1, &globalname);
821 luaG_runerror(L, "global '%s' already defined", globalname);
822}
823
824
817/* add src:line information to 'msg' */ 825/* add src:line information to 'msg' */
818const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, 826const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
819 int line) { 827 int line) {
diff --git a/ldebug.h b/ldebug.h
index 2bfce3cb..20d07818 100644
--- a/ldebug.h
+++ b/ldebug.h
@@ -53,6 +53,7 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
53 const TValue *p2); 53 const TValue *p2);
54LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, 54LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
55 const TValue *p2); 55 const TValue *p2);
56LUAI_FUNC l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k);
56LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); 57LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
57LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, 58LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
58 TString *src, int line); 59 TString *src, int line);
diff --git a/ljumptab.h b/ljumptab.h
index f896b658..52fa6d74 100644
--- a/ljumptab.h
+++ b/ljumptab.h
@@ -107,6 +107,7 @@ static const void *const disptab[NUM_OPCODES] = {
107&&L_OP_CLOSURE, 107&&L_OP_CLOSURE,
108&&L_OP_VARARG, 108&&L_OP_VARARG,
109&&L_OP_GETVARG, 109&&L_OP_GETVARG,
110&&L_OP_ERRNNIL,
110&&L_OP_VARARGPREP, 111&&L_OP_VARARGPREP,
111&&L_OP_EXTRAARG 112&&L_OP_EXTRAARG
112 113
diff --git a/lopcodes.c b/lopcodes.c
index 47458e40..7e182315 100644
--- a/lopcodes.c
+++ b/lopcodes.c
@@ -103,6 +103,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
103 ,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */ 103 ,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
104 ,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */ 104 ,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
105 ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */ 105 ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */
106 ,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */
106 ,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */ 107 ,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
107 ,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */ 108 ,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
108}; 109};
diff --git a/lopcodes.h b/lopcodes.h
index 82bba721..f7bded2c 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -340,6 +340,8 @@ OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
340 340
341OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */ 341OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */
342 342
343OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx] is global name)*/
344
343OP_VARARGPREP,/* (adjust vararg parameters) */ 345OP_VARARGPREP,/* (adjust vararg parameters) */
344 346
345OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ 347OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
diff --git a/lopnames.h b/lopnames.h
index aa7bea77..0554a2e9 100644
--- a/lopnames.h
+++ b/lopnames.h
@@ -95,6 +95,7 @@ static const char *const opnames[] = {
95 "CLOSURE", 95 "CLOSURE",
96 "VARARG", 96 "VARARG",
97 "GETVARG", 97 "GETVARG",
98 "ERRNNIL",
98 "VARARGPREP", 99 "VARARGPREP",
99 "EXTRAARG", 100 "EXTRAARG",
100 NULL 101 NULL
diff --git a/lparser.c b/lparser.c
index 40a30ff6..77141e79 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1875,6 +1875,16 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) {
1875} 1875}
1876 1876
1877 1877
1878static void checkglobal (LexState *ls, TString *varname, int line) {
1879 FuncState *fs = ls->fs;
1880 expdesc var;
1881 int k;
1882 buildglobal(ls, varname, &var); /* create global variable in 'var' */
1883 k = var.u.ind.keystr; /* index of global name in 'k' */
1884 luaK_codecheckglobal(fs, &var, k, line);
1885}
1886
1887
1878/* 1888/*
1879** Recursively traverse list of globals to be initalized. When 1889** Recursively traverse list of globals to be initalized. When
1880** going, generate table description for the global. In the end, 1890** going, generate table description for the global. In the end,
@@ -1883,7 +1893,8 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) {
1883** the stack to the corresponding table description. 'n' is the variable 1893** the stack to the corresponding table description. 'n' is the variable
1884** being handled, range [0, nvars - 1]. 1894** being handled, range [0, nvars - 1].
1885*/ 1895*/
1886static void initglobal (LexState *ls, int nvars, int firstidx, int n) { 1896static void initglobal (LexState *ls, int nvars, int firstidx, int n,
1897 int line) {
1887 if (n == nvars) { /* traversed all variables? */ 1898 if (n == nvars) { /* traversed all variables? */
1888 expdesc e; 1899 expdesc e;
1889 int nexps = explist(ls, &e); /* read list of expressions */ 1900 int nexps = explist(ls, &e); /* read list of expressions */
@@ -1895,8 +1906,9 @@ static void initglobal (LexState *ls, int nvars, int firstidx, int n) {
1895 TString *varname = getlocalvardesc(fs, firstidx + n)->vd.name; 1906 TString *varname = getlocalvardesc(fs, firstidx + n)->vd.name;
1896 buildglobal(ls, varname, &var); /* create global variable in 'var' */ 1907 buildglobal(ls, varname, &var); /* create global variable in 'var' */
1897 enterlevel(ls); /* control recursion depth */ 1908 enterlevel(ls); /* control recursion depth */
1898 initglobal(ls, nvars, firstidx, n + 1); 1909 initglobal(ls, nvars, firstidx, n + 1, line);
1899 leavelevel(ls); 1910 leavelevel(ls);
1911 checkglobal(ls, varname, line);
1900 storevartop(fs, &var); 1912 storevartop(fs, &var);
1901 } 1913 }
1902} 1914}
@@ -1913,7 +1925,7 @@ static void globalnames (LexState *ls, lu_byte defkind) {
1913 nvars++; 1925 nvars++;
1914 } while (testnext(ls, ',')); 1926 } while (testnext(ls, ','));
1915 if (testnext(ls, '=')) /* initialization? */ 1927 if (testnext(ls, '=')) /* initialization? */
1916 initglobal(ls, nvars, lastidx - nvars + 1, 0); 1928 initglobal(ls, nvars, lastidx - nvars + 1, 0, ls->linenumber);
1917 fs->nactvar = cast_short(fs->nactvar + nvars); /* activate declaration */ 1929 fs->nactvar = cast_short(fs->nactvar + nvars); /* activate declaration */
1918} 1930}
1919 1931
@@ -1943,6 +1955,7 @@ static void globalfunc (LexState *ls, int line) {
1943 fs->nactvar++; /* enter its scope */ 1955 fs->nactvar++; /* enter its scope */
1944 buildglobal(ls, fname, &var); 1956 buildglobal(ls, fname, &var);
1945 body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */ 1957 body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */
1958 checkglobal(ls, fname, line);
1946 luaK_storevar(fs, &var, &b); 1959 luaK_storevar(fs, &var, &b);
1947 luaK_fixline(fs, line); /* definition "happens" in the first line */ 1960 luaK_fixline(fs, line); /* definition "happens" in the first line */
1948} 1961}
diff --git a/lvm.c b/lvm.c
index efb0db28..2a9fb67a 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1940,6 +1940,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1940 luaT_getvararg(ci, ra, rc); 1940 luaT_getvararg(ci, ra, rc);
1941 vmbreak; 1941 vmbreak;
1942 } 1942 }
1943 vmcase(OP_ERRNNIL) {
1944 TValue *ra = vRA(i);
1945 if (!ttisnil(ra))
1946 halfProtect(luaG_errnnil(L, cl, GETARG_Bx(i)));
1947 vmbreak;
1948 }
1943 vmcase(OP_VARARGPREP) { 1949 vmcase(OP_VARARGPREP) {
1944 ProtectNT(luaT_adjustvarargs(L, ci, cl->p)); 1950 ProtectNT(luaT_adjustvarargs(L, ci, cl->p));
1945 if (l_unlikely(trap)) { /* previous "Protect" updated trap */ 1951 if (l_unlikely(trap)) { /* previous "Protect" updated trap */
diff --git a/manual/manual.of b/manual/manual.of
index 0127df02..eaf0ce78 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1660,9 +1660,15 @@ The declaration can include an initialization:
1660@producname{stat}@producbody{@Rw{global} 1660@producname{stat}@producbody{@Rw{global}
1661 attnamelist @bnfopt{@bnfter{=} explist}} 1661 attnamelist @bnfopt{@bnfter{=} explist}}
1662} 1662}
1663If present, an initial assignment has the same semantics 1663If there is no initialization,
1664local variables are initialized with @nil;
1665global variables are left unchanged.
1666Otherwise, the initialization gets the same adjustment
1664of a multiple assignment @see{assignment}. 1667of a multiple assignment @see{assignment}.
1665Otherwise, all local variables are initialized with @nil. 1668Moreover, for global variables,
1669the initialization will raise a runtime error
1670if the variable is already defined,
1671that is, it has a non-nil value.
1666 1672
1667The list of names may be prefixed by an attribute 1673The list of names may be prefixed by an attribute
1668(a name between angle brackets) 1674(a name between angle brackets)
@@ -2312,8 +2318,10 @@ global function f () @rep{body} end
2312} 2318}
2313translates to 2319translates to
2314@verbatim{ 2320@verbatim{
2315global f; f = function () @rep{body} end 2321global f; global f = function () @rep{body} end
2316} 2322}
2323The second @Rw{global} makes the assignment an initialization,
2324which will raise an error if that global is already defined.
2317 2325
2318The @emphx{colon} syntax 2326The @emphx{colon} syntax
2319is used to emulate @def{methods}, 2327is used to emulate @def{methods},
diff --git a/testes/goto.lua b/testes/goto.lua
index a692a623..906208b5 100644
--- a/testes/goto.lua
+++ b/testes/goto.lua
@@ -293,6 +293,7 @@ end
293foo() 293foo()
294-------------------------------------------------------------------------- 294--------------------------------------------------------------------------
295 295
296-- check for compilation errors
296local function checkerr (code, err) 297local function checkerr (code, err)
297 local st, msg = load(code) 298 local st, msg = load(code)
298 assert(not st and string.find(msg, err)) 299 assert(not st and string.find(msg, err))
@@ -414,22 +415,26 @@ end
414do print "testing initialization in global declarations" 415do print "testing initialization in global declarations"
415 global<const> a, b, c = 10, 20, 30 416 global<const> a, b, c = 10, 20, 30
416 assert(_ENV.a == 10 and b == 20 and c == 30) 417 assert(_ENV.a == 10 and b == 20 and c == 30)
418 _ENV.a = nil; _ENV.b = nil; _ENV.c = nil;
417 419
418 global<const> a, b, c = 10 420 global<const> a, b, c = 10
419 assert(_ENV.a == 10 and b == nil and c == nil) 421 assert(_ENV.a == 10 and b == nil and c == nil)
422 _ENV.a = nil; _ENV.b = nil; _ENV.c = nil;
420 423
421 global table 424 global table
422 global a, b, c, d = table.unpack{1, 2, 3, 6, 5} 425 global a, b, c, d = table.unpack{1, 2, 3, 6, 5}
423 assert(_ENV.a == 1 and b == 2 and c == 3 and d == 6) 426 assert(_ENV.a == 1 and b == 2 and c == 3 and d == 6)
427 a = nil; b = nil; c = nil; d = nil
424 428
425 local a, b = 100, 200 429 local a, b = 100, 200
426 do 430 do
427 global a, b = a, b 431 global a, b = a, b
428 end 432 end
429 assert(_ENV.a == 100 and _ENV.b == 200) 433 assert(_ENV.a == 100 and _ENV.b == 200)
434 _ENV.a = nil; _ENV.b = nil
430 435
431 436
432 _ENV.a, _ENV.b, _ENV.c, _ENV.d = nil -- erase these globals 437 assert(_ENV.a == nil and _ENV.b == nil and _ENV.c == nil and _ENV.d == nil)
433end 438end
434 439
435do 440do
@@ -454,5 +459,19 @@ do
454 assert(env.a == 10 and env.b == 20 and env.c == 30) 459 assert(env.a == 10 and env.b == 20 and env.c == 30)
455end 460end
456 461
462
463do -- testing global redefinitions
464 -- cannot use 'checkerr' as errors are not compile time
465 global pcall
466 local f = assert(load("global print = 10"))
467 local st, msg = pcall(f)
468 assert(string.find(msg, "global 'print' already defined"))
469
470 local f = assert(load("local _ENV = {AA = false}; global AA = 10"))
471 local st, msg = pcall(f)
472 assert(string.find(msg, "global 'AA' already defined"))
473
474end
475
457print'OK' 476print'OK'
458 477
diff --git a/testes/memerr.lua b/testes/memerr.lua
index 2cc8f481..9c940ca7 100644
--- a/testes/memerr.lua
+++ b/testes/memerr.lua
@@ -166,9 +166,9 @@ local function expand (n,s)
166 e, s, expand(n-1,s), e) 166 e, s, expand(n-1,s), e)
167end 167end
168 168
169G=0; collectgarbage(); a =collectgarbage("count") 169G=0; collectgarbage()
170load(expand(20,"G=G+1"))() 170load(expand(20,"G=G+1"))()
171assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) 171assert(G==20); collectgarbage()
172G = nil 172G = nil
173 173
174testamem("running code on new thread", function () 174testamem("running code on new thread", function ()