Пример #1
0
        protected void VisitBinaryOperatorExpression()
        {
            BinaryOperatorExpression binaryOperatorExpression = this.BinaryOperatorExpression;

            if (this.Emitter.IsAsync && (
                    binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseAnd ||
                    binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseOr ||
                    binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalOr ||
                    binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalAnd
                    ) && this.GetAwaiters(binaryOperatorExpression).Length > 0)
            {
                if (this.Emitter.AsyncBlock.WrittenAwaitExpressions.Contains(binaryOperatorExpression))
                {
                    var index = System.Array.IndexOf(this.Emitter.AsyncBlock.AwaitExpressions, binaryOperatorExpression) + 1;
                    this.Write(JS.Vars.ASYNC_TASK_RESULT + index);
                }
                else
                {
                    var index = System.Array.IndexOf(this.Emitter.AsyncBlock.AwaitExpressions, binaryOperatorExpression) + 1;
                    this.WriteAsyncBinaryExpression(index);
                }

                return;
            }

            var  resolveOperator       = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression, this.Emitter);
            var  expectedType          = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression);
            bool isDecimalExpected     = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal             = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            bool isLongExpected        = Helpers.Is64Type(expectedType, this.Emitter.Resolver);
            bool isLong                = Helpers.Is64Type(resolveOperator.Type, this.Emitter.Resolver);
            OperatorResolveResult orr  = resolveOperator as OperatorResolveResult;
            var    leftResolverResult  = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left, this.Emitter);
            var    rightResolverResult = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right, this.Emitter);
            var    charToString        = -1;
            string variable            = null;
            bool   leftIsNull          = this.BinaryOperatorExpression.Left is NullReferenceExpression;
            bool   rightIsNull         = this.BinaryOperatorExpression.Right is NullReferenceExpression;
            bool   isUint              = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt16) ||
                                         resolveOperator.Type.IsKnownType(KnownTypeCode.UInt32) ||
                                         resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64);

            var isFloatResult    = Helpers.IsFloatType(resolveOperator.Type, this.Emitter.Resolver);
            var leftExpected     = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left);
            var rightExpected    = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right);
            var strictNullChecks = this.Emitter.AssemblyInfo.StrictNullChecks;

            if (orr != null && orr.Type.IsKnownType(KnownTypeCode.String))
            {
                for (int i = 0; i < orr.Operands.Count; i++)
                {
                    var crr = orr.Operands[i] as ConversionResolveResult;
                    if (crr != null && crr.Input.Type.IsKnownType(KnownTypeCode.Char))
                    {
                        charToString = i;
                    }
                }
            }

            if (resolveOperator is ConstantResolveResult)
            {
                this.WriteScript(((ConstantResolveResult)resolveOperator).ConstantValue);
                return;
            }

            var resultIsString   = expectedType.IsKnownType(KnownTypeCode.String) || resolveOperator.Type.IsKnownType(KnownTypeCode.String);
            var isStringConcat   = resultIsString && binaryOperatorExpression.Operator == BinaryOperatorType.Add;
            var toStringForLeft  = false;
            var toStringForRight = false;

            var  parentBinary   = binaryOperatorExpression.Parent as BinaryOperatorExpression;
            bool parentIsString = resultIsString && parentBinary != null && parentBinary.Operator == BinaryOperatorType.Add;

            if (parentIsString)
            {
                var parentResolveOperator = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Parent, this.Emitter) as OperatorResolveResult;

                if (parentResolveOperator != null && parentResolveOperator.UserDefinedOperatorMethod != null || BinaryOperatorBlock.IsOperatorSimple(parentBinary, this.Emitter))
                {
                    parentIsString = false;
                }
            }

            bool isSimpleConcat = isStringConcat && BinaryOperatorBlock.IsOperatorSimple(binaryOperatorExpression, this.Emitter);

            if (charToString == -1 && isStringConcat && !leftResolverResult.Type.IsKnownType(KnownTypeCode.String))
            {
                toStringForLeft = true;
            }

            if (charToString == -1 && isStringConcat && !rightResolverResult.Type.IsKnownType(KnownTypeCode.String))
            {
                toStringForRight = true;
            }

            if (!isStringConcat && (Helpers.IsDecimalType(leftResolverResult.Type, this.Emitter.Resolver) || Helpers.IsDecimalType(rightResolverResult.Type, this.Emitter.Resolver)))
            {
                isDecimal         = true;
                isDecimalExpected = true;
            }

            if (isDecimal && isDecimalExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing)
            {
                this.HandleDecimal(resolveOperator);
                return;
            }

            var isLeftLong  = Helpers.Is64Type(leftExpected, this.Emitter.Resolver);
            var isRightLong = Helpers.Is64Type(rightExpected, this.Emitter.Resolver);

            if (!isLeftLong && !isRightLong)
            {
                if (leftExpected.Kind == TypeKind.Enum && Helpers.Is64Type(leftExpected.GetDefinition().EnumUnderlyingType, this.Emitter.Resolver))
                {
                    isLeftLong = true;
                }

                if (rightExpected.Kind == TypeKind.Enum && Helpers.Is64Type(rightExpected.GetDefinition().EnumUnderlyingType, this.Emitter.Resolver))
                {
                    isRightLong = true;
                }
            }

            if (!(resultIsString && binaryOperatorExpression.Operator == BinaryOperatorType.Add) && (isLeftLong || isRightLong))
            {
                isLong         = true;
                isLongExpected = true;
            }

            if (isLong && isLongExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing)
            {
                if (!isFloatResult || binaryOperatorExpression.Operator == BinaryOperatorType.Divide && isLeftLong)
                {
                    this.HandleLong(resolveOperator, isUint);
                    return;
                }
            }

            var delegateOperator = false;

            if (this.ResolveOperator(binaryOperatorExpression, orr))
            {
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality || binaryOperatorExpression.Operator == BinaryOperatorType.InEquality)
            {
                if (leftIsNull || rightIsNull)
                {
                    this.WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult);

                    if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality)
                    {
                        this.Write(strictNullChecks ? " === " : " == ");
                    }
                    else
                    {
                        this.Write(strictNullChecks ? " !== " : " != ");
                    }

                    this.WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult);
                    return;
                }
            }

            var insideOverflowContext = ConversionBlock.InsideOverflowContext(this.Emitter, binaryOperatorExpression);

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Divide && this.Emitter.Rules.Integer == IntegerRule.Managed &&
                !(this.Emitter.IsJavaScriptOverflowMode && !insideOverflowContext) &&
                (
                    (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||

                    (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), this.Emitter.Resolver))
                ))
            {
                this.Write(JS.Types.BRIDGE_INT + "." + JS.Funcs.Math.DIV + "(");
                this.WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult);
                this.Write(", ");
                this.WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult);
                this.Write(")");
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Multiply && this.Emitter.Rules.Integer == IntegerRule.Managed &&
                !(this.Emitter.IsJavaScriptOverflowMode && !insideOverflowContext) &&
                (
                    (Helpers.IsInteger32Type(leftResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsInteger32Type(rightResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsInteger32Type(resolveOperator.Type, this.Emitter.Resolver)) ||

                    (Helpers.IsInteger32Type(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), this.Emitter.Resolver) &&
                     Helpers.IsInteger32Type(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), this.Emitter.Resolver) &&
                     Helpers.IsInteger32Type(resolveOperator.Type, this.Emitter.Resolver))
                ))
            {
                isUint = NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.UInt32);
                this.Write(JS.Types.BRIDGE_INT + "." + (isUint ? JS.Funcs.Math.UMUL : JS.Funcs.Math.MUL) + "(");
                this.WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult);
                this.Write(", ");
                this.WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult);

                if (ConversionBlock.IsInCheckedContext(this.Emitter, this.BinaryOperatorExpression))
                {
                    this.Write(", 1");
                }

                this.Write(")");
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Add ||
                binaryOperatorExpression.Operator == BinaryOperatorType.Subtract)
            {
                var add = binaryOperatorExpression.Operator == BinaryOperatorType.Add;

                if (expectedType.Kind == TypeKind.Delegate || this.Emitter.Validator.IsDelegateOrLambda(leftResolverResult) && this.Emitter.Validator.IsDelegateOrLambda(rightResolverResult))
                {
                    delegateOperator = true;
                    this.Write(add ? JS.Funcs.BRIDGE_COMBINE : JS.Funcs.BRIDGE_REMOVE);
                    this.WriteOpenParentheses();
                }
            }

            this.NullStringCheck = isStringConcat && !parentIsString && isSimpleConcat;
            if (isStringConcat && !parentIsString && !isSimpleConcat)
            {
                this.Write(JS.Types.System.String.CONCAT);
                this.WriteOpenParentheses();
            }

            bool nullable     = orr != null && orr.IsLiftedOperator;
            bool isCoalescing = (this.Emitter.AssemblyInfo.StrictNullChecks ||
                                 NullableType.IsNullable(leftResolverResult.Type) ||
                                 leftResolverResult.Type.IsKnownType(KnownTypeCode.String) ||
                                 leftResolverResult.Type.IsKnownType(KnownTypeCode.Object)
                                 ) && binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing;
            string root        = JS.Types.SYSTEM_NULLABLE + ".";
            bool   special     = nullable;
            bool   rootSpecial = nullable;
            bool   isBool      = NullableType.IsNullable(resolveOperator.Type) ? NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.Boolean) : resolveOperator.Type.IsKnownType(KnownTypeCode.Boolean);
            bool   toBool      = isBool && !rootSpecial && !delegateOperator && (binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseAnd || binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseOr);
            bool   isRefEquals = !isCoalescing && !strictNullChecks &&
                                 (binaryOperatorExpression.Operator == BinaryOperatorType.InEquality || binaryOperatorExpression.Operator == BinaryOperatorType.Equality) &&
                                 leftExpected.IsReferenceType.HasValue && leftExpected.IsReferenceType.Value &&
                                 rightExpected.IsReferenceType.HasValue && rightExpected.IsReferenceType.Value;

            if (rootSpecial)
            {
                this.Write(root);
            }
            else if (!isRefEquals)
            {
                if (isCoalescing)
                {
                    this.Write("(");
                    variable = this.GetTempVarName();
                    this.Write(variable);
                    this.Write(" = ");
                }
                else if (charToString == 0)
                {
                    this.Write(JS.Funcs.STRING_FROMCHARCODE + "(");
                }

                if (toBool)
                {
                    this.Write("!!(");
                }

                this.WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult, isCoalescing);

                if (isCoalescing)
                {
                    this.Write(", ");
                    this.Write(variable);

                    this.Write(strictNullChecks ? " !== null" : " != null");

                    this.Write(" ? ");

                    ConversionBlock.expressionMap.Add(binaryOperatorExpression.Left, variable);
                    //this.Write(variable);
                    binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
                    ConversionBlock.expressionMap.Remove(binaryOperatorExpression.Left);
                }
                else if (charToString == 0)
                {
                    this.Write(")");
                }
            }

            if (isRefEquals)
            {
                if (binaryOperatorExpression.Operator == BinaryOperatorType.InEquality)
                {
                    this.Write("!");
                }
                this.Write(JS.Funcs.BRIDGE_REFERENCEEQUALS);
                special = true;
            }

            if (!delegateOperator && (!isStringConcat || isSimpleConcat))
            {
                if (!special)
                {
                    this.WriteSpace();
                }

                switch (binaryOperatorExpression.Operator)
                {
                case BinaryOperatorType.Add:
                    this.Write(rootSpecial ? JS.Funcs.Math.ADD : "+");
                    break;

                case BinaryOperatorType.BitwiseAnd:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? JS.Funcs.Math.AND : "&");
                    }
                    else
                    {
                        this.Write(rootSpecial ? JS.Funcs.Math.BAND : "&");
                    }

                    break;

                case BinaryOperatorType.BitwiseOr:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? JS.Funcs.Math.OR : "|");
                    }
                    else
                    {
                        this.Write(rootSpecial ? JS.Funcs.Math.BOR : "|");
                    }
                    break;

                case BinaryOperatorType.ConditionalAnd:
                    this.Write(rootSpecial ? JS.Funcs.Math.AND : "&&");
                    break;

                case BinaryOperatorType.NullCoalescing:
                    this.Write(isCoalescing ? ":" : "||");
                    break;

                case BinaryOperatorType.ConditionalOr:
                    this.Write(rootSpecial ? JS.Funcs.Math.OR : "||");
                    break;

                case BinaryOperatorType.Divide:
                    this.Write(rootSpecial ? JS.Funcs.Math.DIV : "/");
                    break;

                case BinaryOperatorType.Equality:
                    if (!isRefEquals)
                    {
                        this.Write(rootSpecial ? "eq" : "===");
                    }

                    break;

                case BinaryOperatorType.ExclusiveOr:
                    this.Write(rootSpecial ? JS.Funcs.Math.XOR : "^");
                    break;

                case BinaryOperatorType.GreaterThan:
                    this.Write(rootSpecial ? JS.Funcs.Math.GT : ">");
                    break;

                case BinaryOperatorType.GreaterThanOrEqual:
                    this.Write(rootSpecial ? JS.Funcs.Math.GTE : ">=");
                    break;

                case BinaryOperatorType.InEquality:
                    if (!isRefEquals)
                    {
                        this.Write(rootSpecial ? "neq" : "!==");
                    }
                    break;

                case BinaryOperatorType.LessThan:
                    this.Write(rootSpecial ? JS.Funcs.Math.LT : "<");
                    break;

                case BinaryOperatorType.LessThanOrEqual:
                    this.Write(rootSpecial ? JS.Funcs.Math.LTE : "<=");
                    break;

                case BinaryOperatorType.Modulus:
                    this.Write(rootSpecial ? JS.Funcs.Math.MOD : "%");
                    break;

                case BinaryOperatorType.Multiply:
                    this.Write(rootSpecial ? JS.Funcs.Math.MUL : "*");
                    break;

                case BinaryOperatorType.ShiftLeft:
                    this.Write(rootSpecial ? JS.Funcs.Math.SL : "<<");
                    break;

                case BinaryOperatorType.ShiftRight:
                    if (isUint)
                    {
                        this.Write(rootSpecial ? JS.Funcs.Math.SRR : ">>>");
                    }
                    else
                    {
                        this.Write(rootSpecial ? JS.Funcs.Math.SR : ">>");
                    }

                    break;

                case BinaryOperatorType.Subtract:
                    this.Write(rootSpecial ? JS.Funcs.Math.SUB : "-");
                    break;

                default:
                    throw new EmitterException(binaryOperatorExpression, "Unsupported binary operator: " + binaryOperatorExpression.Operator.ToString());
                }
            }
            else
            {
                this.WriteComma();
            }

            if (special)
            {
                this.WriteOpenParentheses();
                if (charToString == 0)
                {
                    this.Write(JS.Funcs.STRING_FROMCHARCODE + "(");
                }

                this.WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult);

                if (charToString == 0)
                {
                    this.Write(")");
                }

                this.WriteComma();
            }
            else if (!delegateOperator && (!isStringConcat || isSimpleConcat))
            {
                this.WriteSpace();
            }

            if (charToString == 1)
            {
                this.Write(JS.Funcs.STRING_FROMCHARCODE + "(");
            }

            this.WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult);

            if (toBool)
            {
                this.WriteCloseParentheses();
            }

            if (charToString == 1 || isCoalescing)
            {
                this.WriteCloseParentheses();
            }

            if (delegateOperator || special || isStringConcat && !parentIsString && !isSimpleConcat)
            {
                this.WriteCloseParentheses();
            }
        }
