Пример #1
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType     = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum   = IsEnumOrNullableEnum(leftType);
            var rightType    = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum  = IsEnumOrNullableEnum(rightType);
            var resultType   = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            if ((leftIsEnum || rightIsEnum) && LogicalOperators.Contains(boe.Operator))
            {
                if (leftIsEnum)
                {
                    var cast = JSInvocationExpression.InvokeStatic(
                        JS.Number(TypeSystem.Int32), new[] { boe.Left }, true
                        );

                    boe.ReplaceChild(boe.Left, cast);
                }

                if (rightIsEnum)
                {
                    var cast = JSInvocationExpression.InvokeStatic(
                        JS.Number(TypeSystem.Int32), new[] { boe.Right }, true
                        );

                    boe.ReplaceChild(boe.Right, cast);
                }
            }

            VisitChildren(boe);
        }
Пример #2
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            bool isArithmetic = !(boe.Operator is JSAssignmentOperator);

            if ((leftType.FullName == "System.Char") && isArithmetic)
            {
                boe.ReplaceChild(boe.Left, CastToInteger(boe.Left));
            }

            if ((rightType.FullName == "System.Char") && isArithmetic)
            {
                boe.ReplaceChild(boe.Right, CastToInteger(boe.Right));
            }

            var parentInvocation = ParentNode as JSInvocationExpression;
            JSDotExpressionBase parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpressionBase : null;

            if (
                isArithmetic &&
                (boe.GetActualType(TypeSystem).FullName == "System.Char") &&
                !(
                    (parentInvocation != null) &&
                    (parentInvocationDot != null) &&
                    (parentInvocationDot.Target is JSStringIdentifier) &&
                    (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") &&
                    (parentInvocationDot.Member is JSFakeMethod) &&
                    (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode")
                    )
                )
            {
                var castBoe = CastToChar(boe);
                ParentNode.ReplaceChild(boe, castBoe);

                VisitReplacement(castBoe);
            }
            else
            {
                VisitChildren(boe);
            }
        }
Пример #3
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType = boe.Left.GetExpectedType(TypeSystem);
            var rightType = boe.Right.GetExpectedType(TypeSystem);

            bool isArithmetic = !(boe.Operator is JSAssignmentOperator);

            if ((leftType.FullName == "System.Char") && isArithmetic)
                boe.ReplaceChild(boe.Left, CastToInteger(boe.Left));

            if ((rightType.FullName == "System.Char") && isArithmetic)
                boe.ReplaceChild(boe.Right, CastToInteger(boe.Right));

            var parentInvocation = ParentNode as JSInvocationExpression;
            JSDotExpression parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpression : null;

            if (
                isArithmetic &&
                (boe.GetExpectedType(TypeSystem).FullName == "System.Char") &&
                !(
                    (parentInvocation != null) &&
                    (parentInvocationDot != null) &&
                    (parentInvocationDot.Target is JSStringIdentifier) &&
                    (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") &&
                    (parentInvocationDot.Member is JSFakeMethod) &&
                    (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode")
                )
            ) {
                var castBoe = CastToChar(boe);
                ParentNode.ReplaceChild(boe, castBoe);

                VisitReplacement(castBoe);
            } else {
                VisitChildren(boe);
            }
        }
Пример #4
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            // We can end up with a pointer literal in an arithmetic expression.
            // In this case we want to switch it back to a normal integer literal so that the math operations work.
            var leftPointer  = boe.Left as JSPointerLiteral;
            var rightPointer = boe.Right as JSPointerLiteral;

            if (!(boe.Operator is JSAssignmentOperator))
            {
                if (leftPointer != null)
                {
                    boe.ReplaceChild(boe.Left, JSLiteral.New(leftPointer.Value));
                }
                if (rightPointer != null)
                {
                    boe.ReplaceChild(boe.Right, JSLiteral.New(rightPointer.Value));
                }
            }

            JSExpression replacement = null;

            if (leftType.IsPointer && TypeUtil.IsIntegral(rightType))
            {
                if (
                    (boe.Operator == JSOperator.Add) ||
                    (boe.Operator == JSOperator.AddAssignment)
                    )
                {
                    replacement = new JSPointerAddExpression(
                        boe.Left, boe.Right,
                        boe.Operator == JSOperator.AddAssignment
                        );
                }
                else if (
                    (boe.Operator == JSOperator.Subtract) ||
                    (boe.Operator == JSOperator.SubtractAssignment)
                    )
                {
                    // FIXME: Int32 is probably wrong
                    replacement = new JSPointerAddExpression(
                        boe.Left,
                        new JSUnaryOperatorExpression(JSOperator.Negation, boe.Right, TypeSystem.Int32),
                        boe.Operator == JSOperator.SubtractAssignment
                        );
                }
            }
            else if (leftType.IsPointer && rightType.IsPointer)
            {
                if (boe.Operator == JSOperator.Subtract)
                {
                    // FIXME: Int32 is probably wrong
                    replacement = new JSPointerDeltaExpression(
                        boe.Left, boe.Right, TypeSystem.Int32
                        );
                }
                else if (boe.Operator is JSComparisonOperator)
                {
                    replacement = new JSPointerComparisonExpression(boe.Operator, boe.Left, boe.Right, boe.ActualType);
                }
            }

            if (replacement != null)
            {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(boe);
            }
        }
Пример #5
0
        public void VisitNode (JSBinaryOperatorExpression boe) {
            var leftType = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            // We can end up with a pointer literal in an arithmetic expression.
            // In this case we want to switch it back to a normal integer literal so that the math operations work.
            var leftPointer = boe.Left as JSPointerLiteral;
            var rightPointer = boe.Right as JSPointerLiteral;
            if (!(boe.Operator is JSAssignmentOperator)) {
                if (leftPointer != null)
                    boe.ReplaceChild(boe.Left, JSLiteral.New(leftPointer.Value));
                if (rightPointer != null)
                    boe.ReplaceChild(boe.Right, JSLiteral.New(rightPointer.Value));
            }

            JSExpression replacement = null;
            if (leftType.IsPointer && TypeUtil.IsIntegral(rightType)) {
                if (
                    (boe.Operator == JSOperator.Add) ||
                    (boe.Operator == JSOperator.AddAssignment)
                ) {
                    replacement = new JSPointerAddExpression(
                        boe.Left, boe.Right,
                        boe.Operator == JSOperator.AddAssignment
                    );
                } else if (
                    (boe.Operator == JSOperator.Subtract) ||
                    (boe.Operator == JSOperator.SubtractAssignment)
                ) {
                    // FIXME: Int32 is probably wrong
                    replacement = new JSPointerAddExpression(
                        boe.Left,
                        new JSUnaryOperatorExpression(JSOperator.Negation, boe.Right, TypeSystem.Int32),
                        boe.Operator == JSOperator.SubtractAssignment
                    );
                }
            } else if (leftType.IsPointer && rightType.IsPointer) {
                if (boe.Operator == JSOperator.Subtract) {
                    // FIXME: Int32 is probably wrong
                    replacement = new JSPointerDeltaExpression(
                        boe.Left, boe.Right, TypeSystem.Int32
                    );
                } else if (boe.Operator is JSComparisonOperator) {
                    replacement = new JSPointerComparisonExpression(boe.Operator, boe.Left, boe.Right, boe.ActualType);
                }
            }

            if (replacement != null) {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            } else {
                VisitChildren(boe);
            }
        }
Пример #6
0
        public void VisitNode (JSBinaryOperatorExpression boe) {
            var leftType = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            bool isArithmetic = !(boe.Operator is JSAssignmentOperator);

            if (!isArithmetic && boe.Operator != JSOperator.Assignment && leftType.FullName == "System.Char")
            {
                JSBinaryOperator newOperator;
                if (boe.Operator == JSOperator.AddAssignment)
                {
                    newOperator = JSOperator.Add;
                }
                else if (boe.Operator == JSOperator.BitwiseAndAssignment)
                {
                    newOperator = JSOperator.BitwiseAnd;
                }
                else if (boe.Operator == JSOperator.BitwiseOrAssignment)
                {
                    newOperator = JSOperator.BitwiseOr;
                }
                else if (boe.Operator == JSOperator.BitwiseXorAssignment)
                {
                    newOperator = JSOperator.BitwiseXor;
                }
                else if (boe.Operator == JSOperator.DivideAssignment)
                {
                    newOperator = JSOperator.Divide;
                }
                else if (boe.Operator == JSOperator.MultiplyAssignment)
                {
                    newOperator = JSOperator.Multiply;
                }
                else if (boe.Operator == JSOperator.RemainderAssignment)
                {
                    newOperator = JSOperator.Remainder;
                }
                else if (boe.Operator == JSOperator.ShiftLeftAssignment)
                {
                    newOperator = JSOperator.ShiftLeft;
                }
                else if (boe.Operator == JSOperator.ShiftRightAssignment)
                {
                    newOperator = JSOperator.ShiftRight;
                }
                else if (boe.Operator == JSOperator.ShiftRightUnsignedAssignment)
                {
                    newOperator = JSOperator.ShiftRightUnsigned;
                }
                else if (boe.Operator == JSOperator.SubtractAssignment)
                {
                    newOperator = JSOperator.Subtract;
                }
                else
                {
                    throw new InvalidOperationException("Unknown assigment operator");
                }

                var newBoe = new JSBinaryOperatorExpression(JSOperator.Assignment, boe.Left,
                    new JSBinaryOperatorExpression(newOperator, boe.Left, boe.Right, boe.ActualType), boe.ActualType);
                ParentNode.ReplaceChild(boe, newBoe);
                VisitReplacement(newBoe);
                return;
            }

            if (boe.Operator == JSOperator.Assignment && (leftType.FullName == "System.Char") && (rightType.FullName != "System.Char"))
            {
                boe.ReplaceChild(boe.Right, CastToChar(boe.Right));
            }
            if (boe.Operator == JSOperator.Assignment && (leftType.FullName != "System.Char") && (rightType.FullName == "System.Char"))
            {
                boe.ReplaceChild(boe.Right, CastToInteger(boe.Right));
            }

            if ((leftType.FullName == "System.Char") && isArithmetic)
                boe.ReplaceChild(boe.Left, CastToInteger(boe.Left));

            if ((rightType.FullName == "System.Char") && isArithmetic)
                boe.ReplaceChild(boe.Right, CastToInteger(boe.Right));

            var parentInvocation = ParentNode as JSInvocationExpression;
            JSDotExpressionBase parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpressionBase : null;

            if (
                isArithmetic && 
                (boe.GetActualType(TypeSystem).FullName == "System.Char") &&
                !(
                    (parentInvocation != null) && 
                    (parentInvocationDot != null) &&
                    (parentInvocationDot.Target is JSStringIdentifier) &&
                    (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") &&
                    (parentInvocationDot.Member is JSFakeMethod) &&
                    (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode")
                )
            ) {
                var castBoe = CastToChar(boe);
                ParentNode.ReplaceChild(boe, castBoe);

                VisitReplacement(castBoe);
            } else {    
                VisitChildren(boe);
            }
        }
Пример #7
0
        void PostOptimizeAssignment(JSBinaryOperatorExpression boe, JSExpression rhs)
        {
            var rhsCopy = rhs as JSStructCopyExpression;

            if (rhsCopy == null)
            {
                return;
            }

            var expr = rhsCopy.Struct;
            var rre  = expr as JSResultReferenceExpression;

            if (rre != null)
            {
                expr = rre.Referent;
            }

            var invocation = expr as JSInvocationExpression;

            if (invocation == null)
            {
                return;
            }

            var invokeMethod = invocation.JSMethod;

            if (invokeMethod == null)
            {
                return;
            }

            var invocationSecondPass = GetSecondPass(invokeMethod);

            if (invocationSecondPass == null)
            {
                return;
            }

            bool   eliminateCopy   = false;
            string eliminateReason = null;

            if (invocationSecondPass.ResultIsNew)
            {
                // If this expression is the return value of a function invocation, we can eliminate struct
                //  copies if the return value is a 'new' expression.
                eliminateCopy   = true;
                eliminateReason = "Result is new";
            }
            else if (invocationSecondPass.ResultVariable != null)
            {
                // We can also eliminate a return value copy if the return value is one of the function's
                //  arguments, and we are sure that argument does not escape (other than through the return
                //  statement, that is).

                var parameters     = invokeMethod.Method.Parameters;
                int parameterIndex = -1;

                for (var i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i].Name != invocationSecondPass.ResultVariable)
                    {
                        continue;
                    }

                    parameterIndex = i;
                    break;
                }

                // We found a single parameter that acts as the result of this function call.
                if (parameterIndex >= 0)
                {
                    GenericParameter relevantParameter;
                    var innerValue = invocation.Arguments[parameterIndex];

                    // Identify any local variables that are a dependency of the result parameter.
                    var localVariableDependencies = StaticAnalyzer.ExtractInvolvedVariables(
                        innerValue,
                        (n) =>
                        // If a variable is inside a copy expression we can ignore it as a dependency.
                        // The copy ensures that the dependency is resolved at the time of invocation.
                        (n is JSStructCopyExpression) ||
                        // If a variable is inside an invocation expression we can ignore it as a dependency.
                        // Dependency resolution would have occurred for the invocation already.
                        (n is JSInvocationExpression)
                        );

                    // Was the result parameter already copied when invoking the function?
                    // If so, we can eliminate the copy of the result because all dependencies have been resolved.
                    // Note that this is separate from the variable dependency extraction above -
                    //  if an invocation has multiple variable dependencies, the above merely narrows them down
                    //  while this detects cases where there are effectively *no* dependencies of any kind.
                    // This also detects cases where the argument is the result of an invocation or property access
                    //  and the result was copied.
                    var isAlreadyCopied = innerValue is JSStructCopyExpression;

                    var dependenciesModified = localVariableDependencies.Any(iv => SecondPass.IsVariableModified(iv.Name));

                    var copyNeededForTarget = IsCopyNeededForAssignmentTarget(boe.Left);

                    var escapes  = invocationSecondPass.DoesVariableEscape(invocationSecondPass.ResultVariable, false);
                    var modified = invocationSecondPass.IsVariableModified(invocationSecondPass.ResultVariable);

                    var traceMessage = (Action)(() => {
                        if (TracePostOptimizeDecisions)
                        {
                            Console.WriteLine(
                                "< {0}: {1} > escapes:{2} modified:{3} copyNeededForTarget({4}):{5} inputsModified:{6}",
                                parameters[parameterIndex].Name, innerValue, escapes, modified, boe.Left, copyNeededForTarget, dependenciesModified
                                );
                        }
                    });

                    if (isAlreadyCopied)
                    {
                        eliminateCopy   = true;
                        eliminateReason = "Result was already copied as part of argument list";
                    }
                    else if (!escapes && !dependenciesModified)
                    {
                        if (!copyNeededForTarget)
                        {
                            eliminateCopy   = true;
                            eliminateReason = "Target does not require a copy and other criteria are met";
                        }
                        else if (!modified)
                        {
                            eliminateCopy   = true;
                            eliminateReason = "Input not modified, doesn't escape, no dependency changes";
                        }

                        traceMessage();
                    }
                    else
                    {
                        traceMessage();
                    }
                }
            }

            if (eliminateCopy)
            {
                if (TracePostOptimizedCopies)
                {
                    Console.WriteLine("Post-optimized assignment {0} because {1}", boe, eliminateReason);
                }

                boe.ReplaceChild(rhsCopy, rhsCopy.Struct);
            }
        }
Пример #8
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum = IsEnumOrNullableEnum(leftType);
            var rightType = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum = IsEnumOrNullableEnum(rightType);
            var resultType = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            if (LogicalOperators.Contains(boe.Operator)) {
                if (eitherIsEnum) {
                    if (leftIsEnum) {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                        );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum) {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                        );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            } else if (BitwiseOperators.Contains(boe.Operator)) {
                var parentCast = ParentNode as JSCastExpression;
                if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType))) {
                    var cast = JSCastExpression.New(
                        boe, resultType, TypeSystem, true
                    );

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            }

            VisitChildren(boe);
        }
