new experimental syntax using reserved word 'undef'
diff --git a/lbaselib.c b/lbaselib.c
index 477d44d..12a9e88 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_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 @@
   {"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 8f3c68c..95e87f3 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 <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 @@
       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 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 @@
       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 @@
       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 beeba54..e7c294d 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 @@
                             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 ac6a035..f9783ff 100644
--- a/ljumptab.h
+++ b/ljumptab.h
@@ -78,6 +78,8 @@
 &&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 5d5efb0..7e59eb4 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 @@
     "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>"
diff --git a/llex.h b/llex.h
index 9f23bd8..fb33c33 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 @@
   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 79d77cc..ac59537 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 @@
   "GEI",
   "TEST",
   "TESTSET",
+  "UNDEF",
+  "ISDEF",
   "CALL",
   "TAILCALL",
   "RETURN",
@@ -162,6 +164,8 @@
  ,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 be7359e..ddbaf8d 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_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 da27c47..9bf5485 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 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 @@
     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 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 @@
       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 @@
   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 @@
       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 @@
       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 6007d61..b8705e8 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 @@
   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 891e7d8..b3abbf1 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 @@
         }
         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;