Пример #2
0
        protected void VisitBinaryOperatorExpression()
        {
            BinaryOperatorExpression binaryOperatorExpression = this.BinaryOperatorExpression;
            var  resolveOperator       = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression, this.Emitter);
            var  expectedType          = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression);
            bool isDecimalExpected     = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal             = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            bool isLongExpected        = Helpers.Is64Type(expectedType, this.Emitter.Resolver);
            bool isLong                = Helpers.Is64Type(resolveOperator.Type, this.Emitter.Resolver);
            OperatorResolveResult orr  = resolveOperator as OperatorResolveResult;
            var    leftResolverResult  = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left, this.Emitter);
            var    rightResolverResult = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right, this.Emitter);
            var    charToString        = -1;
            string variable            = null;
            bool   leftIsNull          = this.BinaryOperatorExpression.Left is NullReferenceExpression;
            bool   rightIsNull         = this.BinaryOperatorExpression.Right is NullReferenceExpression;
            bool   isUint              = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt16) ||
                                         resolveOperator.Type.IsKnownType(KnownTypeCode.UInt32) ||
                                         resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64);

            if ((leftIsNull || rightIsNull) && (binaryOperatorExpression.Operator == BinaryOperatorType.Equality || binaryOperatorExpression.Operator == BinaryOperatorType.InEquality))
            {
                if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality)
                {
                    this.Write("!");
                }

                this.Write("Bridge.hasValue");

                this.WriteOpenParentheses();

                if (leftIsNull)
                {
                    binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);
                }
                else
                {
                    binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
                }

                this.WriteCloseParentheses();
                return;
            }

            if (orr != null && orr.Type.IsKnownType(KnownTypeCode.String))
            {
                for (int i = 0; i < orr.Operands.Count; i++)
                {
                    var crr = orr.Operands[i] as ConversionResolveResult;
                    if (crr != null && crr.Input.Type.IsKnownType(KnownTypeCode.Char))
                    {
                        charToString = i;
                    }
                }
            }

            if (resolveOperator is ConstantResolveResult)
            {
                this.WriteScript(((ConstantResolveResult)resolveOperator).ConstantValue);
                return;
            }

            if (!((expectedType.IsKnownType(KnownTypeCode.String) || resolveOperator.Type.IsKnownType(KnownTypeCode.String)) && binaryOperatorExpression.Operator == BinaryOperatorType.Add) && (Helpers.IsDecimalType(leftResolverResult.Type, this.Emitter.Resolver) || Helpers.IsDecimalType(rightResolverResult.Type, this.Emitter.Resolver)))
            {
                isDecimal         = true;
                isDecimalExpected = true;
            }

            if (isDecimal && isDecimalExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing)
            {
                this.HandleDecimal(resolveOperator);
                return;
            }

            var isFloatResult = Helpers.IsFloatType(resolveOperator.Type, this.Emitter.Resolver);
            var leftExpected  = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left);
            var rightExpected = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right);
            var isLeftLong    = Helpers.Is64Type(leftExpected, this.Emitter.Resolver);
            var isRightLong   = Helpers.Is64Type(rightExpected, this.Emitter.Resolver);

            if (!((expectedType.IsKnownType(KnownTypeCode.String) || resolveOperator.Type.IsKnownType(KnownTypeCode.String)) && binaryOperatorExpression.Operator == BinaryOperatorType.Add) && (isLeftLong || isRightLong))
            {
                isLong         = true;
                isLongExpected = true;
            }

            if (isLong && isLongExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing)
            {
                if (!isFloatResult || binaryOperatorExpression.Operator == BinaryOperatorType.Divide && isLeftLong)
                {
                    this.HandleLong(resolveOperator, isUint);
                    return;
                }
            }

            var delegateOperator = false;

            if (this.ResolveOperator(binaryOperatorExpression, orr))
            {
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Divide &&
                !(this.Emitter.IsJavaScriptOverflowMode && !ConversionBlock.InsideOverflowContext(this.Emitter, binaryOperatorExpression)) &&
                (
                    (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||

                    (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), this.Emitter.Resolver))
                ))
            {
                this.Write("Bridge.Int.div(");
                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
                this.Write(", ");
                binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);
                this.Write(")");
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Add ||
                binaryOperatorExpression.Operator == BinaryOperatorType.Subtract)
            {
                var add = binaryOperatorExpression.Operator == BinaryOperatorType.Add;

                if (this.Emitter.Validator.IsDelegateOrLambda(leftResolverResult) && this.Emitter.Validator.IsDelegateOrLambda(rightResolverResult))
                {
                    delegateOperator = true;
                    this.Write(Bridge.Translator.Emitter.ROOT + "." + (add ? Bridge.Translator.Emitter.DELEGATE_COMBINE : Bridge.Translator.Emitter.DELEGATE_REMOVE));
                    this.WriteOpenParentheses();
                }
            }

            bool   nullable     = orr != null && orr.IsLiftedOperator;
            bool   isCoalescing = binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing;
            string root         = Bridge.Translator.Emitter.ROOT + ".Nullable.";
            bool   special      = nullable;
            bool   rootSpecial  = nullable;
            bool   isBool       = NullableType.IsNullable(resolveOperator.Type) ? NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.Boolean) : resolveOperator.Type.IsKnownType(KnownTypeCode.Boolean);
            bool   toBool       = isBool && !rootSpecial && !delegateOperator && (binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseAnd || binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseOr);

            if (rootSpecial)
            {
                this.Write(root);
            }
            else
            {
                if (isCoalescing)
                {
                    this.Write("(");
                    variable = this.GetTempVarName();
                    this.Write(variable);
                    this.Write(" = ");
                }
                else if (charToString == 0)
                {
                    this.Write("String.fromCharCode(");
                }

                if (toBool)
                {
                    this.Write("!!(");
                }

                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);

                if (isCoalescing)
                {
                    this.Write(", Bridge.hasValue(");
                    this.Write(variable);
                    this.Write(") ? ");
                    this.Write(variable);
                }
                else if (charToString == 0)
                {
                    this.Write(")");
                }
            }

            if (!delegateOperator)
            {
                if (!special)
                {
                    this.WriteSpace();
                }

                switch (binaryOperatorExpression.Operator)
                {
                case BinaryOperatorType.Add:
                    this.Write(rootSpecial ? "add" : "+");
                    break;

                case BinaryOperatorType.BitwiseAnd:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? "and" : "&");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "band" : "&");
                    }

                    break;

                case BinaryOperatorType.BitwiseOr:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? "or" : "|");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "bor" : "|");
                    }
                    break;

                case BinaryOperatorType.ConditionalAnd:
                    this.Write(rootSpecial ? "and" : "&&");
                    break;

                case BinaryOperatorType.NullCoalescing:
                    this.Write(":");
                    break;

                case BinaryOperatorType.ConditionalOr:
                    this.Write(rootSpecial ? "or" : "||");
                    break;

                case BinaryOperatorType.Divide:
                    this.Write(rootSpecial ? "div" : "/");
                    break;

                case BinaryOperatorType.Equality:
                    this.Write(rootSpecial ? "eq" : "===");
                    break;

                case BinaryOperatorType.ExclusiveOr:
                    this.Write(rootSpecial ? "xor" : "^");
                    break;

                case BinaryOperatorType.GreaterThan:
                    this.Write(rootSpecial ? "gt" : ">");
                    break;

                case BinaryOperatorType.GreaterThanOrEqual:
                    this.Write(rootSpecial ? "gte" : ">=");
                    break;

                case BinaryOperatorType.InEquality:
                    this.Write(rootSpecial ? "neq" : "!==");
                    break;

                case BinaryOperatorType.LessThan:
                    this.Write(rootSpecial ? "lt" : "<");
                    break;

                case BinaryOperatorType.LessThanOrEqual:
                    this.Write(rootSpecial ? "lte" : "<=");
                    break;

                case BinaryOperatorType.Modulus:
                    this.Write(rootSpecial ? "mod" : "%");
                    break;

                case BinaryOperatorType.Multiply:
                    this.Write(rootSpecial ? "mul" : "*");
                    break;

                case BinaryOperatorType.ShiftLeft:
                    this.Write(rootSpecial ? "sl" : "<<");
                    break;

                case BinaryOperatorType.ShiftRight:
                    if (isUint)
                    {
                        this.Write(rootSpecial ? "srr" : ">>>");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "sr" : ">>");
                    }

                    break;

                case BinaryOperatorType.Subtract:
                    this.Write(rootSpecial ? "sub" : "-");
                    break;

                default:
                    throw new EmitterException(binaryOperatorExpression, "Unsupported binary operator: " + binaryOperatorExpression.Operator.ToString());
                }
            }
            else
            {
                this.WriteComma();
            }

            if (special)
            {
                this.WriteOpenParentheses();
                if (charToString == 0)
                {
                    this.Write("String.fromCharCode(");
                }

                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);

                if (charToString == 0)
                {
                    this.Write(")");
                }

                this.WriteComma();
            }
            else
            {
                this.WriteSpace();
            }

            if (charToString == 1)
            {
                this.Write("String.fromCharCode(");
            }

            binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);

            if (toBool)
            {
                this.WriteCloseParentheses();
            }

            if (charToString == 1 || isCoalescing)
            {
                this.WriteCloseParentheses();
            }

            if (delegateOperator || special)
            {
                this.WriteCloseParentheses();
            }
        }
