Exemplo n.º 1
0
        static LuaArguments EvalNumericFor(NumericFor stat, LuaContext Context, out LuaReturnStatus returned)
        {
            returned.broke    = false;
            returned.returned = false;
            var varList   = EvalExpression(stat.Var, Context);
            var limitList = EvalExpression(stat.Limit, Context);
            var stepList  = EvalExpression(stat.Step, Context);
            var var       = LuaEvents.toNumber(varList[0]);
            var limit     = LuaEvents.toNumber(limitList[0]);
            var step      = LuaEvents.toNumber(stepList[0]);

            if (!(var & limit & step).AsBool())
            {
                throw new LuaException("Error in for loop");
            }
            LuaContext ctx = new LuaContext(Context);

            while ((step > 0 & var <= limit) | (step <= 0 & var >= limit))
            {
                ctx.SetLocal(stat.Variable, var);
                LuaArguments obj = EvalBlock(stat.Block, ctx, out returned);
                if (returned.broke)
                {
                    break;
                }
                if (returned.returned)
                {
                    return(obj);
                }
                var = var + step;
            }
            return(Lua.Return());
        }
Exemplo n.º 2
0
 public bool Match(XMLLuaSearchNumericFor req, NumericFor real)
 {
     Logger.Debug($"numeric_for");
     if (Match(req.Block, real.Block) && Match(req.Limit, real.Limit) && Match(req.Step, real.Step) &&
         Match(req.Var, real.Var) && (req.Variable == real.Variable))
     {
         SetSelectionIfSelected(real.Span, req);
         return(true);
     }
     return(false);
 }
Exemplo n.º 3
0
        public async Task ExecuteNumericFor(NumericFor numericFor, LuaState state, CancellationToken token = default)
        {
            var var = await _engine.EvaluateExpression(numericFor.Var, state, token).FirstAsync();

            var step = await _engine.EvaluateExpression(numericFor.Step, state, token).FirstAsync();

            var limit = await _engine.EvaluateExpression(numericFor.Limit, state, token).FirstAsync();

            var forState  = state.WithNewContext();
            var compareOp = step < 0d ? BinaryOp.GreaterOrEqual : BinaryOp.LessOrEqual;

            while (!state.FunctionState.DidReturn && !token.IsCancellationRequested && (await LuaObject.BinaryOperationAsync(state.Engine, compareOp, var, limit, token)).AsBool())
            {
                await forState.Context.NewIndexAsync(state.Engine, numericFor.Variable, var, token);

                await _engine.ExecuteStatement(numericFor.Block, forState, token);

                var = await LuaObject.BinaryOperationAsync(state.Engine, BinaryOp.Addition, var, step, token);
            }
        }
Exemplo n.º 4
0
 public void Visit(NumericFor 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);
                    }
Exemplo n.º 6
0
 public virtual void Visit(NumericFor node)
 {
 }
Exemplo n.º 7
0
        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");
        }