Esempio n. 1
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var resultType       = boe.GetActualType(TypeSystem);
            var resultIsIntegral = TypeUtil.Is32BitIntegral(resultType);
            var resultIsPointer  = TypeUtil.IsPointer(resultType);

            JSExpression replacement;

            if (
                (resultIsIntegral) &&
                ((replacement = DeconstructMutationAssignment(ParentNode, boe, TypeSystem, resultType)) != null)
                )
            {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            if (boe.Operator == JSOperator.Assignment)
            {
                replacement = ConvertReadExpressionToWriteExpression(boe, TypeSystem);
                if (replacement != boe)
                {
                    ParentNode.ReplaceChild(boe, replacement);
                    VisitReplacement(replacement);
                    return;
                }
            }

            VisitChildren(boe);
        }
Esempio n. 2
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);
        }
Esempio n. 3
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var boeType   = boe.GetActualType(TypeSystem);
            var typeToken = WasmUtil.PickTypeKeyword(boeType);

            if (typeToken == null)
            {
                Console.WriteLine("Unhandled binary operator type {0}", boeType);
                return;
            }

            if (boe.Operator == JSOperator.Assignment)
            {
                Assign(boe.Left, boe.Right);
                return;
            }

            string keyword;

            if (!OperatorTable.TryGetValue(boe.Operator, out keyword))
            {
                Console.WriteLine("Unimplemented operator {0}", boe.Operator);
                return;
            }

            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);
            var leftSign  = TypeUtil.IsSigned(leftType);

            // HACK: Emit the argument type since we're comparing it
            if (boe.Operator is JSComparisonOperator)
            {
                typeToken = WasmUtil.PickTypeKeyword(leftType);
            }

            var signSuffix = "";

            if (leftSign.HasValue && TypeUtil.IsIntegral(leftType))
            {
                signSuffix = leftSign.Value
                    ? "s"
                    : "u";
            }

            var actualKeyword = string.Format(
                keyword + "." + typeToken,
                signSuffix
                );

            Formatter.WriteSExpr(
                actualKeyword,
                (_) => EmitArgumentList(_, new[] { boe.Left, boe.Right }, true),
                true, false
                );
        }
Esempio n. 4
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            JSPropertyAccess     pa;
            JSAssignmentOperator assignmentOperator;
            JSBinaryOperator     newOperator;

            if (
                IsPropertyAccess(boe, out pa) &&
                ((assignmentOperator = boe.Operator as JSAssignmentOperator) != null) &&
                IntroduceEnumCasts.ReverseCompoundAssignments.TryGetValue(assignmentOperator, out newOperator)
                )
            {
                // FIXME: Terrible hack
                var type         = pa.GetActualType(TypeSystem);
                var tempVariable = TemporaryVariable.ForFunction(
                    Stack.Last() as JSFunctionExpression, type
                    );
                var replacement = new JSCommaExpression(
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment, tempVariable,
                        new JSBinaryOperatorExpression(
                            newOperator,
                            new JSPropertyAccess(
                                pa.ThisReference, pa.Property, false,
                                pa.TypeQualified,
                                pa.OriginalType, pa.OriginalMethod,
                                pa.IsVirtualCall
                                ),
                            boe.Right, boe.GetActualType(TypeSystem)
                            ), type
                        ),
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment,
                        new JSPropertyAccess(
                            pa.ThisReference, pa.Property, true,
                            pa.TypeQualified,
                            pa.OriginalType, pa.OriginalMethod,
                            pa.IsVirtualCall
                            ), tempVariable, type
                        ),
                    tempVariable
                    );

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(boe);
            }
        }
        public void VisitNode (JSBinaryOperatorExpression boe) {
            JSPropertyAccess pa;
            JSAssignmentOperator assignmentOperator;
            JSBinaryOperator newOperator;

            if (
                IsPropertyAccess(boe, out pa) &&
                ((assignmentOperator = boe.Operator as JSAssignmentOperator) != null) &&
                IntroduceEnumCasts.ReverseCompoundAssignments.TryGetValue(assignmentOperator, out newOperator)
            ) {
                // FIXME: Terrible hack
                var type = pa.GetActualType(TypeSystem);
                var tempVariable = TemporaryVariable.ForFunction(
                    Stack.Last() as JSFunctionExpression, type
                );
                var replacement = new JSCommaExpression(
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment, tempVariable,
                        new JSBinaryOperatorExpression(
                            newOperator,
                            new JSPropertyAccess(
                                pa.ThisReference, pa.Property, false,
                                pa.TypeQualified, 
                                pa.OriginalType, pa.OriginalMethod, 
                                pa.IsVirtualCall
                            ), 
                            boe.Right, boe.GetActualType(TypeSystem)
                        ), type
                    ),
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment, 
                        new JSPropertyAccess(
                            pa.ThisReference, pa.Property, true, 
                            pa.TypeQualified,
                            pa.OriginalType, pa.OriginalMethod, 
                            pa.IsVirtualCall
                        ), tempVariable, type
                    ),
                    tempVariable
                );

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            } else {
                VisitChildren(boe);
            }
        }
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var resultType = boe.GetActualType(TypeSystem);
            var resultIsIntegral = TypeUtil.Is32BitIntegral(resultType);

            JSExpression replacement;

            if (
                resultIsIntegral &&
                ((replacement = DeconstructMutationAssignment(boe, TypeSystem, resultType)) != null)
            ) {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Esempio n. 7
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);
            }
        }
