public bool Match(XMLLuaSearchGenericFor req, GenericFor real) { Logger.Debug($"generic_for"); if (!Match(req.Block, real.Block)) { return(false); } if (req.Expressions.Count != real.Expressions.Count) { return(false); } if (req.Variables.Count != real.Variables.Count) { return(false); } for (var i = 0; i < req.Expressions.Count; i++) { if (!Match(req.Expressions[i], real.Expressions[i])) { return(false); } } for (var i = 0; i < req.Variables.Count; i++) { if (req.Variables[i] != real.Variables[i]) { return(false); } } SetSelectionIfSelected(real.Span, req); return(true); }
public async Task ExecuteGenericFor(GenericFor forStat, LuaState state, CancellationToken token) { var forState = state.WithNewContext(); var varNames = forStat.Variables.Select(LuaObject.FromString).ToArray(); var expressions = await _engine.EvaluateExpression(forStat.Expressions, state, token); var func = expressions[0]; var table = expressions[1]; var args = Lua.Args(expressions.Skip(1)); while (true) { var result = await func.CallAsync(state.Engine, args, token); if (result[0].IsNil()) { break; } for (var i = 0; i < varNames.Length; i++) { forState.Context.NewIndexRaw(varNames[i], result[i]); } await _engine.ExecuteStatement(forStat.Block, forState, token); args = Lua.Args(new[] { table }.Concat(result)); } }
static LuaArguments EvalGenericFor(GenericFor stat, LuaContext Context, out LuaReturnStatus returned) { returned.broke = false; returned.returned = false; LuaArguments args = null; foreach (IExpression expr in stat.Expressions) { if (args == null) { args = EvalExpression(expr, Context); } else { args.Concat(EvalExpression(expr, Context)); } } LuaObject f = args[0], s = args[1], var = args[2]; LuaContext ctx = new LuaContext(Context); while (true) { LuaArguments res = f.Call(s, var); for (int i = 0; i < stat.Variables.Count; i++) { ctx.SetLocal(stat.Variables[i], res[i]); } if (res[0].IsNil) { break; } var = res[0]; LuaArguments obj = EvalBlock(stat.Block, ctx, out returned); if (returned.broke) { break; } if (returned.returned) { return(obj); } } return(Lua.Return()); }
public void Visit(GenericFor node) { VisitLuaFunction(node); }
public void Analyze(Function f) { // Traverse all the nodes in post-order and try to convert jumps to if statements var usedFollows = new HashSet <BasicBlock>(); // Heads of for statements var forHeads = new HashSet <BasicBlock>(); var relocalize = new HashSet <Identifier>(); // Order the blocks sequentially for (int i = 0; i < f.Blocks.Count; i++) { f.Blocks[i].OrderNumber = i; } // Step 1: build the AST for ifs/loops based on follow information foreach (var node in f.PostorderTraversal(true)) { // Search instructions for identifiers we need to relocalize foreach (var inst in node.Instructions) { if (inst is Assignment asn) { foreach (var def in inst.GetDefines(true)) { if (relocalize.Contains(def)) { asn.IsLocalDeclaration = true; relocalize.Remove(def); } } } } // A for loop is a pretested loop where the follow does not match the head if (node.LoopFollow != null && node.LoopFollow != node && node.Predecessors.Count() >= 2 && node.LoopType == LoopType.LoopPretested) { var loopInitializer = node.Predecessors.First(x => !node.LoopLatches.Contains(x)); // Match a numeric for if (node.Instructions.Last() is Jump loopJump && loopJump.Condition is BinOp loopCondition && loopCondition.OperationType == BinOperationType.OpLoopCompare && node.Instructions[^ 2] is Assignment aaa3 && aaa3.Right != null && aaa3.Right is BinOp) { var nfor = new NumericFor(); nfor.Limit = loopCondition.Right; Identifier loopvar = (loopCondition.Left as IdentifierReference).Identifier; var incinst = node.Instructions[node.Instructions.Count() - 2]; nfor.Increment = ((incinst as Assignment).Right as BinOp).Right; // Search the predecessor block for the initial assignments (i.e. the definition) /*for (int i = loopInitializer.Instructions.Count() - 1; i >= 0; i--) * { * if (loopInitializer.Instructions[i] is Assignment a && a.GetDefines(true).Contains(loopvar)) * { * nfor.Initial = a; * //if (!lua51) * loopInitializer.Instructions.RemoveAt(i); * break; * } * }*/ // Extract the step variable definition if (loopInitializer.Instructions.Count > 2 && loopInitializer.Instructions[^ 2] is Assignment incassn) { nfor.Increment = incassn.Right; if (incassn.IsLocalDeclaration) { relocalize.Add(incassn.Left[0].Identifier); } loopInitializer.Instructions.RemoveAt(loopInitializer.Instructions.Count - 2); } // Extract the limit variable definition if (loopInitializer.Instructions.Count > 2 && loopInitializer.Instructions[^ 2] is Assignment limitassn) { nfor.Limit = limitassn.Right; if (limitassn.IsLocalDeclaration) { relocalize.Add(limitassn.Left[0].Identifier); } loopInitializer.Instructions.RemoveAt(loopInitializer.Instructions.Count - 2); } // Extract the initializer variable definition if (loopInitializer.Instructions.Count > 1 && loopInitializer.Instructions[loopInitializer.Instructions.Count - 2] is Assignment initassn) { nfor.Initial = initassn; if (initassn.IsLocalDeclaration) { relocalize.Add(initassn.Left[0].Identifier); } loopInitializer.Instructions.RemoveAt(loopInitializer.Instructions.Count - 2); } nfor.Body = node.Successors[1]; nfor.Body.MarkCodegenerated(f.Id); if (!usedFollows.Contains(node.LoopFollow)) { nfor.Follow = node.LoopFollow; usedFollows.Add(node.LoopFollow); node.LoopFollow.MarkCodegenerated(f.Id); } if (loopInitializer.Instructions.Any() && loopInitializer.Instructions[loopInitializer.Instructions.Count() - 1] is Jump) { loopInitializer.Instructions[loopInitializer.Instructions.Count() - 1] = nfor; } else { loopInitializer.Instructions.Add(nfor); } node.MarkCodegenerated(f.Id); // The head might be the follow of an if statement, so do this to not codegen it usedFollows.Add(node); // Remove any jump instructions from the latches if they exist foreach (var latch in node.LoopLatches) { if (latch.Instructions.Count > 0 && latch.Instructions.Last() is Jump jmp2 && !jmp2.Conditional && jmp2.BlockDest == node) { latch.Instructions.RemoveAt(latch.Instructions.Count - 1); } } } // Match a generic for with a predecessor initializer else if (node.Instructions.Count > 0 && node.Instructions.Last() is Jump loopJump2 && loopJump2.Condition is BinOp loopCondition2 && loopInitializer.Instructions.Count >= 2 && loopInitializer.Instructions[loopInitializer.Instructions.Count - 2] is Assignment la && la.Left.Any() && la.Left[0] is IdentifierReference f1 && node.Instructions[0] is Assignment ba && ba.Right is FunctionCall fc && fc.Function is IdentifierReference fci && fci.Identifier == f1.Identifier) { var gfor = new GenericFor(); // Search the predecessor block for the initial assignment which contains the right expression IExpression right = new IExpression(); for (int i = loopInitializer.Instructions.Count() - 1; i >= 0; i--) { if (loopInitializer.Instructions[i] is Assignment a) { right = a.Right; loopInitializer.Instructions.RemoveAt(i); break; } } // Loop head has the loop variables if (node.Instructions.First() is Assignment a2) { gfor.Iterator = new Assignment(a2.Left, right); node.Instructions.RemoveAt(0); } else { throw new Exception("Unkown for pattern"); } // Body contains more loop bytecode that can be removed //var body = (node.Successors[0].ReversePostorderNumber > node.Successors[1].ReversePostorderNumber) ? node.Successors[0] : node.Successors[1]; var body = node.Successors[0]; if (body.Instructions[0] is Assignment a3) { body.Instructions.RemoveAt(0); } gfor.Body = body; gfor.Body.MarkCodegenerated(f.Id); if (!usedFollows.Contains(node.LoopFollow)) { gfor.Follow = node.LoopFollow; usedFollows.Add(node.LoopFollow); node.LoopFollow.MarkCodegenerated(f.Id); } if (loopInitializer.Instructions.Any() && loopInitializer.Instructions[loopInitializer.Instructions.Count() - 1] is Jump) { loopInitializer.Instructions[loopInitializer.Instructions.Count() - 1] = gfor; } else { loopInitializer.Instructions.Add(gfor); } node.MarkCodegenerated(f.Id); // The head might be the follow of an if statement, so do this to not codegen it usedFollows.Add(node); }
public virtual void Visit(GenericFor node) { }
IStatement ParseFor(ParseTreeNode node) { if (node.Term.Name == "For") { var block = ParseDoBlock(node.ChildNodes[2]); var type = node.ChildNodes[1].ChildNodes[0]; if (type.Term.Name == "NumericFor") { var cycle = new NumericFor(); cycle.Block = block; cycle.Variable = type.ChildNodes[0].Token.ValueString; cycle.Var = ParseExpression(type.ChildNodes[1]); cycle.Limit = ParseExpression(type.ChildNodes[2]); cycle.Step = new Runtime.Ast.NumberLiteral() { Value = 1 }; if (type.ChildNodes[3].ChildNodes.Count > 0) { var child = type.ChildNodes[3].ChildNodes[0]; cycle.Step = ParseExpression(child); } return(cycle); } else { var cycle = new GenericFor(); cycle.Block = block; var nameList = type.ChildNodes[0]; var exprList = type.ChildNodes[2]; while (true) { var name = nameList.ChildNodes[0].Token.ValueString; cycle.Variables.Add(name); var child = nameList.ChildNodes[1]; if (child.ChildNodes.Count > 0) { nameList = child.ChildNodes[0]; } else { break; } } while (true) { var expr = ParseExpression(exprList.ChildNodes[0]); cycle.Expressions.Add(expr); var child = exprList.ChildNodes[1]; if (child.ChildNodes.Count > 0) { exprList = child.ChildNodes[0]; } else { break; } } return(cycle); } } throw new Exception("Invalid For node"); }