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 CgForInStat(FuncInfo fi, ForInStat node) { fi.EnterScope(true); CgLocalVarDeclStat(fi, new LocalVarDeclStat { NameList = new List <string> { "(for generator)", "(for state)", "(for control)" }, ExpList = node.ExpList }); foreach (var name in node.NameList) { fi.AddLocVar(name); } var pcJmpToTfc = fi.EmitJmp(0, 0); CgBlock(fi, node.Block); fi.CloseOpenUpvals(); fi.FixsBx(pcJmpToTfc, fi.PC() - pcJmpToTfc); var rGenerator = fi.SlotOfLocVar("(for generator)"); fi.EmitTForCall(rGenerator, node.NameList.Count); fi.EmitTForLoop(rGenerator + 2, pcJmpToTfc - fi.PC() - 1); fi.ExitScope(); }
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; }
private static void CgRetStat(FuncInfo fi, List <Exp> exps) { var nExps = exps.Count; if (nExps == 0) { fi.EmitReturn(0, 0); return; } if (nExps == 1) { if (exps[0] is NameExp nameExp) { var r = fi.SlotOfLocVar(nameExp.Name); if (r >= 0) { fi.EmitReturn(r, 1); return; } } if (exps[0] is FuncCallExp fcExp) { var r = fi.AllocReg(); CgTailCallExp(fi, fcExp, r); fi.FreeReg(); fi.EmitReturn(r, -1); return; } } var multRet = IsVarargOrFuncCall(exps[nExps - 1]); for (var i = 0; i < nExps; i++) { var exp = exps[i]; var r = fi.AllocReg(); if (i == nExps - 1 && multRet) { CgExp(fi, exp, r, -1); } else { CgExp(fi, exp, r, 1); } } fi.FreeRegs(nExps); var a = fi.UsedRegs; if (multRet) { fi.EmitReturn(a, -1); } else { fi.EmitReturn(a, nExps); } }