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(); } }
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(); } }
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 += ")"; } } } }
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(")"); } }
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(")"); } }