Пример #3
0
        private static void NarrowingNumericOrEnumerationConversion(ConversionBlock block, Expression expression, IType targetType, bool fromFloatingPoint, bool isChecked, bool isNullable, bool isExplicit = true)
        {
            if (block.Emitter.IsJavaScriptOverflowMode && !InsideOverflowContext(block.Emitter, expression))
            {
                return;
            }

            var binaryOperatorExpression = expression as BinaryOperatorExpression;

            if (binaryOperatorExpression != null)
            {
                var rr = block.Emitter.Resolver.ResolveNode(expression, block.Emitter);
                var leftResolverResult  = block.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left, block.Emitter);
                var rightResolverResult = block.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right, block.Emitter);
                if (rr != null)
                {
                    if (binaryOperatorExpression.Operator == BinaryOperatorType.Multiply &&
                        !(block.Emitter.IsJavaScriptOverflowMode ||
                          ConversionBlock.InsideOverflowContext(block.Emitter, binaryOperatorExpression)) &&
                        (
                            (Helpers.IsInteger32Type(leftResolverResult.Type, block.Emitter.Resolver) &&
                             Helpers.IsInteger32Type(rightResolverResult.Type, block.Emitter.Resolver) &&
                             Helpers.IsInteger32Type(rr.Type, block.Emitter.Resolver)) ||

                            (Helpers.IsInteger32Type(block.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), block.Emitter.Resolver) &&
                             Helpers.IsInteger32Type(block.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), block.Emitter.Resolver) &&
                             Helpers.IsInteger32Type(rr.Type, block.Emitter.Resolver))
                        ))
                    {
                        return;
                    }
                }
            }

            var assignmentExpression = expression as AssignmentExpression;

            if (assignmentExpression != null)
            {
                var leftResolverResult  = block.Emitter.Resolver.ResolveNode(assignmentExpression.Left, block.Emitter);
                var rightResolverResult = block.Emitter.Resolver.ResolveNode(assignmentExpression.Right, block.Emitter);
                var rr = block.Emitter.Resolver.ResolveNode(assignmentExpression, block.Emitter);

                if (assignmentExpression.Operator == AssignmentOperatorType.Multiply &&
                    !(block.Emitter.IsJavaScriptOverflowMode ||
                      ConversionBlock.InsideOverflowContext(block.Emitter, assignmentExpression)) &&
                    (
                        (Helpers.IsInteger32Type(leftResolverResult.Type, block.Emitter.Resolver) &&
                         Helpers.IsInteger32Type(rightResolverResult.Type, block.Emitter.Resolver) &&
                         Helpers.IsInteger32Type(rr.Type, block.Emitter.Resolver)) ||

                        (Helpers.IsInteger32Type(
                             block.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Left),
                             block.Emitter.Resolver) &&
                         Helpers.IsInteger32Type(
                             block.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Right),
                             block.Emitter.Resolver) &&
                         Helpers.IsInteger32Type(rr.Type, block.Emitter.Resolver))
                    ))
                {
                    return;
                }
            }

            if (isChecked)
            {
                block.Write(JS.Types.BRIDGE_INT + ".check(");

                if (fromFloatingPoint)
                {
                    block.Write(JS.Types.BRIDGE_INT + ".trunc");
                    block.WriteOpenParentheses();
                }

                //expression.AcceptVisitor(block.Emitter);

                if (fromFloatingPoint)
                {
                    block.AfterOutput += ")";
                }

                block.AfterOutput += ", ";
                block.AfterOutput += BridgeTypes.ToJsName(targetType, block.Emitter);
                block.AfterOutput += ")";
            }
            else
            {
                if (isNullable || fromFloatingPoint)
                {
                    targetType = NullableType.IsNullable(targetType) ? NullableType.GetUnderlyingType(targetType) : targetType;
                    string action = null;
                    if (targetType.IsKnownType(KnownTypeCode.Char))
                    {
                        action = "clipu16";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.SByte))
                    {
                        action = "clip8";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Byte))
                    {
                        action = "clipu8";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Int16))
                    {
                        action = "clip16";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.UInt16))
                    {
                        action = "clipu16";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Int32))
                    {
                        action = "clip32";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.UInt32))
                    {
                        action = "clipu32";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Int64))
                    {
                        action = "clip64";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.UInt64))
                    {
                        action = "clipu64";
                    }
                    else
                    {
                        throw new ArgumentException("Can not narrow to " + targetType, "targetType");
                    }

                    block.Write(JS.Types.BRIDGE_INT + ".");
                    block.Write(action);
                    block.Write("(");
                    block.AfterOutput += ")";
                }
                else
                {
                    var skipOuterWrap = (expression.Parent is VariableInitializer) ||
                                        (expression.Parent is AssignmentExpression) ||
                                        targetType.IsKnownType(KnownTypeCode.Int64) ||
                                        targetType.IsKnownType(KnownTypeCode.UInt64) ||
                                        targetType.IsKnownType(KnownTypeCode.Int16) ||
                                        targetType.IsKnownType(KnownTypeCode.SByte);

                    bool skipInnerWrap = false;

                    var  rr             = block.Emitter.Resolver.ResolveNode(expression is CastExpression ? ((CastExpression)expression).Expression : expression, block.Emitter);
                    var  memberTargetrr = rr as MemberResolveResult;
                    bool isField        = memberTargetrr != null && memberTargetrr.Member is IField &&
                                          (memberTargetrr.TargetResult is ThisResolveResult ||
                                           memberTargetrr.TargetResult is LocalResolveResult);

                    if (rr is ThisResolveResult || rr is LocalResolveResult || rr is ConstantResolveResult || isField)
                    {
                        skipInnerWrap = true;
                    }

                    if (!skipOuterWrap)
                    {
                        block.WriteOpenParentheses();
                    }

                    if (targetType.IsKnownType(KnownTypeCode.Char))
                    {
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " & 65535";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.SByte))
                    {
                        block.Write(JS.Types.BRIDGE_INT + ".sxb(");
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " & 255)";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Byte))
                    {
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " & 255";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Int16))
                    {
                        block.Write(JS.Types.BRIDGE_INT + ".sxs(");
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " & 65535)";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.UInt16))
                    {
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " & 65535";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Int32))
                    {
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " | 0";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.UInt32))
                    {
                        if (!skipInnerWrap)
                        {
                            block.WriteOpenParentheses();
                            block.AfterOutput += ")";
                        }
                        block.AfterOutput += " >>> 0";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.Int64))
                    {
                        block.Write(JS.Types.BRIDGE_INT + ".clip64(");
                        block.AfterOutput += ")";
                    }
                    else if (targetType.IsKnownType(KnownTypeCode.UInt64))
                    {
                        block.Write(JS.Types.BRIDGE_INT + ".clipu64(");
                        block.AfterOutput += ")";
                    }
                    else
                    {
                        throw new ArgumentException("Can not narrow to " + targetType, "targetType");
                    }

                    if (!skipOuterWrap)
                    {
                        block.AfterOutput += ")";
                    }
                }
            }
        }
