private static void CgTableConstructorExp(FuncInfo fi, TableConstructorExp node, int a) { var nArr = node.KeyExps?.Count(exp => exp is null) ?? 0; var nExps = node.KeyExps?.Count ?? 0; var multRet = nExps > 0 && IsVarargOrFuncCall(node.ValExps[nExps - 1]); fi.EmitNewTable(a, nArr, nExps - nArr); var arrIdx = 0; for (var i = 0; i < nExps; i++) { var keyExp = node.KeyExps[i]; var valExp = node.ValExps[i]; if (keyExp == null) { arrIdx++; var tmp = fi.AllocReg(); if (i == nExps - 1 && multRet) { CgExp(fi, valExp, tmp, -1); } else { CgExp(fi, valExp, tmp, 1); } if (arrIdx % 50 == 0 || arrIdx == nArr) { var n = arrIdx % 50; if (n == 0) { n = 50; } fi.FreeRegs(n); var c = (arrIdx - 1) / 50 + 1; if (i == nExps - 1 && multRet) { fi.EmitSetList(a, 0, c); } else { fi.EmitSetList(a, n, c); } } continue; } var b = fi.AllocReg(); CgExp(fi, keyExp, b, 1); var d = fi.AllocReg(); CgExp(fi, valExp, d, 1); fi.FreeRegs(2); fi.EmitSetTable(a, b, d); } }
private static void CgTableAccessExp(FuncInfo fi, TableAccessExp node, int a) { var b = fi.AllocReg(); CgExp(fi, node.PrefixExp, b, 1); var c = fi.AllocReg(); CgExp(fi, node.KeyExp, c, 1); fi.EmitGetTable(a, b, c); fi.FreeRegs(2); }
private static void CgConcatExp(FuncInfo fi, ConcatExp node, int a) { foreach (var subExp in node.Exps) { var tmp = fi.AllocReg(); CgExp(fi, subExp, tmp, 1); } var c = fi.UsedRegs - 1; var b = c - node.Exps.Count + 1; fi.FreeRegs(c - b + 1); fi.EmitABC(EOpCode.OP_CONCAT, a, b, c); }
private static int PrepFuncCall(FuncInfo fi, FuncCallExp node, int a) { var nArgs = node.Args?.Count ?? 0; var lastArgIsVarargsOrFuncCall = false; CgExp(fi, node.PrefixExp, a, 1); if (node.NameExp != null) { fi.IndexOfConstant(node.NameExp.Str, out var idx); var c = 0x100 + idx; fi.EmitSelf(a, a, c); } for (var i = 0; i < nArgs; i++) { var arg = node.Args[i]; var tmp = fi.AllocReg(); if (i == nArgs - 1 && IsVarargOrFuncCall(arg)) { lastArgIsVarargsOrFuncCall = true; CgExp(fi, arg, tmp, -1); } else { CgExp(fi, arg, tmp, 1); } } fi.FreeRegs(nArgs); if (node.NameExp != null) { nArgs++; } if (lastArgIsVarargsOrFuncCall) { nArgs = -1; } return(nArgs); }
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 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); } }