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 CgExp(FuncInfo fi, Exp node, int a, int n) { switch (node) { case NilExp _: fi.EmitLoadNil(a, n); break; case FalseExp _: fi.EmitLoadBool(a, 0, 0); break; case TrueExp _: fi.EmitLoadBool(a, 1, 0); break; case IntegerExp integerExp: fi.EmitLoadK(a, integerExp.Val); break; case FloatExp floatExp: fi.EmitLoadK(a, floatExp.Val); break; case StringExp stringExp: fi.EmitLoadK(a, stringExp.Str); break; case ParensExp parensExp: CgExp(fi, parensExp.Exp, a, 1); break; case VarargExp varargExp: CgVarargExp(fi, varargExp, a, n); break; case FuncDefExp funcDefExp: CgFuncDefExp(fi, funcDefExp, a); break; case TableConstructorExp tableConstructorExp: CgTableConstructorExp(fi, tableConstructorExp, a); break; case UnopExp unopExp: CgUnopExp(fi, unopExp, a); break; case BinopExp binopExp: CgBinopExp(fi, binopExp, a); break; case ConcatExp concatExp: CgConcatExp(fi, concatExp, a); break; case NameExp nameExp: CgNameExp(fi, nameExp, a); break; case TableAccessExp tableAccessExp: CgTableAccessExp(fi, tableAccessExp, a); break; case FuncCallExp funcCallExp: CgFuncCallExp(fi, funcCallExp, a, n); break; } }
private static void CgLocalVarDeclStat(FuncInfo fi, LocalVarDeclStat node) { var exps = RemoveTailNil(node.ExpList); var nExps = exps.Count; var nNames = node.NameList.Count; var oldRegs = fi.UsedRegs; if (nExps == nNames) { foreach (var exp in exps) { var a = fi.AllocReg(); CgExp(fi, exp, a, 1); } } else if (nExps > nNames) { for (var i = 0; i < exps.Count; i++) { var exp = exps[i]; var a = fi.AllocReg(); if (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 = nNames - nExps + 1; CgExp(fi, exp, a, n); fi.AllocRegs(n - 1); } else { CgExp(fi, exp, a, 1); } } if (!multRet) { var n = nNames - nExps; var a = fi.AllocRegs(n); fi.EmitLoadNil(a, n); } } fi.UsedRegs = oldRegs; foreach (var name in node.NameList) { fi.AddLocVar(name); } }