Пример #9
0
        void PostOptimizeAssignment (JSBinaryOperatorExpression boe, JSExpression rhs) {
            var rhsCopy = rhs as JSStructCopyExpression;
            if (rhsCopy == null)
                return;

            var expr = rhsCopy.Struct;
            var rre = expr as JSResultReferenceExpression;
            if (rre != null)
                expr = rre.Referent;

            var invocation = expr as JSInvocationExpression;
            if (invocation == null)
                return;

            var invokeMethod = invocation.JSMethod;
            if (invokeMethod == null)
                return;

            var invocationSecondPass = GetSecondPass(invokeMethod);
            if (invocationSecondPass == null)
                return;

            bool eliminateCopy = false;
            string eliminateReason = null;

            if (invocationSecondPass.ResultIsNew) {
                // If this expression is the return value of a function invocation, we can eliminate struct
                //  copies if the return value is a 'new' expression.
                eliminateCopy = true;
                eliminateReason = "Result is new";
            } else if (invocationSecondPass.ResultVariable != null) {
                // We can also eliminate a return value copy if the return value is one of the function's 
                //  arguments, and we are sure that argument does not escape (other than through the return
                //  statement, that is).
                
                var parameters = invokeMethod.Method.Parameters;
                int parameterIndex = -1;

                for (var i = 0; i < parameters.Length; i++) {
                    if (parameters[i].Name != invocationSecondPass.ResultVariable)
                        continue;

                    parameterIndex = i;
                    break;
                }

                // We found a single parameter that acts as the result of this function call.
                if (parameterIndex >= 0) {
                    GenericParameter relevantParameter;
                    var innerValue = invocation.Arguments[parameterIndex];

                    // Identify any local variables that are a dependency of the result parameter.
                    var localVariableDependencies = StaticAnalyzer.ExtractInvolvedVariables(
                        innerValue,
                        (n) =>
                            // If a variable is inside a copy expression we can ignore it as a dependency.
                            // The copy ensures that the dependency is resolved at the time of invocation.
                            (n is JSStructCopyExpression) ||
                            // If a variable is inside an invocation expression we can ignore it as a dependency.
                            // Dependency resolution would have occurred for the invocation already.
                            (n is JSInvocationExpression)
                    );

                    // Was the result parameter already copied when invoking the function?
                    // If so, we can eliminate the copy of the result because all dependencies have been resolved.
                    // Note that this is separate from the variable dependency extraction above -
                    //  if an invocation has multiple variable dependencies, the above merely narrows them down
                    //  while this detects cases where there are effectively *no* dependencies of any kind.
                    // This also detects cases where the argument is the result of an invocation or property access
                    //  and the result was copied.
                    var isAlreadyCopied = innerValue is JSStructCopyExpression;

                    var dependenciesModified = localVariableDependencies.Any(iv => SecondPass.IsVariableModified(iv.Name));

                    var copyNeededForTarget = IsCopyNeededForAssignmentTarget(boe.Left);

                    var escapes = invocationSecondPass.DoesVariableEscape(invocationSecondPass.ResultVariable, false);
                    var modified = invocationSecondPass.IsVariableModified(invocationSecondPass.ResultVariable);

                    var traceMessage = (Action)(() => {
                        if (TracePostOptimizeDecisions)
                            Console.WriteLine(
                                "< {0}: {1} > escapes:{2} modified:{3} copyNeededForTarget({4}):{5} inputsModified:{6}", 
                                parameters[parameterIndex].Name, innerValue, escapes, modified, boe.Left, copyNeededForTarget, dependenciesModified
                            );
                    });

                    if (isAlreadyCopied) {
                        eliminateCopy = true;
                        eliminateReason = "Result was already copied as part of argument list";
                    } else if (!escapes && !dependenciesModified) {
                        if (!copyNeededForTarget) {
                            eliminateCopy = true;
                            eliminateReason = "Target does not require a copy and other criteria are met";
                        } else if (!modified) {
                            eliminateCopy = true;
                            eliminateReason = "Input not modified, doesn't escape, no dependency changes";
                        }

                        traceMessage();
                    } else {
                        traceMessage();
                    }
                }
            }

            if (eliminateCopy) {
                if (TracePostOptimizedCopies)
                    Console.WriteLine("Post-optimized assignment {0} because {1}", boe, eliminateReason);

                boe.ReplaceChild(rhsCopy, rhsCopy.Struct);
            }
        }