Пример #4
0
        protected void VisitAssignmentExpression()
        {
            AssignmentExpression assignmentExpression = this.AssignmentExpression;
            var    oldAssigment     = this.Emitter.IsAssignment;
            var    oldAssigmentType = this.Emitter.AssignmentType;
            string variable         = null;

            bool needReturnValue = !(assignmentExpression.Parent is ExpressionStatement);

            if (needReturnValue && assignmentExpression.Parent is LambdaExpression)
            {
                var lambdarr = this.Emitter.Resolver.ResolveNode(assignmentExpression.Parent, this.Emitter) as LambdaResolveResult;

                if (lambdarr != null && lambdarr.ReturnType.Kind == TypeKind.Void)
                {
                    needReturnValue = false;
                }
            }

            var  delegateAssigment = false;
            bool isEvent           = false;
            var  initCount         = this.Emitter.Writers.Count;

            var asyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

            this.WriteAwaiters(assignmentExpression.Left);
            this.WriteAwaiters(assignmentExpression.Right);

            var  leftResolverResult  = this.Emitter.Resolver.ResolveNode(assignmentExpression.Left, this.Emitter);
            var  rightResolverResult = this.Emitter.Resolver.ResolveNode(assignmentExpression.Right, this.Emitter);
            var  rr                = this.Emitter.Resolver.ResolveNode(assignmentExpression, this.Emitter);
            var  orr               = rr as OperatorResolveResult;
            bool isDecimal         = Helpers.IsDecimalType(rr.Type, this.Emitter.Resolver);
            bool isLong            = Helpers.Is64Type(rr.Type, this.Emitter.Resolver);
            var  expectedType      = this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression);
            bool isDecimalExpected = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isLongExpected    = Helpers.Is64Type(expectedType, this.Emitter.Resolver);
            bool isUserOperator    = this.IsUserOperator(orr);

            bool isUint = rr.Type.IsKnownType(KnownTypeCode.UInt16) ||
                          rr.Type.IsKnownType(KnownTypeCode.UInt32) ||
                          rr.Type.IsKnownType(KnownTypeCode.UInt64);

            var charToString = -1;

            if (orr != null && orr.Type.IsKnownType(KnownTypeCode.String))
            {
                for (int i = 0; i < orr.Operands.Count; i++)
                {
                    var crr = orr.Operands[i] as ConversionResolveResult;
                    if (crr != null && crr.Input.Type.IsKnownType(KnownTypeCode.Char))
                    {
                        charToString = i;
                    }
                }
            }

            var  memberTargetrr = leftResolverResult as MemberResolveResult;
            bool isField        = (memberTargetrr != null && memberTargetrr.Member is IField &&
                                   (memberTargetrr.TargetResult is ThisResolveResult ||
                                    memberTargetrr.TargetResult is LocalResolveResult)) || leftResolverResult is ThisResolveResult || leftResolverResult is LocalResolveResult || leftResolverResult is ConstantResolveResult;

            var  rightMemberTargetrr = rightResolverResult as MemberResolveResult;
            bool isRightSimple       = (rightMemberTargetrr != null && rightMemberTargetrr.Member is IField &&
                                        (rightMemberTargetrr.TargetResult is ThisResolveResult ||
                                         rightMemberTargetrr.TargetResult is LocalResolveResult)) || rightResolverResult is ThisResolveResult || rightResolverResult is LocalResolveResult || rightResolverResult is ConstantResolveResult;

            var needTempVar = needReturnValue && (!isRightSimple && !isField || assignmentExpression.Operator != AssignmentOperatorType.Assign);

            /*if (assignmentExpression.Operator == AssignmentOperatorType.Any)
             * {
             *  needTempVar = false;
             * }*/

            if (needReturnValue)
            {
                if (needTempVar)
                {
                    variable = this.GetTempVarName();
                    this.Write("(" + variable + " = ");

                    var oldValue1 = this.Emitter.ReplaceAwaiterByVar;
                    this.Emitter.ReplaceAwaiterByVar = true;
                    assignmentExpression.Right.AcceptVisitor(this.Emitter);

                    this.Emitter.ReplaceAwaiterByVar = oldValue1;
                    this.Write(", ");
                }
                else
                {
                    this.Write("(");
                }
            }

            if (assignmentExpression.Operator == AssignmentOperatorType.Divide &&
                !(this.Emitter.IsJavaScriptOverflowMode && !ConversionBlock.InsideOverflowContext(this.Emitter, assignmentExpression)) &&
                !isLong && !isLongExpected &&
                (
                    (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||

                    (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Left), this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Right), this.Emitter.Resolver))
                ))
            {
                this.Emitter.IsAssignment   = true;
                this.Emitter.AssignmentType = AssignmentOperatorType.Assign;
                var oldValue1 = this.Emitter.ReplaceAwaiterByVar;
                this.Emitter.ReplaceAwaiterByVar = true;
                assignmentExpression.Left.AcceptVisitor(this.Emitter);

                if (this.Emitter.Writers.Count == initCount)
                {
                    this.Write(" = ");
                }

                this.Emitter.ReplaceAwaiterByVar = oldValue1;
                this.Emitter.AssignmentType      = oldAssigmentType;
                this.Emitter.IsAssignment        = oldAssigment;

                this.Write(JS.Types.BRIDGE_INT + "." + JS.Funcs.Math.DIV + "(");
                assignmentExpression.Left.AcceptVisitor(this.Emitter);
                this.Write(", ");
                oldValue1 = this.Emitter.ReplaceAwaiterByVar;
                this.Emitter.ReplaceAwaiterByVar = true;

                assignmentExpression.Right.AcceptVisitor(this.Emitter);

                this.Write(")");

                this.Emitter.ReplaceAwaiterByVar     = oldValue1;
                this.Emitter.AsyncExpressionHandling = asyncExpressionHandling;

                if (this.Emitter.Writers.Count > initCount)
                {
                    this.PopWriter();
                }

                if (needReturnValue && !isField)
                {
                    if (needTempVar)
                    {
                        this.Write(", " + variable);
                    }
                    else
                    {
                        this.Write(", ");
                        this.Emitter.IsAssignment = false;
                        assignmentExpression.Right.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = oldAssigment;
                    }
                }

                if (needReturnValue)
                {
                    this.Write(")");
                }

                return;
            }

            if (assignmentExpression.Operator == AssignmentOperatorType.Add ||
                assignmentExpression.Operator == AssignmentOperatorType.Subtract)
            {
                var add = assignmentExpression.Operator == AssignmentOperatorType.Add;

                if (this.Emitter.Validator.IsDelegateOrLambda(leftResolverResult))
                {
                    delegateAssigment = true;
                    var leftMemberResolveResult = leftResolverResult as MemberResolveResult;

                    if (leftMemberResolveResult != null)
                    {
                        isEvent = leftMemberResolveResult.Member is IEvent;
                    }

                    if (!isEvent)
                    {
                        this.Emitter.IsAssignment   = true;
                        this.Emitter.AssignmentType = AssignmentOperatorType.Assign;
                        assignmentExpression.Left.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = false;

                        if (this.Emitter.Writers.Count == initCount)
                        {
                            this.Write(" = ");
                        }

                        this.Write(add ? JS.Funcs.BRIDGE_COMBINE : JS.Funcs.BRIDGE_REMOVE);
                        this.WriteOpenParentheses();
                    }
                }
            }

            bool   nullable = orr != null && orr.IsLiftedOperator;
            string root     = JS.Types.SYSTEM_NULLABLE + ".";

            bool special = nullable;

            this.Emitter.IsAssignment   = true;
            this.Emitter.AssignmentType = assignmentExpression.Operator;
            var oldValue = this.Emitter.ReplaceAwaiterByVar;

            this.Emitter.ReplaceAwaiterByVar = true;

            bool thisAssignment = leftResolverResult is ThisResolveResult;

            if (!thisAssignment)
            {
                if (special || (isDecimal && isDecimalExpected) || (isLong && isLongExpected) || isUserOperator)
                {
                    this.Emitter.AssignmentType = AssignmentOperatorType.Assign;
                }

                if (delegateAssigment && !isEvent)
                {
                    this.Emitter.IsAssignment = false;
                }

                assignmentExpression.Left.AcceptVisitor(this.Emitter);

                if (delegateAssigment)
                {
                    this.Emitter.IsAssignment = true;
                }
            }
            else
            {
                this.Write("(");
            }

            this.Emitter.ReplaceAwaiterByVar = oldValue;
            this.Emitter.AssignmentType      = oldAssigmentType;
            this.Emitter.IsAssignment        = oldAssigment;

            if (this.Emitter.Writers.Count == initCount && !delegateAssigment && !thisAssignment)
            {
                this.WriteSpace();
            }

            if (isDecimal && isDecimalExpected)
            {
                if (this.Emitter.Writers.Count == initCount)
                {
                    this.Write("= ");
                }

                oldValue = this.Emitter.ReplaceAwaiterByVar;
                this.Emitter.ReplaceAwaiterByVar = true;

                this.HandleDecimal(rr, variable);

                if (this.Emitter.Writers.Count > initCount)
                {
                    this.PopWriter();
                }

                if (needTempVar)
                {
                    this.Write(", " + variable + ")");
                }
                else if (needReturnValue)
                {
                    if (!isField)
                    {
                        this.Write(", ");
                        this.Emitter.IsAssignment = false;
                        assignmentExpression.Right.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = oldAssigment;
                    }

                    this.Write(")");
                }

                this.Emitter.ReplaceAwaiterByVar = oldValue;
                return;
            }

            if (isLong && isLongExpected)
            {
                if (this.Emitter.Writers.Count == initCount)
                {
                    this.Write("= ");
                }

                oldValue = this.Emitter.ReplaceAwaiterByVar;
                this.Emitter.ReplaceAwaiterByVar = true;

                this.HandleLong(rr, variable, isUint);

                if (this.Emitter.Writers.Count > initCount)
                {
                    this.PopWriter();
                }

                if (needTempVar)
                {
                    this.Write(", " + variable + ")");
                }
                else if (needReturnValue)
                {
                    if (!isField)
                    {
                        this.Write(", ");
                        this.Emitter.IsAssignment = false;
                        assignmentExpression.Right.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = oldAssigment;
                    }

                    this.Write(")");
                }
                this.Emitter.ReplaceAwaiterByVar = oldValue;
                return;
            }

            if (this.ResolveOperator(assignmentExpression, orr, initCount, thisAssignment))
            {
                if (thisAssignment)
                {
                    this.Write(")." + JS.Funcs.CLONE + "(this)");
                }
                else if (needReturnValue)
                {
                    this.Write(")");
                }
                return;
            }

            bool isBool = NullableType.IsNullable(rr.Type) ? NullableType.GetUnderlyingType(rr.Type).IsKnownType(KnownTypeCode.Boolean) : rr.Type.IsKnownType(KnownTypeCode.Boolean);

            if (!delegateAssigment)
            {
                if (!special)
                {
                    switch (assignmentExpression.Operator)
                    {
                    case AssignmentOperatorType.Assign:
                        break;

                    case AssignmentOperatorType.Add:
                        this.Write("+");
                        break;

                    case AssignmentOperatorType.BitwiseAnd:
                        if (!isBool)
                        {
                            this.Write("&");
                        }
                        break;

                    case AssignmentOperatorType.BitwiseOr:
                        if (!isBool)
                        {
                            this.Write("|");
                        }

                        break;

                    case AssignmentOperatorType.Divide:
                        this.Write("/");
                        break;

                    case AssignmentOperatorType.ExclusiveOr:
                        this.Write("^");
                        break;

                    case AssignmentOperatorType.Modulus:
                        this.Write("%");
                        break;

                    case AssignmentOperatorType.Multiply:
                        this.Write("*");
                        break;

                    case AssignmentOperatorType.ShiftLeft:
                        this.Write("<<");
                        break;

                    case AssignmentOperatorType.ShiftRight:
                        this.Write(isUint ? ">>>" : ">>");
                        break;

                    case AssignmentOperatorType.Subtract:
                        this.Write("-");
                        break;

                    default:
                        throw new EmitterException(assignmentExpression,
                                                   "Unsupported assignment operator: " + assignmentExpression.Operator.ToString());
                    }
                }

                if (special)
                {
                    if (this.Emitter.Writers.Count == initCount)
                    {
                        this.Write("= ");
                    }
                    this.Write(root);

                    switch (assignmentExpression.Operator)
                    {
                    case AssignmentOperatorType.Assign:
                        break;

                    case AssignmentOperatorType.Add:
                        this.Write(JS.Funcs.Math.ADD);
                        break;

                    case AssignmentOperatorType.BitwiseAnd:
                        this.Write(isBool ? JS.Funcs.Math.AND : JS.Funcs.Math.BAND);
                        break;

                    case AssignmentOperatorType.BitwiseOr:
                        this.Write(isBool ? JS.Funcs.Math.OR : JS.Funcs.Math.BOR);
                        break;

                    case AssignmentOperatorType.Divide:
                        this.Write(JS.Funcs.Math.DIV);
                        break;

                    case AssignmentOperatorType.ExclusiveOr:
                        this.Write(JS.Funcs.Math.XOR);
                        break;

                    case AssignmentOperatorType.Modulus:
                        this.Write(JS.Funcs.Math.MOD);
                        break;

                    case AssignmentOperatorType.Multiply:
                        this.Write(JS.Funcs.Math.MUL);
                        break;

                    case AssignmentOperatorType.ShiftLeft:
                        this.Write(JS.Funcs.Math.SL);
                        break;

                    case AssignmentOperatorType.ShiftRight:
                        this.Write(isUint ? JS.Funcs.Math.SRR : JS.Funcs.Math.SR);
                        break;

                    case AssignmentOperatorType.Subtract:
                        this.Write(JS.Funcs.Math.SUB);
                        break;

                    default:
                        throw new EmitterException(assignmentExpression,
                                                   "Unsupported assignment operator: " + assignmentExpression.Operator.ToString());
                    }

                    this.WriteOpenParentheses();

                    assignmentExpression.Left.AcceptVisitor(this.Emitter);
                    this.Write(", ");
                }

                if (this.Emitter.Writers.Count == initCount && !thisAssignment && !special)
                {
                    this.Write("= ");
                }
            }
            else if (!isEvent)
            {
                this.WriteComma();
            }

            if (!special && isBool && (assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd || assignmentExpression.Operator == AssignmentOperatorType.BitwiseOr))
            {
                this.Write("!!(");
                assignmentExpression.Left.AcceptVisitor(this.Emitter);
                this.Write(assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd ? " & " : " | ");
            }

            oldValue = this.Emitter.ReplaceAwaiterByVar;
            this.Emitter.ReplaceAwaiterByVar = true;

            if (charToString == 1)
            {
                this.Write(JS.Funcs.STRING_FROMCHARCODE + "(");
            }

            if (needTempVar)
            {
                this.Write(variable);
            }
            else
            {
                var wrap = assignmentExpression.Operator != AssignmentOperatorType.Assign &&
                           this.Emitter.Writers.Count > initCount &&
                           !AssigmentExpressionHelper.CheckIsRightAssigmentExpression(assignmentExpression);

                if (wrap)
                {
                    this.WriteOpenParentheses();
                }

                assignmentExpression.Right.AcceptVisitor(this.Emitter);

                if (wrap)
                {
                    this.WriteCloseParentheses();
                }
            }

            if (!special && isBool &&
                (assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd ||
                 assignmentExpression.Operator == AssignmentOperatorType.BitwiseOr))
            {
                this.WriteCloseParentheses();
            }

            if (charToString == 1)
            {
                this.WriteCloseParentheses();
            }

            if (special)
            {
                this.WriteCloseParentheses();
            }

            if (thisAssignment)
            {
                this.Write(")." + JS.Funcs.CLONE + "(this)");
            }

            this.Emitter.ReplaceAwaiterByVar     = oldValue;
            this.Emitter.AsyncExpressionHandling = asyncExpressionHandling;

            if (this.Emitter.Writers.Count > initCount)
            {
                var writerCount = this.Emitter.Writers.Count;
                for (int i = initCount; i < writerCount; i++)
                {
                    this.PopWriter();
                }
            }

            if (delegateAssigment)
            {
                this.WriteCloseParentheses();
            }

            if (needTempVar)
            {
                this.Write(", " + variable + ")");
            }
            else if (needReturnValue)
            {
                if (!isField)
                {
                    this.Write(", ");
                    this.Emitter.IsAssignment = false;
                    assignmentExpression.Right.AcceptVisitor(this.Emitter);
                    this.Emitter.IsAssignment = oldAssigment;
                }

                this.Write(")");
            }
        }
