Exemplo n.º 1
0
        private JSForLoop ReplaceWhileLoopAndEnumerator(JSWhileLoop wl, JSExpression backingStore, JSExpression enumerator, TypeInfo enumeratorType, string arrayMember, string lengthMember)
        {
            var loopId             = _NextLoopId++;
            var arrayVariableName  = String.Format("a${0:x}", loopId);
            var indexVariableName  = String.Format("i${0:x}", loopId);
            var lengthVariableName = String.Format("l${0:x}", loopId);

            var currentPropertyReference = enumeratorType.Definition.Properties.First((p) => p.Name == "Current");
            var currentPropertyInfo      = enumeratorType.Source.GetProperty(currentPropertyReference);

            var itemType  = currentPropertyInfo.ReturnType;
            var arrayType = new ArrayType(itemType);

            var arrayVariable = new JSVariable(
                arrayVariableName, arrayType, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(arrayMember, arrayType))
                );
            var indexVariable = new JSVariable(
                indexVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSLiteral.New(0)
                );
            var lengthVariable = new JSVariable(
                lengthVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(lengthMember, TypeSystem.Int32))
                );

            var initializer = new JSVariableDeclarationStatement(
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, arrayVariable, arrayVariable.DefaultValue, arrayVariable.IdentifierType
                    ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, indexVariable, indexVariable.DefaultValue, indexVariable.IdentifierType
                    ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, lengthVariable, lengthVariable.DefaultValue, lengthVariable.IdentifierType
                    )
                );

            var condition = new JSBinaryOperatorExpression(
                JSOperator.LessThan,
                indexVariable, lengthVariable, TypeSystem.Boolean
                );

            var increment = new JSUnaryOperatorExpression(
                JSOperator.PostIncrement,
                indexVariable, TypeSystem.Int32
                );

            var result = new JSForLoop(
                initializer, condition, new JSExpressionStatement(increment),
                wl.Statements.ToArray()
                );

            result.Index = wl.Index;

            new PropertyAccessReplacer(
                enumerator, new JSProperty(currentPropertyReference, currentPropertyInfo),
                new JSIndexerExpression(
                    arrayVariable, indexVariable,
                    itemType
                    )
                ).Visit(result);

            return(result);
        }
        protected void TransformVariableIntoReference(JSVariable variable, JSVariableDeclarationStatement statement, int declarationIndex, JSBlockStatement enclosingBlock)
        {
            var oldDeclaration    = statement.Declarations[declarationIndex];
            var valueType         = oldDeclaration.Right.GetActualType(JSIL.TypeSystem);
            var newVariable       = variable.Reference();
            var enclosingFunction = Stack.OfType <JSFunctionExpression>().First();

            JSExpression initialValue;

            // If the declaration was in function scope originally we can hoist the initial value
            //  into our new variable declaration. If not, we need to initialize the ref variable
            //  to the default value for its type. It will get the correct value assigned later.
            if (enclosingBlock == enclosingFunction.Body)
            {
                initialValue = oldDeclaration.Right;
            }
            else
            {
                initialValue = new JSDefaultValueLiteral(valueType);
            }

            var newDeclaration = new JSVariableDeclarationStatement(new JSBinaryOperatorExpression(
                                                                        JSOperator.Assignment,
                                                                        // We have to use a constructed ref to the variable here, otherwise
                                                                        //  the declaration will look like 'var x.value = foo'
                                                                        new JSVariable(variable.Identifier, variable.IdentifierType, variable.Function),
                                                                        JSIL.NewReference(initialValue),
                                                                        newVariable.IdentifierType
                                                                        ));

            if (Tracing)
            {
                Console.WriteLine(String.Format("Transformed {0} into {1} in {2}", variable, newVariable, statement));
            }

            // Insert the new declaration directly before the top-level block containing the original
            //  declaration. This ensures that if its initial value has a dependency on external state,
            //  the declaration will not precede the values it depends on.
            // Note that for declarations that were hoisted out of inner blocks (conditionals, loops)
            //  it doesn't actually matter where the insert occurs, since we initialize with a default
            //  value in that case.
            enclosingFunction.Body.InsertNearChildRecursive(
                statement, newDeclaration, 0
                );

            // If the reference is being declared in function scope, it doesn't need a separate assignment
            //  for its initialization. Otherwise, we need to insert an assignment after the original variable
            //  declaration statement to ensure that the reference variable is initialized to the right value
            //  at the exact right point in the function's execution.
            if (enclosingBlock != enclosingFunction.Body)
            {
                var newAssignment = new JSExpressionStatement(
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment, newVariable, oldDeclaration.Right, valueType
                        )
                    );
                var insertLocation = enclosingBlock.Statements.IndexOf(statement) + 1;
                enclosingBlock.Statements.Insert(insertLocation, newAssignment);
            }

            Variables[variable.Identifier] = newVariable;
            statement.Declarations.RemoveAt(declarationIndex);
            TransformedVariables.Add(variable.Identifier);
        }