Esempio n. 8
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var resultType       = boe.GetActualType(TypeSystem);
            var resultIsIntegral = TypeUtil.Is32BitIntegral(resultType);

            JSExpression replacement;

            if (
                resultIsIntegral &&
                ((replacement = DeconstructMutationAssignment(boe, TypeSystem, resultType)) != null)
                )
            {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            VisitChildren(boe);
        }
Esempio n. 9
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);
            }
        }
Esempio n. 10
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);
        }
Esempio n. 11
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            TypeReference expectedType;

            try
            {
                // GetExpectedType can throw NoExpectedTypeException
                // Shouldn't it return null or something like a NoType instead?
                expectedType = boe.GetActualType(TypeSystem);
            }
            catch (NoExpectedTypeException)
            {
                expectedType = null;
            }

            var isLongExpression = IsLongOrULong(leftType) || IsLongOrULong(rightType);

            bool isUnsigned = (leftType.MetadataType == MetadataType.UInt64) || (rightType.MetadataType == MetadataType.UInt64);
            var  resultType = isUnsigned ? TypeSystem.UInt64 : TypeSystem.Int64;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;

            if ((assignmentOperator != null) && (isLongExpression))
            {
                if (assignmentOperator == JSOperator.Assignment)
                {
                    VisitChildren(boe);
                    return;
                }

                // Deconstruct the mutation assignment so we can insert the appropriate operator call.
                var replacement = IntroduceEnumCasts.DeconstructMutationAssignment(boe, TypeSystem, resultType);
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            }
            else if (isLongExpression)
            {
                var verb = GetVerb(boe.Operator);

                if (verb == null)
                {
                    throw new NotImplementedException("Int64 operator not yet supported: " + boe.Operator.Token);
                }

                JSIdentifier method = new JSFakeMethod(
                    verb, resultType,
                    new[] { leftType, rightType }, MethodTypeFactory
                    );

                var replacement = JSInvocationExpression
                                  .InvokeStatic(leftType, method, new[] { boe.Left, boe.Right }, true);

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            }
            else
            {
                VisitChildren(boe);
            }
        }
