private static void assignment(LexState ls, LHS_assign lh, int nvars) { expdesc e = new expdesc(); check_condition(ls, expkind.VLOCAL <= lh.v.k && lh.v.k <= expkind.VINDEXED, "syntax error"); if (testnext(ls, ',') != 0) { /* assignment . `,' primaryexp assignment */ LHS_assign nv = new LHS_assign(); nv.prev = lh; primaryexp(ls, nv.v); if (nv.v.k == expkind.VLOCAL) check_conflict(ls, lh, nv.v); luaY_checklimit(ls.fs, nvars, Lua.LUAI_MAXCCALLS - ls.L.nCcalls, "variables in assignment"); assignment(ls, nv, nvars + 1); } else { /* assignment . `=' explist1 */ int nexps; checknext(ls, '='); nexps = explist1(ls, e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, e); if (nexps > nvars) ls.fs.freereg -= nexps - nvars; /* remove extra values */ } else { Lua.luaK_setoneret(ls.fs, e); /* close last expression */ Lua.luaK_storevar(ls.fs, lh.v, e); return; /* avoid default */ } } init_exp(e, expkind.VNONRELOC, ls.fs.freereg - 1); /* default assignment */ Lua.luaK_storevar(ls.fs, lh.v, e); }
private static void primaryexp(LexState ls, expdesc v) { /* primaryexp . prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ FuncState fs = ls.fs; prefixexp(ls, v); for (; ; ) { switch (ls.t.token) { case '.': { /* field */ field(ls, v); break; } case '[': { /* `[' exp1 `]' */ expdesc key = new expdesc(); Lua.luaK_exp2anyreg(fs, v); yindex(ls, key); Lua.luaK_indexed(fs, v, key); break; } case ':': { /* `:' NAME funcargs */ expdesc key = new expdesc(); Lua.luaX_next(ls); checkname(ls, key); Lua.luaK_self(fs, v, key); funcargs(ls, v); break; } case '(': case (int)RESERVED.TK_STRING: case '{': { /* funcargs */ Lua.luaK_exp2nextreg(fs, v); funcargs(ls, v); break; } default: return; } } }
public const int UNARY_PRIORITY = 8; /* priority for unary operators */ /* ** subexpr . (simpleexp | unop subexpr) { binop subexpr } ** where `binop' is any binary operator with a priority higher than `limit' */ private static BinOpr subexpr(LexState ls, expdesc v, uint limit) { BinOpr op = new BinOpr(); UnOpr uop = new UnOpr(); enterlevel(ls); uop = getunopr(ls.t.token); if (uop != UnOpr.OPR_NOUNOPR) { Lua.luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); Lua.luaK_prefix(ls.fs, uop, v); } else simpleexp(ls, v); /* expand while operators have priorities higher than `limit' */ op = getbinopr(ls.t.token); while (op != BinOpr.OPR_NOBINOPR && priority[(int)op].left > limit) { expdesc v2 = new expdesc(); BinOpr nextop; Lua.luaX_next(ls); Lua.luaK_infix(ls.fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, v2, priority[(int)op].right); Lua.luaK_posfix(ls.fs, op, v, v2); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ }
private static void body(LexState ls, expdesc e, int needself, int line) { /* body . `(' parlist `)' chunk END */ FuncState new_fs = new FuncState(); open_func(ls, new_fs); new_fs.f.linedefined = line; checknext(ls, '('); if (needself != 0) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); chunk(ls); new_fs.f.lastlinedefined = ls.linenumber; check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FUNCTION, line); close_func(ls); pushclosure(ls, new_fs, e); }
private static void funcargs(LexState ls, expdesc f) { FuncState fs = ls.fs; expdesc args = new expdesc(); int base_, nparams; int line = ls.linenumber; switch (ls.t.token) { case '(': { /* funcargs . `(' [ explist1 ] `)' */ if (line != ls.lastline) Lua.luaX_syntaxerror(ls, "ambiguous syntax (function call x new statement)"); Lua.luaX_next(ls); if (ls.t.token == ')') /* arg list is empty? */ args.k = expkind.VVOID; else { explist1(ls, args); Lua.luaK_setmultret(fs, args); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs . constructor */ constructor(ls, args); break; } case (int)RESERVED.TK_STRING: { /* funcargs . STRING */ codestring(ls, args, ls.t.seminfo.ts); Lua.luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { Lua.luaX_syntaxerror(ls, "function arguments expected"); return; } } Lua.lua_assert(f.k == expkind.VNONRELOC); base_ = f.u.s.info; /* base_ register for call */ if (hasmultret(args.k) != 0) nparams = Lua.LUA_MULTRET; /* open call */ else { if (args.k != expkind.VVOID) Lua.luaK_exp2nextreg(fs, args); /* close last argument */ nparams = fs.freereg - (base_ + 1); } init_exp(f, expkind.VCALL, Lua.luaK_codeABC(fs, OpCode.OP_CALL, base_, nparams + 1, 2)); Lua.luaK_fixline(fs, line); fs.freereg = base_ + 1; /* call remove function and arguments and leaves (unless changed) one result */ }
/*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ private static void field(LexState ls, expdesc v) { /* field . ['.' | ':'] NAME */ FuncState fs = ls.fs; expdesc key = new expdesc(); Lua.luaK_exp2anyreg(fs, v); Lua.luaX_next(ls); /* skip the dot or colon */ checkname(ls, key); Lua.luaK_indexed(fs, v, key); }
private static void recfield(LexState ls, ConsControl cc) { /* recfield . (NAME | `['exp1`]') = exp1 */ /* recfield -> FUNCTION funcname body */ FuncState fs = ls.fs; int reg = ls.fs.freereg; expdesc key = new expdesc(), val = new expdesc(); int rkkey; if (ls.t.token == (int)RESERVED.TK_NAME) { luaY_checklimit(fs, cc.nh, Lua.MAX_INT, "items in a constructor"); checkname(ls, key); } else /* ls.t.token == '[' */ yindex(ls, key); cc.nh++; checknext(ls, '='); rkkey = Lua.luaK_exp2RK(fs, key); expr(ls, val); Lua.luaK_codeABC(fs, OpCode.OP_SETTABLE, cc.t.u.s.info, rkkey, Lua.luaK_exp2RK(fs, val)); fs.freereg = reg; /* free registers */ }
private static void checkname(LexState ls, expdesc e) { codestring(ls, e, str_checkname(ls)); }
private static void localfunc(LexState ls) { expdesc v = new expdesc(), b = new expdesc(); FuncState fs = ls.fs; new_localvar(ls, str_checkname(ls), 0); init_exp(v, expkind.VLOCAL, fs.freereg); Lua.luaK_reserveregs(fs, 1); adjustlocalvars(ls, 1); body(ls, b, 0, ls.linenumber); Lua.luaK_storevar(fs, v, b); /* debug information will only see the variable after this point! */ getlocvar(fs, fs.nactvar - 1).startpc = fs.pc; }
private static void codestring(LexState ls, expdesc e, TString s) { init_exp(e, expkind.VK, Lua.luaK_stringK(ls.fs, s)); }
private static void forlist(LexState ls, TString indexname) { /* forlist . NAME {,NAME} IN explist1 forbody */ FuncState fs = ls.fs; expdesc e = new expdesc(); int nvars = 0; int line; int base_ = fs.freereg; /* create control variables */ new_localvarliteral(ls, "(for generator)", nvars++); new_localvarliteral(ls, "(for state)", nvars++); new_localvarliteral(ls, "(for control)", nvars++); /* create declared variables */ new_localvar(ls, indexname, nvars++); while (testnext(ls, ',') != 0) new_localvar(ls, str_checkname(ls), nvars++); checknext(ls, (int)RESERVED.TK_IN); line = ls.linenumber; adjust_assign(ls, 3, explist1(ls, e), e); Lua.luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base_, line, nvars - 3, 0); }
private static int exp1(LexState ls) { expdesc e = new expdesc(); int k; expr(ls, e); k = (int)e.k; Lua.luaK_exp2nextreg(ls.fs, e); return k; }
private static void init_exp(expdesc e, expkind k, int i) { e.f = e.t = Lua.NO_JUMP; e.k = k; e.u.s.info = i; }
private static int cond(LexState ls) { /* cond . exp */ expdesc v = new expdesc(); expr(ls, v); /* read condition */ if (v.k == expkind.VNIL) v.k = expkind.VFALSE; /* `falses' are all equal here */ Lua.luaK_goiftrue(ls.fs, v); return v.f; }
private static void adjust_assign(LexState ls, int nvars, int nexps, expdesc e) { FuncState fs = ls.fs; int extra = nvars - nexps; if (hasmultret(e.k) != 0) { extra++; /* includes call itself */ if (extra < 0) extra = 0; Lua.luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ if (extra > 1) Lua.luaK_reserveregs(fs, extra - 1); } else { if (e.k != expkind.VVOID) Lua.luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { int reg = fs.freereg; Lua.luaK_reserveregs(fs, extra); Lua.luaK_nil(fs, reg, extra); } } }
private static void localstat(LexState ls) { /* stat . LOCAL NAME {`,' NAME} [`=' explist1] */ int nvars = 0; int nexps; expdesc e = new expdesc(); do { new_localvar(ls, str_checkname(ls), nvars++); } while (testnext(ls, ',') != 0); if (testnext(ls, '=') != 0) nexps = explist1(ls, e); else { e.k = expkind.VVOID; nexps = 0; } adjust_assign(ls, nvars, nexps, e); adjustlocalvars(ls, nvars); }
private static void pushclosure(LexState ls, FuncState func, expdesc v) { FuncState fs = ls.fs; Proto f = fs.f; int oldsize = f.sizep; int i; Lua.luaM_growvector(ls.L, ref f.p, fs.np, ref f.sizep, Lua.MAXARG_Bx, "constant table overflow"); while (oldsize < f.sizep) f.p[oldsize++] = null; f.p[fs.np++] = func.f; Lua.luaC_objbarrier(ls.L, f, func.f); init_exp(v, expkind.VRELOCABLE, Lua.luaK_codeABx(fs, OpCode.OP_CLOSURE, 0, fs.np - 1)); for (i = 0; i < func.f.nups; i++) { OpCode o = ((int)func.upvalues[i].k == (int)expkind.VLOCAL) ? OpCode.OP_MOVE : OpCode.OP_GETUPVAL; Lua.luaK_codeABC(fs, o, 0, func.upvalues[i].info, 0); } }
private static int funcname(LexState ls, expdesc v) { /* funcname . NAME {field} [`:' NAME] */ int needself = 0; singlevar(ls, v); while (ls.t.token == '.') field(ls, v); if (ls.t.token == ':') { needself = 1; field(ls, v); } return needself; }
private static void yindex(LexState ls, expdesc v) { /* index . '[' expr ']' */ //luaX_next(ls); /* skip the '[' */ //expr(ls, v); //luaK_exp2val(ls.fs, v); //checknext(ls, ']'); Lua.luaX_next(ls); /* skip the '[' */ do { expr(ls, v); Lua.luaK_exp2val(ls.fs, v); //yindex(ls, key); //luaK_indexed(ls.fs, v, key); } while (testnext(ls, ',') == 1); checknext(ls, ']'); }
private static void funcstat(LexState ls, int line) { /* funcstat . FUNCTION funcname body */ int needself; expdesc v = new expdesc(), b = new expdesc(); Lua.luaX_next(ls); /* skip FUNCTION */ needself = funcname(ls, v); body(ls, b, needself, line); Lua.luaK_storevar(ls.fs, v, b); Lua.luaK_fixline(ls.fs, line); /* definition `happens' in the first line */ }
private static void constructor(LexState ls, expdesc t) { /* constructor . ?? */ FuncState fs = ls.fs; int line = ls.linenumber; int pc = Lua.luaK_codeABC(fs, OpCode.OP_NEWTABLE, 0, 0, 0); ConsControl cc = new ConsControl(); cc.na = cc.nh = cc.tostore = 0; cc.t = t; init_exp(t, expkind.VRELOCABLE, pc); init_exp(cc.v, expkind.VVOID, 0); /* no value (yet) */ Lua.luaK_exp2nextreg(ls.fs, t); /* fix it at stack top (for gc) */ checknext(ls, '{'); do { Lua.lua_assert(cc.v.k == expkind.VVOID || cc.tostore > 0); if (ls.t.token == '}') break; closelistfield(fs, cc); switch (ls.t.token) { case (int)RESERVED.TK_NAME: { /* may be listfields or recfields */ Lua.luaX_lookahead(ls); if (ls.lookahead.token != '=') /* expression? */ listfield(ls, cc); else recfield(ls, cc); break; } case '[': { /* constructor_item . recfield */ recfield(ls, cc); break; } default: { /* constructor_part . listfield */ listfield(ls, cc); break; } } } while ((testnext(ls, ',') != 0) || (testnext(ls, ';') != 0)); check_match(ls, '}', '{', line); lastlistfield(fs, cc); Lua.SETARG_B(new InstructionPtr(fs.f.code, pc), Lua.luaO_int2fb((uint)cc.na)); /* set initial array size */ Lua.SETARG_C(new InstructionPtr(fs.f.code, pc), Lua.luaO_int2fb((uint)cc.nh)); /* set initial table size */ }
private static void retstat(LexState ls) { /* stat . RETURN explist */ FuncState fs = ls.fs; expdesc e = new expdesc(); int first, nret; /* registers with returned values */ Lua.luaX_next(ls); /* skip RETURN */ if ((block_follow(ls.t.token) != 0) || ls.t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, e); /* optional return values */ if (hasmultret(e.k) != 0) { Lua.luaK_setmultret(fs, e); if (e.k == expkind.VCALL && nret == 1) { /* tail call? */ Lua.SET_OPCODE(Lua.getcode(fs, e), OpCode.OP_TAILCALL); Lua.lua_assert(Lua.GETARG_A(Lua.getcode(fs, e)) == fs.nactvar); } first = fs.nactvar; nret = Lua.LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = Lua.luaK_exp2anyreg(fs, e); else { Lua.luaK_exp2nextreg(fs, e); /* values must go to the `stack' */ first = fs.nactvar; /* return all `active' values */ Lua.lua_assert(nret == fs.freereg - first); } } } Lua.luaK_ret(fs, first, nret); }
private static int explist1(LexState ls, expdesc v) { /* explist1 . expr { `,' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',') != 0) { Lua.luaK_exp2nextreg(ls.fs, v); expr(ls, v); n++; } return n; }
private static int indexupvalue(FuncState fs, TString name, expdesc v) { int i; Proto f = fs.f; int oldsize = f.sizeupvalues; for (i = 0; i < f.nups; i++) { if ((int)fs.upvalues[i].k == (int)v.k && fs.upvalues[i].info == v.u.s.info) { Lua.lua_assert(f.upvalues[i] == name); return i; } } /* new one */ luaY_checklimit(fs, f.nups + 1, Lua.LUAI_MAXUPVALUES, "upvalues"); Lua.luaM_growvector(fs.L, ref f.upvalues, f.nups, ref f.sizeupvalues, Lua.MAX_INT, ""); while (oldsize < f.sizeupvalues) f.upvalues[oldsize++] = null; f.upvalues[f.nups] = name; Lua.luaC_objbarrier(fs.L, f, name); Lua.lua_assert(v.k == expkind.VLOCAL || v.k == expkind.VUPVAL); fs.upvalues[f.nups].k = Lua.cast_byte(v.k); fs.upvalues[f.nups].info = Lua.cast_byte(v.u.s.info); return f.nups++; }
/* ** {====================================================================== ** Expression parsing ** ======================================================================= */ private static void prefixexp(LexState ls, expdesc v) { /* prefixexp . NAME | '(' expr ')' */ switch (ls.t.token) { case '(': { int line = ls.linenumber; Lua.luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); Lua.luaK_dischargevars(ls.fs, v); return; } case (int)RESERVED.TK_NAME: { singlevar(ls, v); return; } default: { Lua.luaX_syntaxerror(ls, "unexpected symbol"); return; } } }
private static expkind singlevaraux(FuncState fs, TString n, expdesc var, int base_) { if (fs == null) { /* no more levels? */ init_exp(var, expkind.VGLOBAL, Lua.NO_REG); /* default is global variable */ return expkind.VGLOBAL; } else { int v = searchvar(fs, n); /* look up at current level */ if (v >= 0) { init_exp(var, expkind.VLOCAL, v); if (base_ == 0) markupval(fs, v); /* local will be used as an upval */ return expkind.VLOCAL; } else { /* not found at current level; try upper one */ if (singlevaraux(fs.prev, n, var, 0) == expkind.VGLOBAL) return expkind.VGLOBAL; var.u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ var.k = expkind.VUPVAL; /* upvalue in this level */ return expkind.VUPVAL; } } }
private static void simpleexp(LexState ls, expdesc v) { /* simpleexp . NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp */ switch (ls.t.token) { case (int)RESERVED.TK_NUMBER: { init_exp(v, expkind.VKNUM, 0); v.u.nval = ls.t.seminfo.r; break; } case (int)RESERVED.TK_STRING: { codestring(ls, v, ls.t.seminfo.ts); break; } case (int)RESERVED.TK_NIL: { init_exp(v, expkind.VNIL, 0); break; } case (int)RESERVED.TK_TRUE: { init_exp(v, expkind.VTRUE, 0); break; } case (int)RESERVED.TK_FALSE: { init_exp(v, expkind.VFALSE, 0); break; } case (int)RESERVED.TK_DOTS: { /* vararg */ FuncState fs = ls.fs; check_condition(ls, fs.f.is_vararg != 0, "cannot use " + Lua.LUA_QL("...") + " outside a vararg function"); fs.f.is_vararg &= unchecked((lu_byte)(~Lua.VARARG_NEEDSARG)); /* don't need 'arg' */ init_exp(v, expkind.VVARARG, Lua.luaK_codeABC(fs, OpCode.OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case (int)RESERVED.TK_FUNCTION: { Lua.luaX_next(ls); body(ls, v, 0, ls.linenumber); return; } default: { primaryexp(ls, v); return; } } Lua.luaX_next(ls); }
private static void singlevar(LexState ls, expdesc var) { TString varname = str_checkname(ls); FuncState fs = ls.fs; if (singlevaraux(fs, varname, var, 1) == expkind.VGLOBAL) var.u.s.info = Lua.luaK_stringK(fs, varname); /* info points to global name */ }
private static void expr(LexState ls, expdesc v) { subexpr(ls, v, 0); }
/* ** check whether, in an assignment to a local variable, the local variable ** is needed in a previous assignment (to a table). If so, save original ** local value in a safe place and use this safe copy in the previous ** assignment. */ private static void check_conflict(LexState ls, LHS_assign lh, expdesc v) { FuncState fs = ls.fs; int extra = fs.freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh != null; lh = lh.prev) { if (lh.v.k == expkind.VINDEXED) { if (lh.v.u.s.info == v.u.s.info) { /* conflict? */ conflict = 1; lh.v.u.s.info = extra; /* previous assignment will use safe copy */ } if (lh.v.u.s.aux == v.u.s.info) { /* conflict? */ conflict = 1; lh.v.u.s.aux = extra; /* previous assignment will use safe copy */ } } } if (conflict != 0) { Lua.luaK_codeABC(fs, OpCode.OP_MOVE, fs.freereg, v.u.s.info, 0); /* make copy */ Lua.luaK_reserveregs(fs, 1); } }