private static void CgNameExp(FuncInfo fi, NameExp node, int a) { var r = fi.SlotOfLocVar(node.Name); if (r >= 0) { fi.EmitMove(a, r); } else { var idx = fi.IndexOfUpval(node.Name); if (idx >= 0) { fi.EmitGetUpval(a, idx); } else { var taExp = new TableAccessExp { PrefixExp = new NameExp { Line = 0, Name = "_ENV" }, KeyExp = new StringExp { Line = 0, Str = node.Name } }; CgTableAccessExp(fi, taExp, a); } } }
private static void CgBinopExp(FuncInfo fi, BinopExp node, int a) { switch (node.Op) { case ETokenType.OpAnd: case ETokenType.OpOr: { var b = fi.AllocReg(); CgExp(fi, node.Exp1, b, 1); fi.FreeReg(); if (node.Op == ETokenType.OpAnd) { fi.EmitTestSet(a, b, 0); } else { fi.EmitTestSet(a, b, 1); } var pcOfJmp = fi.EmitJmp(0, 0); b = fi.AllocReg(); CgExp(fi, node.Exp2, b, 1); fi.FreeReg(); fi.EmitMove(a, b); fi.FixsBx(pcOfJmp, fi.PC() - pcOfJmp); break; } default: { var b = fi.AllocReg(); CgExp(fi, node.Exp1, b, 1); var c = fi.AllocReg(); CgExp(fi, node.Exp2, c, 1); fi.EmitBinaryOp(node.Op, a, b, c); fi.FreeRegs(2); break; } } }
private static void CgAssignStat(FuncInfo fi, AssignStat node) { var exps = RemoveTailNil(node.ExpList); var nExps = exps.Count; var nVars = node.VarList.Count; var tRegs = new int[nVars]; var kRegs = new int[nVars]; var vRegs = new int[nVars]; var oldRegs = fi.UsedRegs; for (var i = 0; i < node.VarList.Count; i++) { var exp = node.VarList[i]; if (exp is TableAccessExp tableAccessExp) { tRegs[i] = fi.AllocReg(); CgExp(fi, tableAccessExp.PrefixExp, tRegs[i], 1); kRegs[i] = fi.AllocReg(); CgExp(fi, tableAccessExp.KeyExp, kRegs[i], 1); } else if (exp is NameExp nameExp) { var name = nameExp.Name; if (fi.SlotOfLocVar(name) < 0 && fi.IndexOfUpval(name) < 0) { kRegs[i] = -1; fi.IndexOfConstant(name, out var constIdx); if (constIdx > 0xff) { kRegs[i] = fi.AllocReg(); } } } } for (var i = 0; i < nVars; i++) { vRegs[i] = fi.UsedRegs + i; } if (nExps >= nVars) { for (var i = 0; i < exps.Count; i++) { var exp = exps[i]; var a = fi.AllocReg(); if (i >= nVars && i == nExps - 1 && IsVarargOrFuncCall(exp)) { CgExp(fi, exp, a, 0); } else { CgExp(fi, exp, a, 1); } } } else { var multRet = false; for (var i = 0; i < exps.Count; i++) { var exp = exps[i]; var a = fi.AllocReg(); if (i == nExps - 1 && IsVarargOrFuncCall(exp)) { multRet = true; var n = nVars - nExps + 1; CgExp(fi, exp, a, n); fi.AllocRegs(n - 1); } else { CgExp(fi, exp, a, 1); } } if (!multRet) { var n = nVars - nExps; var a = fi.AllocRegs(n); fi.EmitLoadNil(a, n); } } for (var i = 0; i < node.VarList.Count; i++) { var exp = node.VarList[i]; if (exp is NameExp nameExp) { var varName = nameExp.Name; var a = fi.SlotOfLocVar(varName); if (a >= 0) { fi.EmitMove(a, vRegs[i]); } else { var b = fi.IndexOfUpval(varName); if (b >= 0) { fi.EmitSetUpval(vRegs[i], b); } else { a = fi.SlotOfLocVar("_ENV"); if (a >= 0) { if (kRegs[i] < 0) { fi.IndexOfConstant(varName, out var constIdx); b = 0x100 + constIdx; fi.EmitSetTable(a, b, vRegs[i]); } else { fi.EmitSetTable(a, kRegs[i], vRegs[i]); } } else { a = fi.IndexOfUpval("_ENV"); if (kRegs[i] < 0) { fi.IndexOfConstant(varName, out var idx); b = 0x100 + idx; fi.EmitSetTabUp(a, b, vRegs[i]); } else { fi.EmitSetTable(a, kRegs[i], vRegs[i]); } } } } } else { fi.EmitSetTable(tRegs[i], kRegs[i], vRegs[i]); } } fi.UsedRegs = oldRegs; }