Esempio n. 12
0
        public void VisitNode (JSBinaryOperatorExpression boe) {
            if (!boe.CanSimplify) {
                VisitChildren(boe);
                return;
            }

            JSExpression left, right, nestedLeft;
            if (!JSReferenceExpression.TryDereference(JSIL, boe.Left, out left))
                left = boe.Left;
            if (!JSReferenceExpression.TryDereference(JSIL, boe.Right, out right))
                right = boe.Right;

            var nestedBoe = right as JSBinaryOperatorExpression;
            var isAssignment = (boe.Operator == JSOperator.Assignment);
            var leftNew = left as JSNewExpression;
            var rightNew = right as JSNewExpression;
            var leftVar = left as JSVariable;

            if (
                isAssignment && (nestedBoe != null) && 
                (left.IsConstant || (leftVar != null) || left is JSDotExpressionBase) &&
                !(ParentNode is JSVariableDeclarationStatement)
            ) {
                if (!nestedBoe.CanSimplify) {
                    VisitChildren(boe);
                    return;
                }

                JSUnaryOperator prefixOperator;
                JSAssignmentOperator compoundOperator;

                if (!JSReferenceExpression.TryDereference(JSIL, nestedBoe.Left, out nestedLeft))
                    nestedLeft = nestedBoe.Left;

                var rightLiteral = nestedBoe.Right as JSIntegerLiteral;
                var areEqual = left.Equals(nestedLeft);

                if (
                    areEqual &&
                    PrefixOperators.TryGetValue(nestedBoe.Operator, out prefixOperator) &&
                    (rightLiteral != null) && (rightLiteral.Value == 1)
                ) {
                    var newUoe = new JSUnaryOperatorExpression(
                        prefixOperator, boe.Left,
                        boe.GetActualType(TypeSystem)
                    );

                    ParentNode.ReplaceChild(boe, newUoe);
                    VisitReplacement(newUoe);

                    return;
                } else if (
                    areEqual && 
                    CompoundAssignments.TryGetValue(nestedBoe.Operator, out compoundOperator)
                ) {
                    var newBoe = new JSBinaryOperatorExpression(
                        compoundOperator, boe.Left, nestedBoe.Right,
                        boe.GetActualType(TypeSystem)
                    );

                    ParentNode.ReplaceChild(boe, newBoe);
                    VisitReplacement(newBoe);

                    return;
                }
            } else if (
                isAssignment && (leftNew != null) &&
                (rightNew != null)
            ) {
                // FIXME
                /*
                var rightType = rightNew.Type as JSDotExpressionBase;
                if (
                    (rightType != null) &&
                    (rightType.Member.Identifier == "CollectionInitializer")
                ) {
                    var newInitializer = new JSInitializerApplicationExpression(
                        boe.Left, new JSArrayExpression(
                            TypeSystem.Object,
                            rightNew.Arguments.ToArray()
                        )
                    );

                    ParentNode.ReplaceChild(boe, newInitializer);
                    VisitReplacement(newInitializer);

                    return;
                }
                */
            } else if (
                isAssignment && (leftVar != null) &&
                leftVar.IsThis
            ) {
                var leftType = leftVar.GetActualType(TypeSystem);
                if (!TypeUtil.IsStruct(leftType)) {
                    ParentNode.ReplaceChild(boe, new JSUntranslatableExpression(boe));

                    return;
                } else {
                    var newInvocation = JSInvocationExpression.InvokeStatic(
                        JSIL.CopyMembers, new[] { boe.Right, leftVar }
                    );

                    ParentNode.ReplaceChild(boe, newInvocation);
                    VisitReplacement(newInvocation);

                    return;
                }
            }

            VisitChildren(boe);
        }
Esempio n. 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);
        }
Esempio n. 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;

            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);
        }
