Skip to content

Commit e44f3a2

Browse files
committed
Global initialization checks name conflict
Initialization "global a = 10" raises an error if global 'a' is already defined, that is, it has a non-nil value.
1 parent f791bb6 commit e44f3a2

13 files changed

Lines changed: 87 additions & 9 deletions

File tree

lcode.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,22 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) {
705705
}
706706

707707

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+
*/
714+
void 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+
708724
/*
709725
** Convert a constant in 'v' into an expression description 'e'
710726
*/

lcode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ LUAI_FUNC int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C,
6868
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
6969
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
7070
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
71+
LUAI_FUNC void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k,
72+
int line);
7173
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
7274
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
7375
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);

ldebug.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,14 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
814814
}
815815

816816

817+
l_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+
817825
/* add src:line information to 'msg' */
818826
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
819827
int line) {

ldebug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
5353
const TValue *p2);
5454
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
5555
const TValue *p2);
56+
LUAI_FUNC l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k);
5657
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
5758
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
5859
TString *src, int line);

ljumptab.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ static const void *const disptab[NUM_OPCODES] = {
107107
&&L_OP_CLOSURE,
108108
&&L_OP_VARARG,
109109
&&L_OP_GETVARG,
110+
&&L_OP_ERRNNIL,
110111
&&L_OP_VARARGPREP,
111112
&&L_OP_EXTRAARG
112113

lopcodes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
103103
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
104104
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
105105
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */
106+
,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */
106107
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
107108
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
108109
};

lopcodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
340340

341341
OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */
342342

343+
OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx] is global name)*/
344+
343345
OP_VARARGPREP,/* (adjust vararg parameters) */
344346

345347
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */

lopnames.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ static const char *const opnames[] = {
9595
"CLOSURE",
9696
"VARARG",
9797
"GETVARG",
98+
"ERRNNIL",
9899
"VARARGPREP",
99100
"EXTRAARG",
100101
NULL

lparser.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,16 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) {
18751875
}
18761876

18771877

1878+
static 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+
18781888
/*
18791889
** Recursively traverse list of globals to be initalized. When
18801890
** going, generate table description for the global. In the end,
@@ -1883,7 +1893,8 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) {
18831893
** the stack to the corresponding table description. 'n' is the variable
18841894
** being handled, range [0, nvars - 1].
18851895
*/
1886-
static void initglobal (LexState *ls, int nvars, int firstidx, int n) {
1896+
static void initglobal (LexState *ls, int nvars, int firstidx, int n,
1897+
int line) {
18871898
if (n == nvars) { /* traversed all variables? */
18881899
expdesc e;
18891900
int nexps = explist(ls, &e); /* read list of expressions */
@@ -1895,8 +1906,9 @@ static void initglobal (LexState *ls, int nvars, int firstidx, int n) {
18951906
TString *varname = getlocalvardesc(fs, firstidx + n)->vd.name;
18961907
buildglobal(ls, varname, &var); /* create global variable in 'var' */
18971908
enterlevel(ls); /* control recursion depth */
1898-
initglobal(ls, nvars, firstidx, n + 1);
1909+
initglobal(ls, nvars, firstidx, n + 1, line);
18991910
leavelevel(ls);
1911+
checkglobal(ls, varname, line);
19001912
storevartop(fs, &var);
19011913
}
19021914
}
@@ -1913,7 +1925,7 @@ static void globalnames (LexState *ls, lu_byte defkind) {
19131925
nvars++;
19141926
} while (testnext(ls, ','));
19151927
if (testnext(ls, '=')) /* initialization? */
1916-
initglobal(ls, nvars, lastidx - nvars + 1, 0);
1928+
initglobal(ls, nvars, lastidx - nvars + 1, 0, ls->linenumber);
19171929
fs->nactvar = cast_short(fs->nactvar + nvars); /* activate declaration */
19181930
}
19191931

@@ -1943,6 +1955,7 @@ static void globalfunc (LexState *ls, int line) {
19431955
fs->nactvar++; /* enter its scope */
19441956
buildglobal(ls, fname, &var);
19451957
body(ls, &b, 0, ls->linenumber); /* compile and return closure in 'b' */
1958+
checkglobal(ls, fname, line);
19461959
luaK_storevar(fs, &var, &b);
19471960
luaK_fixline(fs, line); /* definition "happens" in the first line */
19481961
}

lvm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,6 +1940,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
19401940
luaT_getvararg(ci, ra, rc);
19411941
vmbreak;
19421942
}
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+
}
19431949
vmcase(OP_VARARGPREP) {
19441950
ProtectNT(luaT_adjustvarargs(L, ci, cl->p));
19451951
if (l_unlikely(trap)) { /* previous "Protect" updated trap */

0 commit comments

Comments
 (0)