From 4a1612ff9b968fe446bc4dd20460bfaccabeb3b3 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 7 Mar 2018 12:55:38 -0300 Subject: [PATCH] new experimental syntax using reserved word 'undef' --- lbaselib.c | 20 +---------------- lcode.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++--- lcode.h | 4 +++- ljumptab.h | 2 ++ llex.c | 4 ++-- llex.h | 4 ++-- lopcodes.c | 6 +++++- lopcodes.h | 5 ++++- lparser.c | 29 +++++++++++++++---------- lparser.h | 5 +++-- lvm.c | 14 +++++++++++- 11 files changed, 113 insertions(+), 43 deletions(-) diff --git a/lbaselib.c b/lbaselib.c index 477d44d2..12a9e888 100644 --- a/lbaselib.c +++ b/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}, diff --git a/lcode.c b/lcode.c index 8f3c68c0..95e87f31 100644 --- a/lcode.c +++ b/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 " 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: { diff --git a/lcode.h b/lcode.h index beeba54f..e7c294d4 100644 --- a/lcode.h +++ b/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 diff --git a/ljumptab.h b/ljumptab.h index ac6a0357..f9783ffb 100644 --- a/ljumptab.h +++ b/ljumptab.h @@ -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, diff --git a/llex.c b/llex.c index 5d5efb07..7e59eb49 100644 --- a/llex.c +++ b/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", "//", "..", "...", "==", ">=", "<=", "~=", "<<", ">>", "::", "", "", "", "", "" diff --git a/llex.h b/llex.h index 9f23bd89..fb33c33f 100644 --- a/llex.h +++ b/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, diff --git a/lopcodes.c b/lopcodes.c index 79d77cc1..ac59537b 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -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 */ diff --git a/lopcodes.h b/lopcodes.h index be7359e9..ddbaf8da 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -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)) */ diff --git a/lparser.c b/lparser.c index da27c472..9bf5485e 100644 --- a/lparser.c +++ b/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 " 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, " 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 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; diff --git a/lparser.h b/lparser.h index 6007d618..b8705e84 100644 --- a/lparser.h +++ b/lparser.h @@ -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; diff --git a/lvm.c b/lvm.c index 891e7d8d..b3abbf13 100644 --- a/lvm.c +++ b/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;