Esempio n. 15
0
        public void VisitNode(JSBinaryOperatorExpression bop)
        {
            bool parens = true;
            bool needsTruncation = false, needsCast = false;

            if (ParentNode is JSIfStatement)
            {
                parens = false;
            }
            else if ((ParentNode is JSWhileLoop) && ((JSWhileLoop)ParentNode).Condition == bop)
            {
                parens = false;
            }
            else if ((ParentNode is JSDoLoop) && ((JSDoLoop)ParentNode).Condition == bop)
            {
                parens = false;
            }
            else if (ParentNode is JSForLoop)
            {
                var fl = (JSForLoop)ParentNode;
                if (
                    (fl.Condition == bop) ||
                    (fl.Increment.SelfAndChildrenRecursive.Any((n) => bop.Equals(n))) ||
                    (fl.Initializer.SelfAndChildrenRecursive.Any((n) => bop.Equals(n)))
                    )
                {
                    parens = false;
                }
            }
            else if ((ParentNode is JSSwitchStatement) && ((JSSwitchStatement)ParentNode).Condition == bop)
            {
                parens = false;
            }
            else if (
                (ParentNode is JSBinaryOperatorExpression) &&
                ((JSBinaryOperatorExpression)ParentNode).Operator == bop.Operator &&
                bop.Operator is JSLogicalOperator
                )
            {
                parens = false;
            }
            else if (ParentNode is JSVariableDeclarationStatement)
            {
                parens = false;
            }
            else if (ParentNode is JSExpressionStatement)
            {
                parens = false;
            }

            var leftType   = bop.Left.GetActualType(TypeSystem);
            var rightType  = bop.Right.GetActualType(TypeSystem);
            var resultType = bop.GetActualType(TypeSystem);

            // We need to perform manual truncation to maintain the semantics of C#'s division operator
            if ((bop.Operator == JSOperator.Divide))
            {
                needsTruncation =
                    (TypeUtil.IsIntegral(leftType) ||
                     TypeUtil.IsIntegral(rightType)) &&
                    TypeUtil.IsIntegral(resultType);
            }

            // Arithmetic on enum types needs a cast at the end.
            if (bop.Operator is JSArithmeticOperator)
            {
                if (TypeUtil.IsEnum(TypeUtil.StripNullable(resultType)))
                {
                    needsCast = true;
                }
            }

            if (needsTruncation)
            {
                if (bop.Operator is JSAssignmentOperator)
                {
                    throw new NotImplementedException("Truncation of assignment operations not implemented");
                }

                Output.WriteRaw("Math.floor");
            }
            else if (needsCast)
            {
                Output.WriteRaw("JSIL.Cast");
            }

            parens |= needsTruncation;
            parens |= needsCast;

            if (parens)
            {
                Output.LPar();
            }

            Visit(bop.Left);
            Output.Space();
            Output.WriteRaw(bop.Operator.Token);
            Output.Space();

            if (
                (bop.Operator is JSLogicalOperator) &&
                (Stack.OfType <JSBinaryOperatorExpression>().Skip(1).FirstOrDefault() != null)
                )
            {
                Output.NewLine();
            }

            Visit(bop.Right);

            if (needsCast)
            {
                Output.Comma();
                Output.Identifier(TypeUtil.StripNullable(resultType), ReferenceContext);
            }

            if (parens)
            {
                Output.RPar();
            }
        }
Esempio n. 16
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);
        }
