mirror of
https://github.com/lua/lua
synced 2024-11-22 12:51:30 +03:00
new experimental syntax using reserved word 'undef'
This commit is contained in:
parent
464658b16a
commit
4a1612ff9b
20
lbaselib.c
20
lbaselib.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lbaselib.c,v 1.321 2018/02/27 17:48:28 roberto Exp roberto $
|
||||
** $Id: lbaselib.c,v 1.322 2018/02/27 18:47:32 roberto Exp roberto $
|
||||
** Basic library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -170,22 +170,6 @@ static int luaB_rawset (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
static int luaB_keyin (lua_State *L) {
|
||||
luaL_checkany(L, 2); /* ensures a first argument too */
|
||||
lua_settop(L, 2);
|
||||
lua_pushboolean(L, lua_keyin(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_removekey (lua_State *L) {
|
||||
luaL_checkany(L, 2); /* ensures a first argument too */
|
||||
lua_settop(L, 2);
|
||||
lua_removekey(L, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pushmode (lua_State *L, int oldmode) {
|
||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational");
|
||||
return 1;
|
||||
@ -503,8 +487,6 @@ static const luaL_Reg base_funcs[] = {
|
||||
{"rawlen", luaB_rawlen},
|
||||
{"rawget", luaB_rawget},
|
||||
{"rawset", luaB_rawset},
|
||||
{"keyin", luaB_keyin},
|
||||
{"removekey", luaB_removekey},
|
||||
{"select", luaB_select},
|
||||
{"setmetatable", luaB_setmetatable},
|
||||
{"tonumber", luaB_tonumber},
|
||||
|
63
lcode.c
63
lcode.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lcode.c,v 2.157 2018/02/21 15:49:32 roberto Exp roberto $
|
||||
** $Id: lcode.c,v 2.158 2018/02/26 14:16:05 roberto Exp roberto $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -40,6 +40,14 @@
|
||||
static int codesJ (FuncState *fs, OpCode o, int sj, int k);
|
||||
|
||||
|
||||
|
||||
/* semantic error */
|
||||
l_noret luaK_semerror (LexState *ls, const char *msg) {
|
||||
ls->t.token = 0; /* remove "near <token>" from final message */
|
||||
luaX_syntaxerror(ls, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** If expression is a numeric constant, fills 'v' with its value
|
||||
** and returns 1. Otherwise, returns 0.
|
||||
@ -670,6 +678,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
||||
e->k = VNONRELOC; /* becomes a non-relocatable value */
|
||||
break;
|
||||
}
|
||||
case VUNDEF: { /* not a real expression */
|
||||
luaK_semerror(fs->ls, "'undef' is not a value!!");
|
||||
break;
|
||||
}
|
||||
case VUPVAL: { /* move value to some (pending) register */
|
||||
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
|
||||
e->k = VRELOC;
|
||||
@ -1398,6 +1410,48 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
|
||||
}
|
||||
|
||||
|
||||
static void normalizeindexed (FuncState *fs, expdesc *v) {
|
||||
if (v->k != VINDEXED) { /* not in proper form? */
|
||||
int key = fs->freereg; /* register with key value */
|
||||
luaK_reserveregs(fs, 1);
|
||||
switch (v->k) {
|
||||
case VINDEXI:
|
||||
luaK_int(fs, key, v->u.ind.idx);
|
||||
break;
|
||||
case VINDEXSTR:
|
||||
luaK_codek(fs, key, v->u.ind.idx);
|
||||
break;
|
||||
case VINDEXUP:
|
||||
luaK_codek(fs, key, v->u.ind.idx);
|
||||
luaK_codeABC(fs, OP_GETUPVAL, fs->freereg, v->u.ind.t, 0);
|
||||
v->u.ind.t = fs->freereg;
|
||||
luaK_reserveregs(fs, 1); /* one more register for the upvalue */
|
||||
break;
|
||||
default:
|
||||
luaK_semerror(fs->ls, "'undef' is not a value!!");
|
||||
break;
|
||||
}
|
||||
v->u.ind.idx = key;
|
||||
v->k = VINDEXED;
|
||||
}
|
||||
freeregs(fs, v->u.ind.t, v->u.ind.idx);
|
||||
}
|
||||
|
||||
|
||||
static void codeisdef (FuncState *fs, int eq, expdesc *v) {
|
||||
normalizeindexed(fs, v);
|
||||
v->u.info = luaK_codeABCk(fs, OP_ISDEF, 0, v->u.ind.t, v->u.ind.idx, eq);
|
||||
v->k = VRELOC;
|
||||
}
|
||||
|
||||
|
||||
void luaK_codeundef (FuncState *fs, expdesc *v) {
|
||||
normalizeindexed(fs, v);
|
||||
v->u.info = luaK_codeABC(fs, OP_UNDEF, v->u.ind.t, v->u.ind.idx, 0);
|
||||
v->k = VRELOC;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Apply prefix operation 'op' to expression 'e'.
|
||||
*/
|
||||
@ -1446,7 +1500,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||
break;
|
||||
}
|
||||
case OPR_EQ: case OPR_NE: {
|
||||
if (!tonumeral(v, NULL))
|
||||
if (!tonumeral(v, NULL) && fs->ls->t.token != TK_UNDEF)
|
||||
luaK_exp2RK(fs, v);
|
||||
/* else keep numeral, which may be an immediate operand */
|
||||
break;
|
||||
@ -1543,7 +1597,10 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
|
||||
break;
|
||||
}
|
||||
case OPR_EQ: case OPR_NE: {
|
||||
codeeq(fs, opr, e1, e2);
|
||||
if (e2->k == VUNDEF)
|
||||
codeisdef(fs, opr == OPR_NE, e1);
|
||||
else
|
||||
codeeq(fs, opr, e1, e2);
|
||||
break;
|
||||
}
|
||||
case OPR_LT: case OPR_LE: {
|
||||
|
4
lcode.h
4
lcode.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lcode.h,v 1.69 2017/11/30 13:29:18 roberto Exp roberto $
|
||||
** $Id: lcode.h,v 1.70 2017/12/18 15:44:44 roberto Exp roberto $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -89,6 +89,8 @@ LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
|
||||
expdesc *v2, int line);
|
||||
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
||||
LUAI_FUNC void luaK_finish (FuncState *fs);
|
||||
LUAI_FUNC void luaK_codeundef (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -78,6 +78,8 @@ static void *disptab[] = {
|
||||
&&L_OP_GEI,
|
||||
&&L_OP_TEST,
|
||||
&&L_OP_TESTSET,
|
||||
&&L_OP_UNDEF,
|
||||
&&L_OP_ISDEF,
|
||||
&&L_OP_CALL,
|
||||
&&L_OP_TAILCALL,
|
||||
&&L_OP_RETURN,
|
||||
|
4
llex.c
4
llex.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: llex.c,v 2.99 2018/01/28 15:13:26 roberto Exp roberto $
|
||||
** $Id: llex.c,v 2.100 2018/02/23 13:13:31 roberto Exp roberto $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -41,7 +41,7 @@ static const char *const luaX_tokens [] = {
|
||||
"and", "break", "do", "else", "elseif",
|
||||
"end", "false", "for", "function", "goto", "if",
|
||||
"in", "local", "nil", "not", "or", "repeat",
|
||||
"return", "then", "true", "until", "while",
|
||||
"return", "then", "true", "undef", "until", "while",
|
||||
"//", "..", "...", "==", ">=", "<=", "~=",
|
||||
"<<", ">>", "::", "<eof>",
|
||||
"<number>", "<integer>", "<name>", "<string>"
|
||||
|
4
llex.h
4
llex.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp roberto $
|
||||
** $Id: llex.h,v 1.80 2018/01/28 15:13:26 roberto Exp roberto $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -28,7 +28,7 @@ enum RESERVED {
|
||||
TK_AND = FIRST_RESERVED, TK_BREAK,
|
||||
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
||||
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
|
||||
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
||||
TK_RETURN, TK_THEN, TK_TRUE, TK_UNDEF, TK_UNTIL, TK_WHILE,
|
||||
/* other terminal symbols */
|
||||
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
|
||||
TK_SHL, TK_SHR,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lopcodes.c,v 1.78 2018/02/15 15:34:29 roberto Exp roberto $
|
||||
** $Id: lopcodes.c,v 1.79 2018/02/21 15:49:32 roberto Exp roberto $
|
||||
** Opcodes for Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -79,6 +79,8 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
|
||||
"GEI",
|
||||
"TEST",
|
||||
"TESTSET",
|
||||
"UNDEF",
|
||||
"ISDEF",
|
||||
"CALL",
|
||||
"TAILCALL",
|
||||
"RETURN",
|
||||
@ -162,6 +164,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
||||
,opmode(0, 0, 1, 0, iABC) /* OP_GEI */
|
||||
,opmode(0, 0, 1, 0, iABC) /* OP_TEST */
|
||||
,opmode(0, 0, 1, 1, iABC) /* OP_TESTSET */
|
||||
,opmode(0, 0, 0, 0, iABC) /* OP_UNDEF */
|
||||
,opmode(0, 0, 0, 1, iABC) /* OP_ISDEF */
|
||||
,opmode(1, 1, 0, 1, iABC) /* OP_CALL */
|
||||
,opmode(1, 1, 0, 1, iABC) /* OP_TAILCALL */
|
||||
,opmode(0, 1, 0, 0, iABC) /* OP_RETURN */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lopcodes.h,v 1.188 2018/02/15 15:34:29 roberto Exp roberto $
|
||||
** $Id: lopcodes.h,v 1.189 2018/02/21 15:49:32 roberto Exp roberto $
|
||||
** Opcodes for Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -266,6 +266,9 @@ OP_GEI,/* A sB if ((R(A) >= sB) ~= k) then pc++ */
|
||||
OP_TEST,/* A if (not R(A) == k) then pc++ */
|
||||
OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */
|
||||
|
||||
OP_UNDEF,/* A B R(A)[R(B)] = undef */
|
||||
OP_ISDEF,/* A B C R(A) = (R(B)[R(C)] == undef */
|
||||
|
||||
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||
|
||||
|
29
lparser.c
29
lparser.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lparser.c,v 2.177 2018/02/09 15:16:06 roberto Exp roberto $
|
||||
** $Id: lparser.c,v 2.178 2018/02/17 19:20:00 roberto Exp roberto $
|
||||
** Lua Parser
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -65,13 +65,6 @@ static void statement (LexState *ls);
|
||||
static void expr (LexState *ls, expdesc *v);
|
||||
|
||||
|
||||
/* semantic error */
|
||||
static l_noret semerror (LexState *ls, const char *msg) {
|
||||
ls->t.token = 0; /* remove "near <token>" from final message */
|
||||
luaX_syntaxerror(ls, msg);
|
||||
}
|
||||
|
||||
|
||||
static l_noret error_expected (LexState *ls, int token) {
|
||||
luaX_syntaxerror(ls,
|
||||
luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
|
||||
@ -347,7 +340,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
|
||||
const char *msg = luaO_pushfstring(ls->L,
|
||||
"<goto %s> at line %d jumps into the scope of local '%s'",
|
||||
getstr(gt->name), gt->line, getstr(vname));
|
||||
semerror(ls, msg);
|
||||
luaK_semerror(ls, msg);
|
||||
}
|
||||
luaK_patchgoto(fs, gt->pc, label->pc, 1);
|
||||
/* remove goto from pending list */
|
||||
@ -477,7 +470,7 @@ static void fixbreaks (FuncState *fs, BlockCnt *bl) {
|
||||
static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
|
||||
const char *msg = "no visible label '%s' for <goto> at line %d";
|
||||
msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
|
||||
semerror(ls, msg);
|
||||
luaK_semerror(ls, msg);
|
||||
}
|
||||
|
||||
|
||||
@ -900,6 +893,11 @@ static void primaryexp (LexState *ls, expdesc *v) {
|
||||
singlevar(ls, v);
|
||||
return;
|
||||
}
|
||||
case TK_UNDEF: {
|
||||
luaX_next(ls);
|
||||
init_exp(v, VUNDEF, 0);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
luaX_syntaxerror(ls, "unexpected symbol");
|
||||
}
|
||||
@ -1185,6 +1183,10 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
||||
else { /* assignment -> '=' explist */
|
||||
int nexps;
|
||||
checknext(ls, '=');
|
||||
if (nvars == 1 && testnext(ls, TK_UNDEF)) {
|
||||
luaK_codeundef(ls->fs, &lh->v);
|
||||
return;
|
||||
}
|
||||
nexps = explist(ls, &e);
|
||||
if (nexps != nvars)
|
||||
adjust_assign(ls, nvars, nexps, &e);
|
||||
@ -1237,7 +1239,7 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
|
||||
const char *msg = luaO_pushfstring(fs->ls->L,
|
||||
"label '%s' already defined on line %d",
|
||||
getstr(label), ll->arr[i].line);
|
||||
semerror(fs->ls, msg);
|
||||
luaK_semerror(fs->ls, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1650,6 +1652,11 @@ static void statement (LexState *ls) {
|
||||
luaX_next(ls); /* skip LOCAL */
|
||||
if (testnext(ls, TK_FUNCTION)) /* local function? */
|
||||
localfunc(ls);
|
||||
else if (testnext(ls, TK_UNDEF))
|
||||
(void)0; /* ignore */
|
||||
/* old versions may need to declare 'local undef'
|
||||
when using 'undef' with no environment; so this
|
||||
version accepts (and ignores) these declarations */
|
||||
else
|
||||
localstat(ls);
|
||||
break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lparser.h,v 1.79 2017/11/30 13:29:18 roberto Exp roberto $
|
||||
** $Id: lparser.h,v 1.80 2017/12/14 14:24:02 roberto Exp roberto $
|
||||
** Lua Parser
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -52,7 +52,8 @@ typedef enum {
|
||||
VRELOC, /* expression can put result in any register;
|
||||
info = instruction pc */
|
||||
VCALL, /* expression is a function call; info = instruction pc */
|
||||
VVARARG /* vararg expression; info = instruction pc */
|
||||
VVARARG, /* vararg expression; info = instruction pc */
|
||||
VUNDEF /* the 'undef' "expression" */
|
||||
} expkind;
|
||||
|
||||
|
||||
|
14
lvm.c
14
lvm.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lvm.c,v 2.348 2018/02/26 14:16:05 roberto Exp roberto $
|
||||
** $Id: lvm.c,v 2.349 2018/03/02 18:59:19 roberto Exp roberto $
|
||||
** Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -1552,6 +1552,18 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
}
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_UNDEF) {
|
||||
TValue *rb = vRB(i);
|
||||
luaT_keydef(L, vra, rb, 1);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_ISDEF) {
|
||||
TValue *rb = vRB(i);
|
||||
TValue *rc = vRC(i);
|
||||
int res = luaT_keydef(L, rb, rc, 0);
|
||||
setbvalue(vra, res == GETARG_k(i));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CALL) {
|
||||
int b = GETARG_B(i);
|
||||
int nresults = GETARG_C(i) - 1;
|
||||
|
Loading…
Reference in New Issue
Block a user