public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var leftIsEnum = IsEnumOrNullableEnum(leftType); var rightType = boe.Right.GetActualType(TypeSystem); var rightIsEnum = IsEnumOrNullableEnum(rightType); var resultType = boe.GetActualType(TypeSystem); var resultIsEnum = IsEnumOrNullableEnum(resultType); if ((leftIsEnum || rightIsEnum) && LogicalOperators.Contains(boe.Operator)) { if (leftIsEnum) { var cast = JSInvocationExpression.InvokeStatic( JS.Number(TypeSystem.Int32), new[] { boe.Left }, true ); boe.ReplaceChild(boe.Left, cast); } if (rightIsEnum) { var cast = JSInvocationExpression.InvokeStatic( JS.Number(TypeSystem.Int32), new[] { boe.Right }, true ); boe.ReplaceChild(boe.Right, cast); } } VisitChildren(boe); }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); bool isArithmetic = !(boe.Operator is JSAssignmentOperator); if ((leftType.FullName == "System.Char") && isArithmetic) { boe.ReplaceChild(boe.Left, CastToInteger(boe.Left)); } if ((rightType.FullName == "System.Char") && isArithmetic) { boe.ReplaceChild(boe.Right, CastToInteger(boe.Right)); } var parentInvocation = ParentNode as JSInvocationExpression; JSDotExpressionBase parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpressionBase : null; if ( isArithmetic && (boe.GetActualType(TypeSystem).FullName == "System.Char") && !( (parentInvocation != null) && (parentInvocationDot != null) && (parentInvocationDot.Target is JSStringIdentifier) && (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") && (parentInvocationDot.Member is JSFakeMethod) && (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode") ) ) { var castBoe = CastToChar(boe); ParentNode.ReplaceChild(boe, castBoe); VisitReplacement(castBoe); } else { VisitChildren(boe); } }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetExpectedType(TypeSystem); var rightType = boe.Right.GetExpectedType(TypeSystem); bool isArithmetic = !(boe.Operator is JSAssignmentOperator); if ((leftType.FullName == "System.Char") && isArithmetic) boe.ReplaceChild(boe.Left, CastToInteger(boe.Left)); if ((rightType.FullName == "System.Char") && isArithmetic) boe.ReplaceChild(boe.Right, CastToInteger(boe.Right)); var parentInvocation = ParentNode as JSInvocationExpression; JSDotExpression parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpression : null; if ( isArithmetic && (boe.GetExpectedType(TypeSystem).FullName == "System.Char") && !( (parentInvocation != null) && (parentInvocationDot != null) && (parentInvocationDot.Target is JSStringIdentifier) && (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") && (parentInvocationDot.Member is JSFakeMethod) && (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode") ) ) { var castBoe = CastToChar(boe); ParentNode.ReplaceChild(boe, castBoe); VisitReplacement(castBoe); } else { VisitChildren(boe); } }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); // We can end up with a pointer literal in an arithmetic expression. // In this case we want to switch it back to a normal integer literal so that the math operations work. var leftPointer = boe.Left as JSPointerLiteral; var rightPointer = boe.Right as JSPointerLiteral; if (!(boe.Operator is JSAssignmentOperator)) { if (leftPointer != null) { boe.ReplaceChild(boe.Left, JSLiteral.New(leftPointer.Value)); } if (rightPointer != null) { boe.ReplaceChild(boe.Right, JSLiteral.New(rightPointer.Value)); } } JSExpression replacement = null; if (leftType.IsPointer && TypeUtil.IsIntegral(rightType)) { if ( (boe.Operator == JSOperator.Add) || (boe.Operator == JSOperator.AddAssignment) ) { replacement = new JSPointerAddExpression( boe.Left, boe.Right, boe.Operator == JSOperator.AddAssignment ); } else if ( (boe.Operator == JSOperator.Subtract) || (boe.Operator == JSOperator.SubtractAssignment) ) { // FIXME: Int32 is probably wrong replacement = new JSPointerAddExpression( boe.Left, new JSUnaryOperatorExpression(JSOperator.Negation, boe.Right, TypeSystem.Int32), boe.Operator == JSOperator.SubtractAssignment ); } } else if (leftType.IsPointer && rightType.IsPointer) { if (boe.Operator == JSOperator.Subtract) { // FIXME: Int32 is probably wrong replacement = new JSPointerDeltaExpression( boe.Left, boe.Right, TypeSystem.Int32 ); } else if (boe.Operator is JSComparisonOperator) { replacement = new JSPointerComparisonExpression(boe.Operator, boe.Left, boe.Right, boe.ActualType); } } if (replacement != null) { ParentNode.ReplaceChild(boe, replacement); VisitReplacement(replacement); } else { VisitChildren(boe); } }
public void VisitNode (JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); // We can end up with a pointer literal in an arithmetic expression. // In this case we want to switch it back to a normal integer literal so that the math operations work. var leftPointer = boe.Left as JSPointerLiteral; var rightPointer = boe.Right as JSPointerLiteral; if (!(boe.Operator is JSAssignmentOperator)) { if (leftPointer != null) boe.ReplaceChild(boe.Left, JSLiteral.New(leftPointer.Value)); if (rightPointer != null) boe.ReplaceChild(boe.Right, JSLiteral.New(rightPointer.Value)); } JSExpression replacement = null; if (leftType.IsPointer && TypeUtil.IsIntegral(rightType)) { if ( (boe.Operator == JSOperator.Add) || (boe.Operator == JSOperator.AddAssignment) ) { replacement = new JSPointerAddExpression( boe.Left, boe.Right, boe.Operator == JSOperator.AddAssignment ); } else if ( (boe.Operator == JSOperator.Subtract) || (boe.Operator == JSOperator.SubtractAssignment) ) { // FIXME: Int32 is probably wrong replacement = new JSPointerAddExpression( boe.Left, new JSUnaryOperatorExpression(JSOperator.Negation, boe.Right, TypeSystem.Int32), boe.Operator == JSOperator.SubtractAssignment ); } } else if (leftType.IsPointer && rightType.IsPointer) { if (boe.Operator == JSOperator.Subtract) { // FIXME: Int32 is probably wrong replacement = new JSPointerDeltaExpression( boe.Left, boe.Right, TypeSystem.Int32 ); } else if (boe.Operator is JSComparisonOperator) { replacement = new JSPointerComparisonExpression(boe.Operator, boe.Left, boe.Right, boe.ActualType); } } if (replacement != null) { ParentNode.ReplaceChild(boe, replacement); VisitReplacement(replacement); } else { VisitChildren(boe); } }
public void VisitNode (JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); bool isArithmetic = !(boe.Operator is JSAssignmentOperator); if (!isArithmetic && boe.Operator != JSOperator.Assignment && leftType.FullName == "System.Char") { JSBinaryOperator newOperator; if (boe.Operator == JSOperator.AddAssignment) { newOperator = JSOperator.Add; } else if (boe.Operator == JSOperator.BitwiseAndAssignment) { newOperator = JSOperator.BitwiseAnd; } else if (boe.Operator == JSOperator.BitwiseOrAssignment) { newOperator = JSOperator.BitwiseOr; } else if (boe.Operator == JSOperator.BitwiseXorAssignment) { newOperator = JSOperator.BitwiseXor; } else if (boe.Operator == JSOperator.DivideAssignment) { newOperator = JSOperator.Divide; } else if (boe.Operator == JSOperator.MultiplyAssignment) { newOperator = JSOperator.Multiply; } else if (boe.Operator == JSOperator.RemainderAssignment) { newOperator = JSOperator.Remainder; } else if (boe.Operator == JSOperator.ShiftLeftAssignment) { newOperator = JSOperator.ShiftLeft; } else if (boe.Operator == JSOperator.ShiftRightAssignment) { newOperator = JSOperator.ShiftRight; } else if (boe.Operator == JSOperator.ShiftRightUnsignedAssignment) { newOperator = JSOperator.ShiftRightUnsigned; } else if (boe.Operator == JSOperator.SubtractAssignment) { newOperator = JSOperator.Subtract; } else { throw new InvalidOperationException("Unknown assigment operator"); } var newBoe = new JSBinaryOperatorExpression(JSOperator.Assignment, boe.Left, new JSBinaryOperatorExpression(newOperator, boe.Left, boe.Right, boe.ActualType), boe.ActualType); ParentNode.ReplaceChild(boe, newBoe); VisitReplacement(newBoe); return; } if (boe.Operator == JSOperator.Assignment && (leftType.FullName == "System.Char") && (rightType.FullName != "System.Char")) { boe.ReplaceChild(boe.Right, CastToChar(boe.Right)); } if (boe.Operator == JSOperator.Assignment && (leftType.FullName != "System.Char") && (rightType.FullName == "System.Char")) { boe.ReplaceChild(boe.Right, CastToInteger(boe.Right)); } if ((leftType.FullName == "System.Char") && isArithmetic) boe.ReplaceChild(boe.Left, CastToInteger(boe.Left)); if ((rightType.FullName == "System.Char") && isArithmetic) boe.ReplaceChild(boe.Right, CastToInteger(boe.Right)); var parentInvocation = ParentNode as JSInvocationExpression; JSDotExpressionBase parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpressionBase : null; if ( isArithmetic && (boe.GetActualType(TypeSystem).FullName == "System.Char") && !( (parentInvocation != null) && (parentInvocationDot != null) && (parentInvocationDot.Target is JSStringIdentifier) && (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") && (parentInvocationDot.Member is JSFakeMethod) && (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode") ) ) { var castBoe = CastToChar(boe); ParentNode.ReplaceChild(boe, castBoe); VisitReplacement(castBoe); } else { VisitChildren(boe); } }
void PostOptimizeAssignment(JSBinaryOperatorExpression boe, JSExpression rhs) { var rhsCopy = rhs as JSStructCopyExpression; if (rhsCopy == null) { return; } var expr = rhsCopy.Struct; var rre = expr as JSResultReferenceExpression; if (rre != null) { expr = rre.Referent; } var invocation = expr as JSInvocationExpression; if (invocation == null) { return; } var invokeMethod = invocation.JSMethod; if (invokeMethod == null) { return; } var invocationSecondPass = GetSecondPass(invokeMethod); if (invocationSecondPass == null) { return; } bool eliminateCopy = false; string eliminateReason = null; if (invocationSecondPass.ResultIsNew) { // If this expression is the return value of a function invocation, we can eliminate struct // copies if the return value is a 'new' expression. eliminateCopy = true; eliminateReason = "Result is new"; } else if (invocationSecondPass.ResultVariable != null) { // We can also eliminate a return value copy if the return value is one of the function's // arguments, and we are sure that argument does not escape (other than through the return // statement, that is). var parameters = invokeMethod.Method.Parameters; int parameterIndex = -1; for (var i = 0; i < parameters.Length; i++) { if (parameters[i].Name != invocationSecondPass.ResultVariable) { continue; } parameterIndex = i; break; } // We found a single parameter that acts as the result of this function call. if (parameterIndex >= 0) { GenericParameter relevantParameter; var innerValue = invocation.Arguments[parameterIndex]; // Identify any local variables that are a dependency of the result parameter. var localVariableDependencies = StaticAnalyzer.ExtractInvolvedVariables( innerValue, (n) => // If a variable is inside a copy expression we can ignore it as a dependency. // The copy ensures that the dependency is resolved at the time of invocation. (n is JSStructCopyExpression) || // If a variable is inside an invocation expression we can ignore it as a dependency. // Dependency resolution would have occurred for the invocation already. (n is JSInvocationExpression) ); // Was the result parameter already copied when invoking the function? // If so, we can eliminate the copy of the result because all dependencies have been resolved. // Note that this is separate from the variable dependency extraction above - // if an invocation has multiple variable dependencies, the above merely narrows them down // while this detects cases where there are effectively *no* dependencies of any kind. // This also detects cases where the argument is the result of an invocation or property access // and the result was copied. var isAlreadyCopied = innerValue is JSStructCopyExpression; var dependenciesModified = localVariableDependencies.Any(iv => SecondPass.IsVariableModified(iv.Name)); var copyNeededForTarget = IsCopyNeededForAssignmentTarget(boe.Left); var escapes = invocationSecondPass.DoesVariableEscape(invocationSecondPass.ResultVariable, false); var modified = invocationSecondPass.IsVariableModified(invocationSecondPass.ResultVariable); var traceMessage = (Action)(() => { if (TracePostOptimizeDecisions) { Console.WriteLine( "< {0}: {1} > escapes:{2} modified:{3} copyNeededForTarget({4}):{5} inputsModified:{6}", parameters[parameterIndex].Name, innerValue, escapes, modified, boe.Left, copyNeededForTarget, dependenciesModified ); } }); if (isAlreadyCopied) { eliminateCopy = true; eliminateReason = "Result was already copied as part of argument list"; } else if (!escapes && !dependenciesModified) { if (!copyNeededForTarget) { eliminateCopy = true; eliminateReason = "Target does not require a copy and other criteria are met"; } else if (!modified) { eliminateCopy = true; eliminateReason = "Input not modified, doesn't escape, no dependency changes"; } traceMessage(); } else { traceMessage(); } } } if (eliminateCopy) { if (TracePostOptimizedCopies) { Console.WriteLine("Post-optimized assignment {0} because {1}", boe, eliminateReason); } boe.ReplaceChild(rhsCopy, rhsCopy.Struct); } }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var leftIsEnum = IsEnumOrNullableEnum(leftType); var rightType = boe.Right.GetActualType(TypeSystem); var rightIsEnum = IsEnumOrNullableEnum(rightType); var resultType = boe.GetActualType(TypeSystem); var resultIsEnum = IsEnumOrNullableEnum(resultType); var eitherIsEnum = leftIsEnum || rightIsEnum; if (LogicalOperators.Contains(boe.Operator)) { if (eitherIsEnum) { if (leftIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Left, null, true ); boe.ReplaceChild(boe.Left, cast); } if (rightIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Right, null, true ); boe.ReplaceChild(boe.Right, cast); } } } else if (BitwiseOperators.Contains(boe.Operator)) { var parentCast = ParentNode as JSCastExpression; if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType))) { var cast = JSCastExpression.New( boe, resultType, TypeSystem, true ); ParentNode.ReplaceChild(boe, cast); VisitReplacement(cast); } } VisitChildren(boe); }
void PostOptimizeAssignment (JSBinaryOperatorExpression boe, JSExpression rhs) { var rhsCopy = rhs as JSStructCopyExpression; if (rhsCopy == null) return; var expr = rhsCopy.Struct; var rre = expr as JSResultReferenceExpression; if (rre != null) expr = rre.Referent; var invocation = expr as JSInvocationExpression; if (invocation == null) return; var invokeMethod = invocation.JSMethod; if (invokeMethod == null) return; var invocationSecondPass = GetSecondPass(invokeMethod); if (invocationSecondPass == null) return; bool eliminateCopy = false; string eliminateReason = null; if (invocationSecondPass.ResultIsNew) { // If this expression is the return value of a function invocation, we can eliminate struct // copies if the return value is a 'new' expression. eliminateCopy = true; eliminateReason = "Result is new"; } else if (invocationSecondPass.ResultVariable != null) { // We can also eliminate a return value copy if the return value is one of the function's // arguments, and we are sure that argument does not escape (other than through the return // statement, that is). var parameters = invokeMethod.Method.Parameters; int parameterIndex = -1; for (var i = 0; i < parameters.Length; i++) { if (parameters[i].Name != invocationSecondPass.ResultVariable) continue; parameterIndex = i; break; } // We found a single parameter that acts as the result of this function call. if (parameterIndex >= 0) { GenericParameter relevantParameter; var innerValue = invocation.Arguments[parameterIndex]; // Identify any local variables that are a dependency of the result parameter. var localVariableDependencies = StaticAnalyzer.ExtractInvolvedVariables( innerValue, (n) => // If a variable is inside a copy expression we can ignore it as a dependency. // The copy ensures that the dependency is resolved at the time of invocation. (n is JSStructCopyExpression) || // If a variable is inside an invocation expression we can ignore it as a dependency. // Dependency resolution would have occurred for the invocation already. (n is JSInvocationExpression) ); // Was the result parameter already copied when invoking the function? // If so, we can eliminate the copy of the result because all dependencies have been resolved. // Note that this is separate from the variable dependency extraction above - // if an invocation has multiple variable dependencies, the above merely narrows them down // while this detects cases where there are effectively *no* dependencies of any kind. // This also detects cases where the argument is the result of an invocation or property access // and the result was copied. var isAlreadyCopied = innerValue is JSStructCopyExpression; var dependenciesModified = localVariableDependencies.Any(iv => SecondPass.IsVariableModified(iv.Name)); var copyNeededForTarget = IsCopyNeededForAssignmentTarget(boe.Left); var escapes = invocationSecondPass.DoesVariableEscape(invocationSecondPass.ResultVariable, false); var modified = invocationSecondPass.IsVariableModified(invocationSecondPass.ResultVariable); var traceMessage = (Action)(() => { if (TracePostOptimizeDecisions) Console.WriteLine( "< {0}: {1} > escapes:{2} modified:{3} copyNeededForTarget({4}):{5} inputsModified:{6}", parameters[parameterIndex].Name, innerValue, escapes, modified, boe.Left, copyNeededForTarget, dependenciesModified ); }); if (isAlreadyCopied) { eliminateCopy = true; eliminateReason = "Result was already copied as part of argument list"; } else if (!escapes && !dependenciesModified) { if (!copyNeededForTarget) { eliminateCopy = true; eliminateReason = "Target does not require a copy and other criteria are met"; } else if (!modified) { eliminateCopy = true; eliminateReason = "Input not modified, doesn't escape, no dependency changes"; } traceMessage(); } else { traceMessage(); } } } if (eliminateCopy) { if (TracePostOptimizedCopies) Console.WriteLine("Post-optimized assignment {0} because {1}", boe, eliminateReason); boe.ReplaceChild(rhsCopy, rhsCopy.Struct); } }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetExpectedType(TypeSystem); var leftIsEnum = ILBlockTranslator.IsEnum(leftType); var rightType = boe.Right.GetExpectedType(TypeSystem); var rightIsEnum = ILBlockTranslator.IsEnum(rightType); if ((leftIsEnum || rightIsEnum) && LogicalOperators.Contains(boe.Operator)) { if (leftIsEnum) { var cast = JSInvocationExpression.InvokeMethod( new JSFakeMethod("valueOf", TypeSystem.Int32, leftType), boe.Left, null, true ); boe.ReplaceChild(boe.Left, cast); } if (rightIsEnum) { var cast = JSInvocationExpression.InvokeMethod( new JSFakeMethod("valueOf", TypeSystem.Int32, rightType), boe.Right, null, true ); boe.ReplaceChild(boe.Right, cast); } } VisitChildren(boe); }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var leftIsEnum = IsEnumOrNullableEnum(leftType); var rightType = boe.Right.GetActualType(TypeSystem); var rightIsEnum = IsEnumOrNullableEnum(rightType); var resultType = boe.GetActualType(TypeSystem); var resultIsEnum = IsEnumOrNullableEnum(resultType); var eitherIsEnum = leftIsEnum || rightIsEnum; var assignmentOperator = boe.Operator as JSAssignmentOperator; JSBinaryOperator replacementOperator; if (LogicalOperators.Contains(boe.Operator)) { if (eitherIsEnum) { if (leftIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Left, null, true ); boe.ReplaceChild(boe.Left, cast); } if (rightIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Right, null, true ); boe.ReplaceChild(boe.Right, cast); } } } else if (BitwiseOperators.Contains(boe.Operator)) { var parentCast = ParentNode as JSCastExpression; if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType))) { var cast = JSCastExpression.New( boe, resultType, TypeSystem, true ); ParentNode.ReplaceChild(boe, cast); VisitReplacement(cast); } } else if ( (assignmentOperator != null) && ReverseCompoundAssignments.TryGetValue(assignmentOperator, out replacementOperator) && leftIsEnum ) { var replacement = new JSBinaryOperatorExpression( JSOperator.Assignment, boe.Left, JSCastExpression.New( new JSBinaryOperatorExpression( replacementOperator, boe.Left, boe.Right, TypeSystem.Int32 ), leftType, TypeSystem, true ), leftType ); ParentNode.ReplaceChild(boe, replacement); VisitReplacement(replacement); return; } VisitChildren(boe); }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var leftIsEnum = IsEnumOrNullableEnum(leftType); var rightType = boe.Right.GetActualType(TypeSystem); var rightIsEnum = IsEnumOrNullableEnum(rightType); var resultType = boe.GetActualType(TypeSystem); var resultIsEnum = IsEnumOrNullableEnum(resultType); var eitherIsEnum = leftIsEnum || rightIsEnum; var assignmentOperator = boe.Operator as JSAssignmentOperator; JSBinaryOperator replacementOperator; JSBinaryOperatorExpression replacement; if (LogicalOperators.Contains(boe.Operator)) { if (eitherIsEnum) { if (leftIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Left, null, true ); boe.ReplaceChild(boe.Left, cast); } if (rightIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Right, null, true ); boe.ReplaceChild(boe.Right, cast); } } } else if (BitwiseOperators.Contains(boe.Operator)) { var parentCast = ParentNode as JSCastExpression; var parentReinterpret = Stack.Skip(2).FirstOrDefault() as JSChangeTypeExpression; if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType)) && ((parentReinterpret == null) || (parentReinterpret.NewType != resultType)) ) { var cast = CastToEnumType(boe, resultType); ParentNode.ReplaceChild(boe, cast); VisitReplacement(cast); } } else if ( leftIsEnum && ((replacement = DeconstructMutationAssignment(boe, TypeSystem, TypeSystem.Int32)) != null) ) { ParentNode.ReplaceChild(boe, replacement); VisitReplacement(replacement); return; } VisitChildren(boe); }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var leftIsEnum = IsEnumOrNullableEnum(leftType); var rightType = boe.Right.GetActualType(TypeSystem); var rightIsEnum = IsEnumOrNullableEnum(rightType); var resultType = boe.GetActualType(TypeSystem); var resultIsEnum = IsEnumOrNullableEnum(resultType); var eitherIsEnum = leftIsEnum || rightIsEnum; JSBinaryOperatorExpression replacement; if (LogicalOperators.Contains(boe.Operator)) { if (eitherIsEnum) { if (leftIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Left, null, true ); boe.ReplaceChild(boe.Left, cast); } if (rightIsEnum) { var cast = JSInvocationExpression.InvokeMethod( JS.valueOf(TypeSystem.Int32), boe.Right, null, true ); boe.ReplaceChild(boe.Right, cast); } } } else if (BitwiseOperators.Contains(boe.Operator)) { var parentCast = ParentNode as JSCastExpression; var parentReinterpret = Stack.Skip(2).FirstOrDefault() as JSChangeTypeExpression; if (resultIsEnum && ((parentCast == null) || (parentCast.NewType != resultType)) && ((parentReinterpret == null) || (parentReinterpret.NewType != resultType)) ) { var cast = CastToEnumType(boe, resultType); ParentNode.ReplaceChild(boe, cast); VisitReplacement(cast); } } else if ( leftIsEnum && ((replacement = DeconstructMutationAssignment(boe, TypeSystem, TypeSystem.Int32)) != null) ) { ParentNode.ReplaceChild(boe, replacement); VisitReplacement(replacement); return; } VisitChildren(boe); }
public void VisitNode(JSBinaryOperatorExpression boe) { var leftType = boe.Left.GetActualType(TypeSystem); var rightType = boe.Right.GetActualType(TypeSystem); bool isArithmetic = !(boe.Operator is JSAssignmentOperator); if (!isArithmetic && boe.Operator != JSOperator.Assignment && leftType.FullName == "System.Char") { JSBinaryOperator newOperator; if (boe.Operator == JSOperator.AddAssignment) { newOperator = JSOperator.Add; } else if (boe.Operator == JSOperator.BitwiseAndAssignment) { newOperator = JSOperator.BitwiseAnd; } else if (boe.Operator == JSOperator.BitwiseOrAssignment) { newOperator = JSOperator.BitwiseOr; } else if (boe.Operator == JSOperator.BitwiseXorAssignment) { newOperator = JSOperator.BitwiseXor; } else if (boe.Operator == JSOperator.DivideAssignment) { newOperator = JSOperator.Divide; } else if (boe.Operator == JSOperator.MultiplyAssignment) { newOperator = JSOperator.Multiply; } else if (boe.Operator == JSOperator.RemainderAssignment) { newOperator = JSOperator.Remainder; } else if (boe.Operator == JSOperator.ShiftLeftAssignment) { newOperator = JSOperator.ShiftLeft; } else if (boe.Operator == JSOperator.ShiftRightAssignment) { newOperator = JSOperator.ShiftRight; } else if (boe.Operator == JSOperator.ShiftRightUnsignedAssignment) { newOperator = JSOperator.ShiftRightUnsigned; } else if (boe.Operator == JSOperator.SubtractAssignment) { newOperator = JSOperator.Subtract; } else { throw new InvalidOperationException("Unknown assigment operator"); } var newBoe = new JSBinaryOperatorExpression(JSOperator.Assignment, boe.Left, new JSBinaryOperatorExpression(newOperator, boe.Left, boe.Right, boe.ActualType), boe.ActualType); ParentNode.ReplaceChild(boe, newBoe); VisitReplacement(newBoe); return; } if (boe.Operator == JSOperator.Assignment && (leftType.FullName == "System.Char") && (rightType.FullName != "System.Char")) { boe.ReplaceChild(boe.Right, CastToChar(boe.Right)); } if (boe.Operator == JSOperator.Assignment && (leftType.FullName != "System.Char") && (rightType.FullName == "System.Char")) { boe.ReplaceChild(boe.Right, CastToInteger(boe.Right)); } if ((leftType.FullName == "System.Char") && isArithmetic) { boe.ReplaceChild(boe.Left, CastToInteger(boe.Left)); } if ((rightType.FullName == "System.Char") && isArithmetic) { boe.ReplaceChild(boe.Right, CastToInteger(boe.Right)); } var parentInvocation = ParentNode as JSInvocationExpression; JSDotExpressionBase parentInvocationDot = (parentInvocation != null) ? parentInvocation.Method as JSDotExpressionBase : null; if ( isArithmetic && (boe.GetActualType(TypeSystem).FullName == "System.Char") && !( (parentInvocation != null) && (parentInvocationDot != null) && (parentInvocationDot.Target is JSStringIdentifier) && (((JSStringIdentifier)parentInvocationDot.Target).Identifier == "String") && (parentInvocationDot.Member is JSFakeMethod) && (((JSFakeMethod)parentInvocationDot.Member).Name == "fromCharCode") ) ) { var castBoe = CastToChar(boe); ParentNode.ReplaceChild(boe, castBoe); VisitReplacement(castBoe); } else { VisitChildren(boe); } }