Esempio n. 17
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var boeType   = boe.GetActualType(TypeSystem);
            var typeToken = WasmUtil.PickTypeKeyword(boeType);

            if (boe.Operator == JSOperator.Assignment)
            {
                Assign(boe.Left, boe.Right);
                return;
            }

            string keyword;

            if (!OperatorTable.TryGetValue(boe.Operator, out keyword))
            {
                Console.WriteLine("Unimplemented operator {0}", boe.Operator);
                return;
            }

            var leftType  = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);
            var leftSign  = TypeUtil.IsSigned(leftType);

            // HACK: Emit the argument type since we're comparing it
            if (boe.Operator is JSComparisonOperator)
            {
                typeToken = WasmUtil.PickTypeKeyword(leftType);
            }

            var signSuffix = "";

            if (
                (leftSign.HasValue && TypeUtil.IsIntegral(leftType)) ||
                // HACK
                (leftType.FullName == "System.Char")
                )
            {
                signSuffix = leftSign.GetValueOrDefault(true)
                    ? "_s"
                    : "_u";
            }
            else if (
                TypeUtil.IsPointer(leftType) ||
                TypeUtil.IsPointer(rightType)
                )
            {
                signSuffix = "_u";
            }

            var actualKeyword = string.Format(
                typeToken + "." + keyword,
                signSuffix
                );

            // HACK: wasm i64 shift takes i64 shift amount
            var right = boe.Right;

            if (
                (boe.Operator == JSOperator.ShiftLeft) ||
                (boe.Operator == JSOperator.ShiftRight)
                )
            {
                right = JSChangeTypeExpression.New(right, leftType, TypeSystem);
            }

            if (typeToken == null)
            {
                Console.WriteLine("Unhandled binary operator type {0} ({1})", boeType, boe);
                return;
            }

            Formatter.WriteSExpr(
                actualKeyword,
                (_) => EmitArgumentList(_, new[] { boe.Left, right }, true),
                true, false
                );
        }
Esempio n. 18
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);
        }
Esempio n. 19
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            JSExpression left, right, nestedLeft;

            if (!JSReferenceExpression.TryDereference(JSIL, boe.Left, out left))
            {
                left = boe.Left;
            }
            if (!JSReferenceExpression.TryDereference(JSIL, boe.Right, out right))
            {
                right = boe.Right;
            }

            var nestedBoe    = right as JSBinaryOperatorExpression;
            var isAssignment = (boe.Operator == JSOperator.Assignment);
            var leftNew      = left as JSNewExpression;
            var rightNew     = right as JSNewExpression;
            var leftVar      = left as JSVariable;

            if (
                isAssignment && (nestedBoe != null) &&
                (left.IsConstant || (leftVar != null) || left is JSDotExpressionBase) &&
                !(ParentNode is JSVariableDeclarationStatement)
                )
            {
                JSUnaryOperator      prefixOperator;
                JSAssignmentOperator compoundOperator;

                if (!JSReferenceExpression.TryDereference(JSIL, nestedBoe.Left, out nestedLeft))
                {
                    nestedLeft = nestedBoe.Left;
                }

                var rightLiteral = nestedBoe.Right as JSIntegerLiteral;
                var areEqual     = left.Equals(nestedLeft);

                if (
                    areEqual &&
                    PrefixOperators.TryGetValue(nestedBoe.Operator, out prefixOperator) &&
                    (rightLiteral != null) && (rightLiteral.Value == 1)
                    )
                {
                    var newUoe = new JSUnaryOperatorExpression(
                        prefixOperator, boe.Left,
                        boe.GetActualType(TypeSystem)
                        );

                    ParentNode.ReplaceChild(boe, newUoe);
                    VisitReplacement(newUoe);

                    return;
                }
                else if (
                    areEqual &&
                    CompoundAssignments.TryGetValue(nestedBoe.Operator, out compoundOperator)
                    )
                {
                    var newBoe = new JSBinaryOperatorExpression(
                        compoundOperator, boe.Left, nestedBoe.Right,
                        boe.GetActualType(TypeSystem)
                        );

                    ParentNode.ReplaceChild(boe, newBoe);
                    VisitReplacement(newBoe);

                    return;
                }
            }
            else if (
                isAssignment && (leftNew != null) &&
                (rightNew != null)
                )
            {
                var rightType = rightNew.Type as JSDotExpressionBase;
                if (
                    (rightType != null) &&
                    (rightType.Member.Identifier == "CollectionInitializer")
                    )
                {
                    var newInitializer = new JSInitializerApplicationExpression(
                        boe.Left, new JSArrayExpression(
                            TypeSystem.Object,
                            rightNew.Arguments.ToArray()
                            )
                        );

                    ParentNode.ReplaceChild(boe, newInitializer);
                    VisitReplacement(newInitializer);

                    return;
                }
            }
            else if (
                isAssignment && (leftVar != null) &&
                leftVar.IsThis
                )
            {
                var leftType = leftVar.GetActualType(TypeSystem);
                if (!TypeUtil.IsStruct(leftType))
                {
                    ParentNode.ReplaceChild(boe, new JSUntranslatableExpression(boe));

                    return;
                }
                else
                {
                    var newInvocation = JSInvocationExpression.InvokeStatic(
                        JSIL.CopyMembers, new[] { boe.Right, leftVar }
                        );

                    ParentNode.ReplaceChild(boe, newInvocation);
                    VisitReplacement(newInvocation);

                    return;
                }
            }

            VisitChildren(boe);
        }
