Boo.Lang.Compiler.Steps.OptimizeIterationStatements.CheckForItemInRangeLoop C# (CSharp) Метод

CheckForItemInRangeLoop() приватный Метод

Optimize the for item in range() construct
private CheckForItemInRangeLoop ( Boo.Lang.Compiler.Ast.ForStatement node ) : void
node Boo.Lang.Compiler.Ast.ForStatement the for statement to check
Результат void
        private void CheckForItemInRangeLoop(ForStatement node)
        {
            MethodInvocationExpression mi = node.Iterator as MethodInvocationExpression;
            if (null == mi) return;
            if (!IsRangeInvocation(mi)) return;

            DeclarationCollection declarations = node.Declarations;
            if (declarations.Count != 1) return;

            ExpressionCollection args = mi.Arguments;
            Block body = new Block(node.LexicalInfo);

            Expression min;
            Expression max;
            Expression step;

            if (args.Count == 1)
            {
                min = CodeBuilder.CreateIntegerLiteral(0);
                max = args[0];
                step = CodeBuilder.CreateIntegerLiteral(1);
            }
            else if (args.Count == 2)
            {
                min = args[0];
                max = args[1];
                step = CodeBuilder.CreateIntegerLiteral(1);
            }
            else
            {
                min = args[0];
                max = args[1];
                step = args[2];
            }

            InternalLocal numVar = CodeBuilder.DeclareTempLocal(
                                        _currentMethod,
                                        TypeSystemServices.IntType);
            Expression numRef = CodeBuilder.CreateReference(numVar);

            // __num = <min>
            body.Add(
                CodeBuilder.CreateAssignment(
                    numRef,
                    min));

            Expression endRef;

            if (max.NodeType == NodeType.IntegerLiteralExpression)
            {
                endRef = max;
            }
            else
            {
                InternalLocal endVar = CodeBuilder.DeclareTempLocal(
                            _currentMethod,
                            TypeSystemServices.IntType);
                endRef = CodeBuilder.CreateReference(endVar);

                // __end = <end>
                body.Add(
                    CodeBuilder.CreateAssignment(
                        endRef,
                        max));
            }

            if (args.Count == 1)
            {
                if (max.NodeType == NodeType.IntegerLiteralExpression)
                {
                    if (((IntegerLiteralExpression)max).Value < 0)
                    {
                        // raise ArgumentOutOfRangeException("max") (if <max> < 0)
                        Statement statement = CodeBuilder.RaiseException(
                            body.LexicalInfo,
                            TypeSystemServices.Map(System_ArgumentOutOfRangeException_ctor),
                            CodeBuilder.CreateStringLiteral("max"));

                        body.Add(statement);
                    }
                }
                else
                {
                    IfStatement ifStatement = new IfStatement(body.LexicalInfo);
                    ifStatement.TrueBlock = new Block();

                    // raise ArgumentOutOfRangeException("max") if __end < 0
                    Statement statement = CodeBuilder.RaiseException(
                            body.LexicalInfo,
                            TypeSystemServices.Map(System_ArgumentOutOfRangeException_ctor),
                            CodeBuilder.CreateStringLiteral("max"));

                    ifStatement.Condition = CodeBuilder.CreateBoundBinaryExpression(
                            TypeSystemServices.BoolType,
                            BinaryOperatorType.LessThan,
                            endRef,
                            CodeBuilder.CreateIntegerLiteral(0));

                    ifStatement.TrueBlock.Add(statement);

                    body.Add(ifStatement);
                }
            }

            Expression stepRef;

            switch (args.Count)
            {
                case 1:
                    stepRef = CodeBuilder.CreateIntegerLiteral(1);
                    break;
                case 2:
                    if ((min.NodeType == NodeType.IntegerLiteralExpression) &&
                    (max.NodeType == NodeType.IntegerLiteralExpression) &&
                    (((IntegerLiteralExpression)max).Value < ((IntegerLiteralExpression)min).Value))
                    {
                        // __step = -1
                        stepRef = CodeBuilder.CreateIntegerLiteral(-1);
                    }
                    else if ((min.NodeType == NodeType.IntegerLiteralExpression) &&
                    (max.NodeType == NodeType.IntegerLiteralExpression))
                    {
                        // __step = 1
                        stepRef = CodeBuilder.CreateIntegerLiteral(1);
                    }
                    else
                    {
                        InternalLocal stepVar = CodeBuilder.DeclareTempLocal(
                                _currentMethod,
                                TypeSystemServices.IntType);
                        stepRef = CodeBuilder.CreateReference(stepVar);

                        // __step = 1
                        body.Add(
                            CodeBuilder.CreateAssignment(
                                stepRef,
                                CodeBuilder.CreateIntegerLiteral(1)));

                        // __step = -1 if __end < __num
                        IfStatement ifStatement = new IfStatement(node.LexicalInfo);

                        ifStatement.Condition = CodeBuilder.CreateBoundBinaryExpression(
                            TypeSystemServices.BoolType,
                            BinaryOperatorType.LessThan,
                            endRef,
                            numRef);

                        ifStatement.TrueBlock = new Block();

                        ifStatement.TrueBlock.Add(
                            CodeBuilder.CreateAssignment(
                                stepRef,
                                CodeBuilder.CreateIntegerLiteral(-1)));

                        body.Add(ifStatement);
                    }
                    break;
                default:
                    if (step.NodeType == NodeType.IntegerLiteralExpression)
                    {
                        stepRef = step;
                    }
                    else
                    {
                        InternalLocal stepVar = CodeBuilder.DeclareTempLocal(
                                    _currentMethod,
                                    TypeSystemServices.IntType);
                        stepRef = CodeBuilder.CreateReference(stepVar);

                        // __step = <step>
                        body.Add(
                            CodeBuilder.CreateAssignment(
                                stepRef,
                                step));
                    }
                    break;
            }

            if (args.Count == 3)
            {
                Expression condition = null;
                bool run = false;

                if (step.NodeType == NodeType.IntegerLiteralExpression)
                {
                    if (((IntegerLiteralExpression)step).Value < 0)
                    {
                        if ((max.NodeType == NodeType.IntegerLiteralExpression) &&
                            (min.NodeType == NodeType.IntegerLiteralExpression))
                        {
                            run = (((IntegerLiteralExpression)max).Value > ((IntegerLiteralExpression)min).Value);
                        }
                        else
                        {
                            condition = CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.BoolType,
                                BinaryOperatorType.GreaterThan,
                                endRef,
                                numRef);
                        }
                    }
                    else
                    {
                        if ((max.NodeType == NodeType.IntegerLiteralExpression) &&
                            (min.NodeType == NodeType.IntegerLiteralExpression))
                        {
                            run = (((IntegerLiteralExpression)max).Value < ((IntegerLiteralExpression)min).Value);
                        }
                        else
                        {
                            condition = CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.BoolType,
                                BinaryOperatorType.LessThan,
                                endRef,
                                numRef);
                        }
                    }
                }
                else
                {
                    if ((max.NodeType == NodeType.IntegerLiteralExpression) &&
                        (min.NodeType == NodeType.IntegerLiteralExpression))
                    {
                        if (((IntegerLiteralExpression)max).Value < ((IntegerLiteralExpression)min).Value)
                        {
                            condition = CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.BoolType,
                                BinaryOperatorType.GreaterThan,
                                stepRef,
                                CodeBuilder.CreateIntegerLiteral(0));
                        }
                        else
                        {
                            condition = CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.BoolType,
                                BinaryOperatorType.LessThan,
                                stepRef,
                                CodeBuilder.CreateIntegerLiteral(0));
                        }
                    }
                    else
                    {
                        condition = CodeBuilder.CreateBoundBinaryExpression(
                            TypeSystemServices.BoolType,
                            BinaryOperatorType.Or,
                            CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.BoolType,
                                BinaryOperatorType.And,
                                CodeBuilder.CreateBoundBinaryExpression(
                                    TypeSystemServices.BoolType,
                                    BinaryOperatorType.LessThan,
                                    stepRef,
                                    CodeBuilder.CreateIntegerLiteral(0)),
                                CodeBuilder.CreateBoundBinaryExpression(
                                    TypeSystemServices.BoolType,
                                    BinaryOperatorType.GreaterThan,
                                    endRef,
                                    numRef)),
                            CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.BoolType,
                                BinaryOperatorType.And,
                                CodeBuilder.CreateBoundBinaryExpression(
                                    TypeSystemServices.BoolType,
                                    BinaryOperatorType.GreaterThan,
                                    stepRef,
                                    CodeBuilder.CreateIntegerLiteral(0)),
                                CodeBuilder.CreateBoundBinaryExpression(
                                    TypeSystemServices.BoolType,
                                    BinaryOperatorType.LessThan,
                                    endRef,
                                    numRef)));
                    }
                }

                // raise ArgumentOutOfRangeException("step") if (__step < 0 and __end > __begin) or (__step > 0 and __end < __begin)
                Statement statement = CodeBuilder.RaiseException(
                            body.LexicalInfo,
                            TypeSystemServices.Map(System_ArgumentOutOfRangeException_ctor),
                            CodeBuilder.CreateStringLiteral("step"));

                if (condition != null)
                {
                    IfStatement ifStatement = new IfStatement(body.LexicalInfo);
                    ifStatement.TrueBlock = new Block();

                    ifStatement.Condition = condition;

                    ifStatement.TrueBlock.Add(statement);

                    body.Add(ifStatement);
                }
                else if (run)
                {
                    body.Add(statement);
                }

                // __end = __num + __step * cast(int, Math.Ceiling((__end - __num)/cast(double, __step)))
                if ((step.NodeType == NodeType.IntegerLiteralExpression) &&
                    (max.NodeType == NodeType.IntegerLiteralExpression) &&
                    (min.NodeType == NodeType.IntegerLiteralExpression))
                {
                    int stepVal = (int)((IntegerLiteralExpression)step).Value;
                    int maxVal = (int)((IntegerLiteralExpression)max).Value;
                    int minVal = (int)((IntegerLiteralExpression)min).Value;
                    endRef = CodeBuilder.CreateIntegerLiteral(
                        minVal + stepVal * (int)System.Math.Ceiling((maxVal - minVal) / ((double)stepVal)));
                }
                else
                {
                    Expression endBak = endRef;
                    if (max.NodeType == NodeType.IntegerLiteralExpression)
                    {
                        InternalLocal endVar = CodeBuilder.DeclareTempLocal(
                                    _currentMethod,
                                    TypeSystemServices.IntType);
                        endRef = CodeBuilder.CreateReference(endVar);
                    }

                    body.Add(
                        CodeBuilder.CreateAssignment(
                            endRef,
                            CodeBuilder.CreateBoundBinaryExpression(
                                TypeSystemServices.IntType,
                                BinaryOperatorType.Addition,
                                numRef,
                                CodeBuilder.CreateBoundBinaryExpression(
                                    TypeSystemServices.IntType,
                                    BinaryOperatorType.Multiply,
                                    stepRef,
                                    CodeBuilder.CreateCast(
                                        TypeSystemServices.IntType,
                                        CodeBuilder.CreateMethodInvocation(
                                            TypeSystemServices.Map(System_Math_Ceiling),
                                            CodeBuilder.CreateBoundBinaryExpression(
                                                TypeSystemServices.DoubleType,
                                                BinaryOperatorType.Division,
                                                CodeBuilder.CreateBoundBinaryExpression(
                                                    TypeSystemServices.IntType,
                                                    BinaryOperatorType.Subtraction,
                                                    endBak,
                                                    numRef),
                                                CodeBuilder.CreateCast(
                                                    TypeSystemServices.DoubleType,
                                                    stepRef))))))));
                }
            }

            // while __num != __end:
            WhileStatement ws = new WhileStatement(node.LexicalInfo);

            BinaryOperatorType op = BinaryOperatorType.Inequality;

            if (stepRef.NodeType == NodeType.IntegerLiteralExpression)
            {
                if (((IntegerLiteralExpression)stepRef).Value > 0)
                {
                    op = BinaryOperatorType.LessThan;
                }
                else
                {
                    op = BinaryOperatorType.GreaterThan;
                }
            }

            ws.Condition = CodeBuilder.CreateBoundBinaryExpression(
                TypeSystemServices.BoolType,
                op,
                numRef,
                endRef);
            ws.Condition.LexicalInfo = node.LexicalInfo;

            //	item = __num
            ws.Block.Add(
                CodeBuilder.CreateAssignment(
                    CodeBuilder.CreateReference((InternalLocal)declarations[0].Entity),
                    numRef));

            Block rawBlock = new Block();
            rawBlock["checked"] = false;

            //  __num += __step
            rawBlock.Add(
                CodeBuilder.CreateAssignment(
                    numRef,
                    CodeBuilder.CreateBoundBinaryExpression(
                        TypeSystemServices.IntType,
                        BinaryOperatorType.Addition,
                        numRef,
                        stepRef)));

            ws.Block.Add(rawBlock as Statement);

            //	<block>
            ws.Block.Add(node.Block);

            ws.OrBlock = node.OrBlock;
            ws.ThenBlock = node.ThenBlock;

            body.Add(ws);

            ReplaceCurrentNode(body);
        }