Exemplo n.º 1
0
        public ForeachStatement TransformNonGenericForEach(ExpressionStatement node)
        {
            Match m1 = getEnumeratorPattern.Match(node);

            if (!m1.Success)
            {
                return(null);
            }
            AstNode tryCatch = node.NextSibling;
            Match   m2       = nonGenericForeachPattern.Match(tryCatch);

            if (!m2.Success)
            {
                return(null);
            }

            IdentifierExpression enumeratorVar = m2.Get <IdentifierExpression>("enumerator").Single();
            IdentifierExpression itemVar       = m2.Get <IdentifierExpression>("itemVar").Single();
            WhileStatement       loop          = m2.Get <WhileStatement>("loop").Single();

            // verify that the getEnumeratorPattern assigns to the same variable as the nonGenericForeachPattern is reading from
            if (!enumeratorVar.IsMatch(m1.Get("left").Single()))
            {
                return(null);
            }

            VariableDeclarationStatement enumeratorVarDecl = FindVariableDeclaration(loop, enumeratorVar.Identifier);

            if (enumeratorVarDecl == null || !(enumeratorVarDecl.Parent is BlockStatement))
            {
                return(null);
            }

            // Find the declaration of the item variable:
            // Because we look only outside the loop, we won't make the mistake of moving a captured variable across the loop boundary
            VariableDeclarationStatement itemVarDecl = FindVariableDeclaration(loop, itemVar.Identifier);

            if (itemVarDecl == null || !(itemVarDecl.Parent is BlockStatement))
            {
                return(null);
            }

            // Now verify that we can move the variable declaration in front of the loop:
            Statement declarationPoint;

            CanMoveVariableDeclarationIntoStatement(itemVarDecl, loop, out declarationPoint);
            // We ignore the return value because we don't care whether we can move the variable into the loop
            // (that is possible only with non-captured variables).
            // We just care that we can move it in front of the loop:
            if (declarationPoint != loop)
            {
                return(null);
            }

            ForeachStatement foreachStatement = new ForeachStatement();

            foreachStatement.VariableType = itemVarDecl.Type.Clone();
            foreachStatement.VariableName = itemVar.Identifier;
            BlockStatement body = new BlockStatement();

            foreachStatement.EmbeddedStatement = body;
            ((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement);

            body.Add(node.Detach());
            body.Add((Statement)tryCatch.Detach());

            // Now that we moved the whole try-catch into the foreach loop; verify that we can
            // move the enumerator into the foreach loop:
            CanMoveVariableDeclarationIntoStatement(enumeratorVarDecl, foreachStatement, out declarationPoint);
            if (declarationPoint != foreachStatement)
            {
                // oops, the enumerator variable can't be moved into the foreach loop
                // Undo our AST changes:
                ((BlockStatement)foreachStatement.Parent).Statements.InsertBefore(foreachStatement, node.Detach());
                foreachStatement.ReplaceWith(tryCatch);
                return(null);
            }

            // Now create the correct body for the foreach statement:
            foreachStatement.InExpression = m1.Get <Expression>("collection").Single().Detach();
            if (foreachStatement.InExpression is BaseReferenceExpression)
            {
                foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
            }
            body.Statements.Clear();
            body.Statements.AddRange(m2.Get <Statement>("stmt").Select(stmt => stmt.Detach()));

            return(foreachStatement);
        }
Exemplo n.º 2
0
        public override void EnterForeachStatement(ForeachStatement foreachStatement)
        {
            var listVariable = new VariableDeclaration(
                foreachStatement.Context,
                "list" + NumberWheel.Next(),
                new INode[]
            {
                AstCloner.Clone((GenericType)foreachStatement.List.Type),
                foreachStatement.List
            });
            var indexVariable = new VariableDeclaration(
                foreachStatement.Context,
                "index" + NumberWheel.Next(),
                new INode[]
            {
                new NumberType(foreachStatement.Context),
                new NumberLiteral(foreachStatement.Context, "0")
            });

            var condition = new BinaryExpression(
                foreachStatement.Context,
                new INode[]
            {
                new SimpleNameExpression(foreachStatement.Context, indexVariable.Name)
                {
                    Declaration = indexVariable,
                    Type        = indexVariable.Type
                },
                new Token(foreachStatement.Context, "<"),
                NativeMethods.ArrayCount(
                    foreachStatement.Context,
                    new SimpleNameExpression(foreachStatement.Context, listVariable.Name)
                {
                    Declaration = listVariable,
                    Type        = listVariable.Type
                })
            });
            var update = new AssignmentExpression(
                foreachStatement.Context,
                new INode[]
            {
                new SimpleNameExpression(foreachStatement.Context, indexVariable.Name)
                {
                    Declaration = indexVariable,
                    Type        = indexVariable.Type
                },
                new AssignmentOperator(foreachStatement.Context, "="),
                new BinaryExpression(
                    foreachStatement.Context,
                    new INode[]
                {
                    new SimpleNameExpression(foreachStatement.Context, indexVariable.Name)
                    {
                        Declaration = indexVariable,
                        Type        = indexVariable.Type
                    },
                    new Token(foreachStatement.Context, "+"),
                    new NumberLiteral(foreachStatement.Context, "1")
                }),
            });
            var forStatement = new ForStatement(
                foreachStatement.Context,
                new[]
            {
                listVariable,
                indexVariable
            },
                new IExpression[0],
                condition,
                update.Yield(),
                foreachStatement.Body);
            var elmVariable = foreachStatement.Variable;

            elmVariable.AddChild(
                NativeMethods.ArrayIndex(
                    foreachStatement.Context,
                    new SimpleNameExpression(foreachStatement.Context, listVariable.Name)
            {
                Declaration = listVariable,
                Type        = listVariable.Type
            },
                    new SimpleNameExpression(foreachStatement.Context, indexVariable.Name)
            {
                Declaration = indexVariable,
                Type        = indexVariable.Type
            })
                );
            forStatement.Body.AddChildFirst(new VariableDeclarationStatement(foreachStatement.Context, elmVariable));
            foreachStatement.ReplaceWith(forStatement);
            Visit(forStatement);
            skipChildren = true;
        }