Esempio n. 20
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);
            }
        }
Esempio n. 21
0
        public void VisitNode(JSBinaryOperatorExpression boe)
        {
            var leftType = boe.Left.GetActualType(TypeSystem);
            var rightType = boe.Right.GetActualType(TypeSystem);

            TypeReference expectedType;
            try
            {
                // GetExpectedType can throw NoExpectedTypeException
                // Shouldn't it return null or something like a NoType instead?
                expectedType = boe.GetActualType(TypeSystem);
            }
            catch (NoExpectedTypeException)
            {
                expectedType = null;
            }

            var isLongExpression = IsLongOrULong(leftType) || IsLongOrULong(rightType);

            bool isUnsigned = (leftType.MetadataType == MetadataType.UInt64) || (rightType.MetadataType == MetadataType.UInt64);
            var resultType = isUnsigned ? TypeSystem.UInt64 : TypeSystem.Int64;

            var assignmentOperator = boe.Operator as JSAssignmentOperator;
            if ((assignmentOperator != null) && (isLongExpression)) {
                if (assignmentOperator == JSOperator.Assignment) {
                    VisitChildren(boe);
                    return;
                }

                // Deconstruct the mutation assignment so we can insert the appropriate operator call.
                var replacement = IntroduceEnumCasts.DeconstructMutationAssignment(boe, TypeSystem, resultType);
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            } else if (isLongExpression) {
                var verb = GetVerb(boe.Operator);

                if (verb == null) {
                    throw new NotImplementedException("Int64 operator not yet supported: " + boe.Operator.Token);
                }

                JSIdentifier method = new JSFakeMethod(
                    verb, boe.Operator is JSComparisonOperator ? TypeSystem.Boolean : resultType, 
                    new[] { leftType, rightType }, MethodTypeFactory
                );

                var replacement = JSInvocationExpression
                    .InvokeStatic(leftType, method, new[] { boe.Left, boe.Right }, true);

                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
            } else {
                VisitChildren(boe);
            }
        }
        public void VisitNode (JSBinaryOperatorExpression boe) {
            var resultType = boe.GetActualType(TypeSystem);
            var resultIsIntegral = TypeUtil.Is32BitIntegral(resultType);
            var resultIsPointer = TypeUtil.IsPointer(resultType);

            JSExpression replacement;

            if (
                (resultIsIntegral) &&
                ((replacement = DeconstructMutationAssignment(ParentNode, boe, TypeSystem, resultType)) != null)
            ) {
                ParentNode.ReplaceChild(boe, replacement);
                VisitReplacement(replacement);
                return;
            }

            if (boe.Operator == JSOperator.Assignment)
            {
                replacement = ConvertReadExpressionToWriteExpression(boe, TypeSystem);
                if (replacement != boe)
                {
                    ParentNode.ReplaceChild(boe, replacement);
                    VisitReplacement(replacement);
                    return;
                }
            }

            VisitChildren(boe);
        }