Пример #10
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType = boe.Left.GetExpectedType(TypeSystem);
            var leftIsEnum = ILBlockTranslator.IsEnum(leftType);
            var rightType = boe.Right.GetExpectedType(TypeSystem);
            var rightIsEnum = ILBlockTranslator.IsEnum(rightType);

            if ((leftIsEnum || rightIsEnum) && LogicalOperators.Contains(boe.Operator)) {
                if (leftIsEnum) {
                    var cast = JSInvocationExpression.InvokeMethod(
                        new JSFakeMethod("valueOf", TypeSystem.Int32, leftType), boe.Left, null, true
                    );

                    boe.ReplaceChild(boe.Left, cast);
                }

                if (rightIsEnum) {
                    var cast = JSInvocationExpression.InvokeMethod(
                        new JSFakeMethod("valueOf", TypeSystem.Int32, rightType), boe.Right, null, true
                    );

                    boe.ReplaceChild(boe.Right, cast);
                }
            }

            VisitChildren(boe);
        }
Пример #11
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum = IsEnumOrNullableEnum(leftType);
            var rightType = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum = IsEnumOrNullableEnum(rightType);
            var resultType = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;
            JSBinaryOperator replacementOperator;

            if (LogicalOperators.Contains(boe.Operator)) {
                if (eitherIsEnum) {
                    if (leftIsEnum) {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                        );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum) {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                        );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            } else if (BitwiseOperators.Contains(boe.Operator)) {
                var parentCast = ParentNode as JSCastExpression;
                if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType))) {
                    var cast = JSCastExpression.New(
                        boe, resultType, TypeSystem, true
                    );

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            } else if (
                (assignmentOperator != null) &&
                ReverseCompoundAssignments.TryGetValue(assignmentOperator, out replacementOperator) &&
                leftIsEnum
            ) {
                var replacement = new JSBinaryOperatorExpression(
                    JSOperator.Assignment, boe.Left,
                    JSCastExpression.New(
                        new JSBinaryOperatorExpression(
                            replacementOperator, boe.Left, boe.Right, TypeSystem.Int32
                        ), leftType, TypeSystem, true
                    ),
                    leftType
                );

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Пример #12
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType     = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum   = IsEnumOrNullableEnum(leftType);
            var rightType    = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum  = IsEnumOrNullableEnum(rightType);
            var resultType   = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;
            JSBinaryOperator           replacementOperator;
            JSBinaryOperatorExpression replacement;

            if (LogicalOperators.Contains(boe.Operator))
            {
                if (eitherIsEnum)
                {
                    if (leftIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                            );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                            );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            }
            else if (BitwiseOperators.Contains(boe.Operator))
            {
                var parentCast        = ParentNode as JSCastExpression;
                var parentReinterpret = Stack.Skip(2).FirstOrDefault() as JSChangeTypeExpression;

                if (resultIsEnum &&
                    ((parentCast == null) || (parentCast.NewType != resultType)) &&
                    ((parentReinterpret == null) || (parentReinterpret.NewType != resultType))
                    )
                {
                    var cast = CastToEnumType(boe, resultType);

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            }
            else if (
                leftIsEnum &&
                ((replacement = DeconstructMutationAssignment(boe, TypeSystem, TypeSystem.Int32)) != null)
                )
            {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Пример #13
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum = IsEnumOrNullableEnum(leftType);
            var rightType = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum = IsEnumOrNullableEnum(rightType);
            var resultType = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            JSBinaryOperatorExpression replacement;

            if (LogicalOperators.Contains(boe.Operator)) {
                if (eitherIsEnum) {
                    if (leftIsEnum) {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                        );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum) {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                        );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            } else if (BitwiseOperators.Contains(boe.Operator)) {
                var parentCast = ParentNode as JSCastExpression;
                var parentReinterpret = Stack.Skip(2).FirstOrDefault() as JSChangeTypeExpression;

                if (resultIsEnum &&
                    ((parentCast == null) || (parentCast.NewType != resultType)) &&
                    ((parentReinterpret == null) || (parentReinterpret.NewType != resultType))
                ) {
                    var cast = CastToEnumType(boe, resultType);

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            } else if (
                leftIsEnum &&
                ((replacement = DeconstructMutationAssignment(boe, TypeSystem, TypeSystem.Int32)) != null)
            ) {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Пример #14
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType     = boe.Left.GetActualType(TypeSystem);
            var leftIsEnum   = IsEnumOrNullableEnum(leftType);
            var rightType    = boe.Right.GetActualType(TypeSystem);
            var rightIsEnum  = IsEnumOrNullableEnum(rightType);
            var resultType   = boe.GetActualType(TypeSystem);
            var resultIsEnum = IsEnumOrNullableEnum(resultType);

            var eitherIsEnum = leftIsEnum || rightIsEnum;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;
            JSBinaryOperator replacementOperator;

            if (LogicalOperators.Contains(boe.Operator))
            {
                if (eitherIsEnum)
                {
                    if (leftIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Left, null, true
                            );

                        boe.ReplaceChild(boe.Left, cast);
                    }

                    if (rightIsEnum)
                    {
                        var cast = JSInvocationExpression.InvokeMethod(
                            JS.valueOf(TypeSystem.Int32), boe.Right, null, true
                            );

                        boe.ReplaceChild(boe.Right, cast);
                    }
                }
            }
            else if (BitwiseOperators.Contains(boe.Operator))
            {
                var parentCast = ParentNode as JSCastExpression;
                if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType)))
                {
                    var cast = JSCastExpression.New(
                        boe, resultType, TypeSystem, true
                        );

                    ParentNode.ReplaceChild(boe, cast);
                    VisitReplacement(cast);
                }
            }
            else if (
                (assignmentOperator != null) &&
                ReverseCompoundAssignments.TryGetValue(assignmentOperator, out replacementOperator) &&
                leftIsEnum
                )
            {
                var replacement = new JSBinaryOperatorExpression(
                    JSOperator.Assignment, boe.Left,
                    JSCastExpression.New(
                        new JSBinaryOperatorExpression(
                            replacementOperator, boe.Left, boe.Right, TypeSystem.Int32
                            ), leftType, TypeSystem, true
                        ),
                    leftType
                    );

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Пример #15
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            bool isArithmetic = !(boe.Operator is JSAssignmentOperator);

            if (!isArithmetic && boe.Operator != JSOperator.Assignment && leftType.FullName == "System.Char")
            {
                JSBinaryOperator newOperator;
                if (boe.Operator == JSOperator.AddAssignment)
                {
                    newOperator = JSOperator.Add;
                }
                else if (boe.Operator == JSOperator.BitwiseAndAssignment)
                {
                    newOperator = JSOperator.BitwiseAnd;
                }
                else if (boe.Operator == JSOperator.BitwiseOrAssignment)
                {
                    newOperator = JSOperator.BitwiseOr;
                }
                else if (boe.Operator == JSOperator.BitwiseXorAssignment)
                {
                    newOperator = JSOperator.BitwiseXor;
                }
                else if (boe.Operator == JSOperator.DivideAssignment)
                {
                    newOperator = JSOperator.Divide;
                }
                else if (boe.Operator == JSOperator.MultiplyAssignment)
                {
                    newOperator = JSOperator.Multiply;
                }
                else if (boe.Operator == JSOperator.RemainderAssignment)
                {
                    newOperator = JSOperator.Remainder;
                }
                else if (boe.Operator == JSOperator.ShiftLeftAssignment)
                {
                    newOperator = JSOperator.ShiftLeft;
                }
                else if (boe.Operator == JSOperator.ShiftRightAssignment)
                {
                    newOperator = JSOperator.ShiftRight;
                }
                else if (boe.Operator == JSOperator.ShiftRightUnsignedAssignment)
                {
                    newOperator = JSOperator.ShiftRightUnsigned;
                }
                else if (boe.Operator == JSOperator.SubtractAssignment)
                {
                    newOperator = JSOperator.Subtract;
                }
                else
                {
                    throw new InvalidOperationException("Unknown assigment operator");
                }

                var newBoe = new JSBinaryOperatorExpression(JSOperator.Assignment, boe.Left,
                                                            new JSBinaryOperatorExpression(newOperator, boe.Left, boe.Right, boe.ActualType), boe.ActualType);
                ParentNode.ReplaceChild(boe, newBoe);
                VisitReplacement(newBoe);
                return;
            }

            if (boe.Operator == JSOperator.Assignment && (leftType.FullName == "System.Char") && (rightType.FullName != "System.Char"))
            {
                boe.ReplaceChild(boe.Right, CastToChar(boe.Right));
            }
            if (boe.Operator == JSOperator.Assignment && (leftType.FullName != "System.Char") && (rightType.FullName == "System.Char"))
            {
                boe.ReplaceChild(boe.Right, CastToInteger(boe.Right));
            }

            if ((leftType.FullName == "System.Char") && isArithmetic)
            {
                boe.ReplaceChild(boe.Left, CastToInteger(boe.Left));
            }

            if ((rightType.FullName == "System.Char") && isArithmetic)
            {
                boe.ReplaceChild(boe.Right, CastToInteger(boe.Right));
            }

            var parentInvocation = ParentNode as JSInvocationExpression;
            JSDotExpressionBase parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpressionBase : null;

            if (
                isArithmetic &&
                (boe.GetActualType(TypeSystem).FullName == "System.Char") &&
                !(
                    (parentInvocation != null) &&
                    (parentInvocationDot != null) &&
                    (parentInvocationDot.Target is JSStringIdentifier) &&
                    (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") &&
                    (parentInvocationDot.Member is JSFakeMethod) &&
                    (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode")
                    )
                )
            {
                var castBoe = CastToChar(boe);
                ParentNode.ReplaceChild(boe, castBoe);

                VisitReplacement(castBoe);
            }
            else
            {
                VisitChildren(boe);
            }
        }