Пример #5
0
        protected void VisitAssignmentExpression()
        {
            AssignmentExpression assignmentExpression = this.AssignmentExpression;
            var    oldAssigment     = this.Emitter.IsAssignment;
            var    oldAssigmentType = this.Emitter.AssignmentType;
            string variable         = null;

            bool needReturnValue = !(assignmentExpression.Parent is ExpressionStatement);

            if (needReturnValue && assignmentExpression.Parent is LambdaExpression)
            {
                var lambdarr = this.Emitter.Resolver.ResolveNode(assignmentExpression.Parent, this.Emitter) as LambdaResolveResult;

                if (lambdarr != null && lambdarr.ReturnType.Kind == TypeKind.Void)
                {
                    needReturnValue = false;
                }
            }

            var  delegateAssigment = false;
            bool isEvent           = false;
            var  initCount         = this.Emitter.Writers.Count;

            var asyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

            this.WriteAwaiters(assignmentExpression.Left);
            this.WriteAwaiters(assignmentExpression.Right);

            var  leftResolverResult  = this.Emitter.Resolver.ResolveNode(assignmentExpression.Left, this.Emitter);
            var  rightResolverResult = this.Emitter.Resolver.ResolveNode(assignmentExpression.Right, this.Emitter);
            var  rr                = this.Emitter.Resolver.ResolveNode(assignmentExpression, this.Emitter);
            var  orr               = rr as OperatorResolveResult;
            bool isDecimal         = Helpers.IsDecimalType(rr.Type, this.Emitter.Resolver);
            bool isLong            = Helpers.Is64Type(rr.Type, this.Emitter.Resolver);
            var  expectedType      = this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression);
            bool isDecimalExpected = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isLongExpected    = Helpers.Is64Type(expectedType, this.Emitter.Resolver);
            bool isUserOperator    = this.IsUserOperator(orr);

            bool isUint = rr.Type.IsKnownType(KnownTypeCode.UInt16) ||
                          rr.Type.IsKnownType(KnownTypeCode.UInt32) ||
                          rr.Type.IsKnownType(KnownTypeCode.UInt64);

            var charToString = -1;

            if (orr != null && orr.Type.IsKnownType(KnownTypeCode.String))
            {
                for (int i = 0; i < orr.Operands.Count; i++)
                {
                    var crr = orr.Operands[i] as ConversionResolveResult;
                    if (crr != null && crr.Input.Type.IsKnownType(KnownTypeCode.Char))
                    {
                        charToString = i;
                    }
                }
            }

            var needTempVar = needReturnValue;

            if (assignmentExpression.Operator != AssignmentOperatorType.Any)
            {
                needTempVar = false;
            }

            if (needReturnValue)
            {
                if (needTempVar)
                {
                    variable = this.GetTempVarName();
                    this.Write("(" + variable + " = ");

                    var oldValue1 = this.Emitter.ReplaceAwaiterByVar;
                    this.Emitter.ReplaceAwaiterByVar = true;
                    assignmentExpression.Right.AcceptVisitor(this.Emitter);

                    this.Emitter.ReplaceAwaiterByVar = oldValue1;
                    this.Write(", ");
                }
                else
                {
                    this.Write("(");
                }
            }

            var  memberTargetrr = leftResolverResult as MemberResolveResult;
            bool isField        = (memberTargetrr != null && memberTargetrr.Member is IField &&
                                   (memberTargetrr.TargetResult is ThisResolveResult ||
                                    memberTargetrr.TargetResult is LocalResolveResult)) || leftResolverResult is ThisResolveResult || leftResolverResult is LocalResolveResult;

            if (assignmentExpression.Operator == AssignmentOperatorType.Divide &&
                !(this.Emitter.IsJavaScriptOverflowMode && !ConversionBlock.InsideOverflowContext(this.Emitter, assignmentExpression)) &&
                !isLong && !isLongExpected &&
                (
                    (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||

                    (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Left), this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Right), this.Emitter.Resolver))
                ))
            {
                this.Emitter.IsAssignment   = true;
                this.Emitter.AssignmentType = AssignmentOperatorType.Assign;
                var oldValue1 = this.Emitter.ReplaceAwaiterByVar;
                this.Emitter.ReplaceAwaiterByVar = true;
                assignmentExpression.Left.AcceptVisitor(this.Emitter);

                if (this.Emitter.Writers.Count == initCount)
                {
                    this.Write(" = ");
                }

                this.Emitter.ReplaceAwaiterByVar = oldValue1;
                this.Emitter.AssignmentType      = oldAssigmentType;
                this.Emitter.IsAssignment        = oldAssigment;

                this.Write("Bridge.Int.div(");
                assignmentExpression.Left.AcceptVisitor(this.Emitter);
                this.Write(", ");
                oldValue1 = this.Emitter.ReplaceAwaiterByVar;
                this.Emitter.ReplaceAwaiterByVar = true;

                assignmentExpression.Right.AcceptVisitor(this.Emitter);

                this.Write(")");

                this.Emitter.ReplaceAwaiterByVar     = oldValue1;
                this.Emitter.AsyncExpressionHandling = asyncExpressionHandling;

                if (this.Emitter.Writers.Count > initCount)
                {
                    this.PopWriter();
                }


                if (needReturnValue && !isField)
                {
                    this.Write(", ");
                    this.Emitter.IsAssignment = false;
                    assignmentExpression.Left.AcceptVisitor(this.Emitter);
                    this.Emitter.IsAssignment = oldAssigment;
                }

                if (needReturnValue)
                {
                    this.Write(")");
                }

                return;
            }

            if (assignmentExpression.Operator == AssignmentOperatorType.Add ||
                assignmentExpression.Operator == AssignmentOperatorType.Subtract)
            {
                var add = assignmentExpression.Operator == AssignmentOperatorType.Add;

                if (this.Emitter.Validator.IsDelegateOrLambda(leftResolverResult))
                {
                    delegateAssigment = true;
                    var leftMemberResolveResult = leftResolverResult as MemberResolveResult;

                    if (leftMemberResolveResult != null)
                    {
                        isEvent = leftMemberResolveResult.Member is DefaultResolvedEvent;
                    }

                    if (!isEvent)
                    {
                        this.Emitter.IsAssignment   = true;
                        this.Emitter.AssignmentType = AssignmentOperatorType.Assign;
                        assignmentExpression.Left.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = false;

                        if (this.Emitter.Writers.Count == initCount)
                        {
                            this.Write(" = ");
                        }

                        this.Write(Bridge.Translator.Emitter.ROOT + "." + (add ? Bridge.Translator.Emitter.DELEGATE_COMBINE : Bridge.Translator.Emitter.DELEGATE_REMOVE));
                        this.WriteOpenParentheses();
                    }
                }
            }

            bool   nullable = orr != null && orr.IsLiftedOperator;
            string root     = Bridge.Translator.Emitter.ROOT + ".Nullable.";

            bool special = nullable;

            this.Emitter.IsAssignment   = true;
            this.Emitter.AssignmentType = assignmentExpression.Operator;
            var oldValue = this.Emitter.ReplaceAwaiterByVar;

            this.Emitter.ReplaceAwaiterByVar = true;

            bool thisAssignment = leftResolverResult is ThisResolveResult;

            if (!thisAssignment)
            {
                if (special || (isDecimal && isDecimalExpected) || (isLong && isLongExpected) || isUserOperator)
                {
                    this.Emitter.AssignmentType = AssignmentOperatorType.Assign;
                }

                if (delegateAssigment && !isEvent)
                {
                    this.Emitter.IsAssignment = false;
                }

                assignmentExpression.Left.AcceptVisitor(this.Emitter);

                if (delegateAssigment)
                {
                    this.Emitter.IsAssignment = true;
                }
            }
            else
            {
                this.Write("(");
            }

            this.Emitter.ReplaceAwaiterByVar = oldValue;
            this.Emitter.AssignmentType      = oldAssigmentType;
            this.Emitter.IsAssignment        = oldAssigment;

            if (this.Emitter.Writers.Count == initCount && !delegateAssigment && !thisAssignment)
            {
                this.WriteSpace();
            }

            if (isDecimal && isDecimalExpected)
            {
                if (this.Emitter.Writers.Count == initCount)
                {
                    this.Write("= ");
                }

                this.HandleDecimal(rr, variable);

                if (this.Emitter.Writers.Count > initCount)
                {
                    this.PopWriter();
                }

                if (needTempVar)
                {
                    this.Write(", " + variable + ")");
                }
                else if (needReturnValue)
                {
                    if (!isField)
                    {
                        this.Write(", ");
                        this.Emitter.IsAssignment = false;
                        assignmentExpression.Left.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = oldAssigment;
                    }

                    this.Write(")");
                }

                return;
            }

            if (isLong && isLongExpected)
            {
                if (this.Emitter.Writers.Count == initCount)
                {
                    this.Write("= ");
                }

                this.HandleLong(rr, variable, isUint);

                if (this.Emitter.Writers.Count > initCount)
                {
                    this.PopWriter();
                }

                if (needTempVar)
                {
                    this.Write(", " + variable + ")");
                }
                else if (needReturnValue)
                {
                    if (!isField)
                    {
                        this.Write(", ");
                        this.Emitter.IsAssignment = false;
                        assignmentExpression.Left.AcceptVisitor(this.Emitter);
                        this.Emitter.IsAssignment = oldAssigment;
                    }

                    this.Write(")");
                }

                return;
            }

            if (this.ResolveOperator(assignmentExpression, orr, initCount))
            {
                return;
            }

            bool isBool = NullableType.IsNullable(rr.Type) ? NullableType.GetUnderlyingType(rr.Type).IsKnownType(KnownTypeCode.Boolean) : rr.Type.IsKnownType(KnownTypeCode.Boolean);

            if (!delegateAssigment)
            {
                if (!special)
                {
                    switch (assignmentExpression.Operator)
                    {
                    case AssignmentOperatorType.Assign:
                        break;

                    case AssignmentOperatorType.Add:
                        this.Write("+");
                        break;

                    case AssignmentOperatorType.BitwiseAnd:
                        if (!isBool)
                        {
                            this.Write("&");
                        }
                        break;

                    case AssignmentOperatorType.BitwiseOr:
                        if (!isBool)
                        {
                            this.Write("|");
                        }

                        break;

                    case AssignmentOperatorType.Divide:
                        this.Write("/");
                        break;

                    case AssignmentOperatorType.ExclusiveOr:
                        this.Write("^");
                        break;

                    case AssignmentOperatorType.Modulus:
                        this.Write("%");
                        break;

                    case AssignmentOperatorType.Multiply:
                        this.Write("*");
                        break;

                    case AssignmentOperatorType.ShiftLeft:
                        this.Write("<<");
                        break;

                    case AssignmentOperatorType.ShiftRight:
                        this.Write(isUint ? ">>>" : ">>");
                        break;

                    case AssignmentOperatorType.Subtract:
                        this.Write("-");
                        break;

                    default:
                        throw new EmitterException(assignmentExpression,
                                                   "Unsupported assignment operator: " + assignmentExpression.Operator.ToString());
                    }
                }

                if (special)
                {
                    if (this.Emitter.Writers.Count == initCount)
                    {
                        this.Write("= ");
                    }
                    this.Write(root);

                    switch (assignmentExpression.Operator)
                    {
                    case AssignmentOperatorType.Assign:
                        break;

                    case AssignmentOperatorType.Add:
                        this.Write("add");
                        break;

                    case AssignmentOperatorType.BitwiseAnd:
                        this.Write(isBool ? "and" : "band");
                        break;

                    case AssignmentOperatorType.BitwiseOr:
                        this.Write(isBool ? "or" : "bor");
                        break;

                    case AssignmentOperatorType.Divide:
                        this.Write("div");
                        break;

                    case AssignmentOperatorType.ExclusiveOr:
                        this.Write("xor");
                        break;

                    case AssignmentOperatorType.Modulus:
                        this.Write("mod");
                        break;

                    case AssignmentOperatorType.Multiply:
                        this.Write("mul");
                        break;

                    case AssignmentOperatorType.ShiftLeft:
                        this.Write("sl");
                        break;

                    case AssignmentOperatorType.ShiftRight:
                        this.Write(isUint ? "srr" : "sr");
                        break;

                    case AssignmentOperatorType.Subtract:
                        this.Write("sub");
                        break;

                    default:
                        throw new EmitterException(assignmentExpression,
                                                   "Unsupported assignment operator: " + assignmentExpression.Operator.ToString());
                    }

                    this.WriteOpenParentheses();

                    assignmentExpression.Left.AcceptVisitor(this.Emitter);
                    this.Write(", ");
                }

                if (this.Emitter.Writers.Count == initCount && !thisAssignment && !special)
                {
                    this.Write("= ");
                }
            }
            else if (!isEvent)
            {
                this.WriteComma();
            }

            if (!special && isBool && (assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd || assignmentExpression.Operator == AssignmentOperatorType.BitwiseOr))
            {
                this.Write("!!(");
                assignmentExpression.Left.AcceptVisitor(this.Emitter);
                this.Write(assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd ? " & " : " | ");
            }

            oldValue = this.Emitter.ReplaceAwaiterByVar;
            this.Emitter.ReplaceAwaiterByVar = true;

            if (charToString == 1)
            {
                this.Write("String.fromCharCode(");
            }

            if (needTempVar)
            {
                this.Write(variable);
            }
            else
            {
                assignmentExpression.Right.AcceptVisitor(this.Emitter);
            }

            if (!special && isBool &&
                (assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd ||
                 assignmentExpression.Operator == AssignmentOperatorType.BitwiseOr))
            {
                this.WriteCloseParentheses();
            }

            if (charToString == 1)
            {
                this.WriteCloseParentheses();
            }

            if (special)
            {
                this.WriteCloseParentheses();
            }

            if (thisAssignment)
            {
                this.Write(").$clone(this)");
            }

            this.Emitter.ReplaceAwaiterByVar     = oldValue;
            this.Emitter.AsyncExpressionHandling = asyncExpressionHandling;

            if (this.Emitter.Writers.Count > initCount)
            {
                var writerCount = this.Emitter.Writers.Count;
                for (int i = initCount; i < writerCount; i++)
                {
                    this.PopWriter();
                }
            }

            if (delegateAssigment)
            {
                this.WriteCloseParentheses();
            }

            if (needTempVar)
            {
                this.Write(", " + variable + ")");
            }
            else if (needReturnValue)
            {
                if (!isField)
                {
                    this.Write(", ");
                    this.Emitter.IsAssignment = false;
                    assignmentExpression.Left.AcceptVisitor(this.Emitter);
                    this.Emitter.IsAssignment = oldAssigment;
                }

                this.Write(")");
            }
        }