private static void anchor_token(LexState ls) { if (ls.t.token == (int)RESERVED.TK_NAME || ls.t.token == (int)RESERVED.TK_STRING) { TString ts = ls.t.seminfo.ts; Lua.luaX_newstring(ls, Lua.getstr(ts), ts.tsv.len); } }
private static int testnext(LexState ls, int c) { if (ls.t.token == c) { Lua.luaX_next(ls); return 1; } else return 0; }
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 expr(LexState ls, expdesc v) { subexpr(ls, v, 0); }
private static void check_match(LexState ls, int what, int who, int where) { if (testnext(ls, what) == 0) { if (where == ls.linenumber) error_expected(ls, what); else { Lua.luaX_syntaxerror(ls, Lua.luaO_pushfstring(ls.L, Lua.LUA_QS + " expected (to close " + Lua.LUA_QS + " at line %d)", Lua.luaX_token2str(ls, what), Lua.luaX_token2str(ls, who), where)); } } }
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 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; } } }
private static void check(LexState ls, int c) { if (ls.t.token != c) error_expected(ls, c); }
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; }
public static Proto luaY_parser(LuaState L, ZIO z, Mbuffer buff, CharPtr name) { LexState lexstate = new LexState(); FuncState funcstate = new FuncState(); lexstate.buff = buff; Lua.luaX_setinput(L, lexstate, z, Lua.luaS_new(L, name)); open_func(lexstate, funcstate); funcstate.f.is_vararg = Lua.VARARG_ISVARARG; /* main func. is always vararg */ Lua.luaX_next(lexstate); /* read first token */ System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; chunk(lexstate); check(lexstate, (int)RESERVED.TK_EOS); close_func(lexstate); Lua.lua_assert(funcstate.prev == null); Lua.lua_assert(funcstate.f.nups == 0); Lua.lua_assert(lexstate.fs == null); return funcstate.f; }
private static void close_func(LexState ls) { LuaState L = ls.L; FuncState fs = ls.fs; Proto f = fs.f; removevars(ls, 0); Lua.luaK_ret(fs, 0, 0); /* final return */ Lua.luaM_reallocvector(L, ref f.code, f.sizecode, fs.pc/*, typeof(Instruction)*/); f.sizecode = fs.pc; Lua.luaM_reallocvector(L, ref f.lineinfo, f.sizelineinfo, fs.pc/*, typeof(int)*/); f.sizelineinfo = fs.pc; Lua.luaM_reallocvector(L, ref f.k, f.sizek, fs.nk/*, TValue*/); f.sizek = fs.nk; Lua.luaM_reallocvector(L, ref f.p, f.sizep, fs.np/*, Proto*/); f.sizep = fs.np; for (int i = 0; i < f.p.Length; i++) { f.p[i].protos = f.p; f.p[i].index = i; } Lua.luaM_reallocvector(L, ref f.locvars, f.sizelocvars, fs.nlocvars/*, LocVar*/); f.sizelocvars = fs.nlocvars; Lua.luaM_reallocvector(L, ref f.upvalues, f.sizeupvalues, f.nups/*, TString*/); f.sizeupvalues = f.nups; Lua.lua_assert(Lua.luaG_checkcode(f)); Lua.lua_assert(fs.bl == null); ls.fs = fs.prev; /* last token read was anchored in defunct function; must reanchor it */ if (fs != null) anchor_token(ls); L.top -= 2; /* remove table and prototype from the stack */ }
private static void open_func(LexState ls, FuncState fs) { LuaState L = ls.L; Proto f = Lua.luaF_newproto(L); fs.f = f; fs.prev = ls.fs; /* linked list of funcstates */ fs.ls = ls; fs.L = L; ls.fs = fs; fs.pc = 0; fs.lasttarget = -1; fs.jpc = Lua.NO_JUMP; fs.freereg = 0; fs.nk = 0; fs.np = 0; fs.nlocvars = 0; fs.nactvar = 0; fs.bl = null; f.source = ls.source; f.maxstacksize = 2; /* registers 0/1 are always valid */ fs.h = Lua.luaH_new(L, 0, 0); /* anchor table of constants and prototype (to avoid being collected) */ Lua.sethvalue2s(L, L.top, fs.h); Lua.incr_top(L); Lua.setptvalue2s(L, L.top, f); Lua.incr_top(L); }
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 void leavelevel(LexState ls) { ls.L.nCcalls--; }
private static void enterlevel(LexState ls) { if (++ls.L.nCcalls > Lua.LUAI_MAXCCALLS) Lua.luaX_lexerror(ls, "chunk has too many syntax levels", 0); }
/*============================================================*/ /* 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 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 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 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 */ }
private static void error_expected(LexState ls, int token) { Lua.luaX_syntaxerror(ls, Lua.luaO_pushfstring(ls.L, Lua.LUA_QS + " expected", Lua.luaX_token2str(ls, token))); }
/* ** {====================================================================== ** 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 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 checknext(LexState ls, int c) { check(ls, c); Lua.luaX_next(ls); }
private static void listfield(LexState ls, ConsControl cc) { expr(ls, cc.v); luaY_checklimit(ls.fs, cc.na, Lua.MAX_INT, "items in a constructor"); cc.na++; cc.tostore++; }
public static void check_condition(LexState ls, bool c, CharPtr msg) { if (!(c)) Lua.luaX_syntaxerror(ls, msg); }
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 */ }
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 parlist(LexState ls) { /* parlist . [ param { `,' param } ] */ FuncState fs = ls.fs; Proto f = fs.f; int nparams = 0; f.is_vararg = 0; #if IMPLICIT_VARARG bool wasvararg = false; // if the parlist contains a '...' #endif if (ls.t.token != ')') { /* is `parlist' not empty? */ do { switch (ls.t.token) { case (int)RESERVED.TK_NAME: { /* param . NAME */ new_localvar(ls, str_checkname(ls), nparams++); break; } case (int)RESERVED.TK_DOTS: { /* param . `...' */ #if IMPLICIT_VARARG wasvararg = true; #endif Lua.luaX_next(ls); #if LUA_COMPAT_VARARG /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); f.is_vararg = Lua.VARARG_HASARG | Lua.VARARG_NEEDSARG; #endif f.is_vararg |= Lua.VARARG_ISVARARG; break; } default: Lua.luaX_syntaxerror(ls, "<name> or " + Lua.LUA_QL("...") + " expected"); break; } } while ((f.is_vararg == 0) && (testnext(ls, ',') != 0)); } #if IMPLICIT_VARARG if (wasvararg == false) { #if LUA_COMPAT_VARARG /* use `arg' as default name */ new_localvarliteral(ls, "arg", nparams++); f.is_vararg = Lua.VARARG_HASARG | Lua.VARARG_NEEDSARG; #else f.is_vararg = 0; #endif f.is_vararg |= Lua.VARARG_ISVARARG; } #endif adjustlocalvars(ls, nparams); f.numparams = Lua.cast_byte(fs.nactvar - (f.is_vararg & Lua.VARARG_HASARG)); Lua.luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */ }
private static void block(LexState ls) { /* block . chunk */ FuncState fs = ls.fs; BlockCnt bl = new BlockCnt(); enterblock(fs, bl, 0); chunk(ls); Lua.lua_assert(bl.breaklist == Lua.NO_JUMP); leaveblock(fs); }
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 */ }