/// <summary> /// Main entry point for lifting; called by both the expression-transform /// and the block transform. /// </summary> ILInstruction Lift(ILInstruction ifInst, ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst) { // ifInst is usually the IfInstruction to which condition belongs; // but can also be a BinaryNumericInstruction. while (condition.MatchLogicNot(out var arg)) { condition = arg; ExtensionMethods.Swap(ref trueInst, ref falseInst); } if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst as IfInstruction)) { var nullPropagated = new NullPropagationTransform(context) .Run(condition, trueInst, falseInst)?.WithILRange(ifInst); if (nullPropagated != null) { return(nullPropagated); } } if (!context.Settings.LiftNullables) { return(null); } if (AnalyzeCondition(condition)) { // (v1 != null && ... && vn != null) ? trueInst : falseInst // => normal lifting return(LiftNormal(trueInst, falseInst)?.WithILRange(ifInst)); } if (MatchCompOrDecimal(condition, out var comp)) { // This might be a C#-style lifted comparison // (C# checks the underlying value before checking the HasValue bits) if (comp.Kind.IsEqualityOrInequality()) { // for equality/inequality, the HasValue bits must also compare equal/inequal if (comp.Kind == ComparisonKind.Inequality) { // handle inequality by swapping one last time ExtensionMethods.Swap(ref trueInst, ref falseInst); } if (falseInst.MatchLdcI4(0)) { // (a.GetValueOrDefault() == b.GetValueOrDefault()) ? (a.HasValue == b.HasValue) : false // => a == b return(LiftCSharpEqualityComparison(comp, ComparisonKind.Equality, trueInst) ?? LiftCSharpUserEqualityComparison(comp, ComparisonKind.Equality, trueInst)); } else if (falseInst.MatchLdcI4(1)) { // (a.GetValueOrDefault() == b.GetValueOrDefault()) ? (a.HasValue != b.HasValue) : true // => a != b return(LiftCSharpEqualityComparison(comp, ComparisonKind.Inequality, trueInst) ?? LiftCSharpUserEqualityComparison(comp, ComparisonKind.Inequality, trueInst)); } else if (IsGenericNewPattern(comp.Left, comp.Right, trueInst, falseInst)) { // (default(T) == null) ? Activator.CreateInstance<T>() : default(T) // => Activator.CreateInstance<T>() return(trueInst); } } else { // Not (in)equality, but one of < <= > >=. // Returns false unless all HasValue bits are true. if (falseInst.MatchLdcI4(0) && AnalyzeCondition(trueInst)) { // comp(lhs, rhs) ? (v1 != null && ... && vn != null) : false // => comp.lifted[C#](lhs, rhs) return(LiftCSharpComparison(comp, comp.Kind)); } else if (trueInst.MatchLdcI4(0) && AnalyzeCondition(falseInst)) { // comp(lhs, rhs) ? false : (v1 != null && ... && vn != null) return(LiftCSharpComparison(comp, comp.Kind.Negate())); } } } ILVariable v; // Handle equality comparisons with bool?: if (MatchGetValueOrDefault(condition, out v) && NullableType.GetUnderlyingType(v.Type).IsKnownType(KnownTypeCode.Boolean)) { if (MatchHasValueCall(trueInst, v) && falseInst.MatchLdcI4(0)) { // v.GetValueOrDefault() ? v.HasValue : false // ==> v == true context.Step("NullableLiftingTransform: v == true", ifInst); return(new Comp(ComparisonKind.Equality, ComparisonLiftingKind.CSharp, StackType.I4, Sign.None, new LdLoc(v).WithILRange(trueInst), new LdcI4(1).WithILRange(falseInst) ).WithILRange(ifInst)); } else if (trueInst.MatchLdcI4(0) && MatchHasValueCall(falseInst, v)) { // v.GetValueOrDefault() ? false : v.HasValue // ==> v == false context.Step("NullableLiftingTransform: v == false", ifInst); return(new Comp(ComparisonKind.Equality, ComparisonLiftingKind.CSharp, StackType.I4, Sign.None, new LdLoc(v).WithILRange(falseInst), trueInst // LdcI4(0) ).WithILRange(ifInst)); } else if (MatchNegatedHasValueCall(trueInst, v) && falseInst.MatchLdcI4(1)) { // v.GetValueOrDefault() ? !v.HasValue : true // ==> v != true context.Step("NullableLiftingTransform: v != true", ifInst); return(new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp, StackType.I4, Sign.None, new LdLoc(v).WithILRange(trueInst), falseInst // LdcI4(1) ).WithILRange(ifInst)); } else if (trueInst.MatchLdcI4(1) && MatchNegatedHasValueCall(falseInst, v)) { // v.GetValueOrDefault() ? true : !v.HasValue // ==> v != false context.Step("NullableLiftingTransform: v != false", ifInst); return(new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp, StackType.I4, Sign.None, new LdLoc(v).WithILRange(falseInst), new LdcI4(0).WithILRange(trueInst) ).WithILRange(ifInst)); } } // Handle & and | on bool?: if (trueInst.MatchLdLoc(out v)) { if (MatchNullableCtor(falseInst, out var utype, out var arg) && utype.IsKnownType(KnownTypeCode.Boolean) && arg.MatchLdcI4(0)) { // condition ? v : (bool?)false // => condition & v context.Step("NullableLiftingTransform: 3vl.bool.and(bool, bool?)", ifInst); return(new ThreeValuedBoolAnd(condition, trueInst).WithILRange(ifInst)); } if (falseInst.MatchLdLoc(out var v2)) { // condition ? v : v2 if (MatchThreeValuedLogicConditionPattern(condition, out var nullable1, out var nullable2)) { // (nullable1.GetValueOrDefault() || (!nullable2.GetValueOrDefault() && !nullable1.HasValue)) ? v : v2 if (v == nullable1 && v2 == nullable2) { context.Step("NullableLiftingTransform: 3vl.bool.or(bool?, bool?)", ifInst); return(new ThreeValuedBoolOr(trueInst, falseInst).WithILRange(ifInst)); } else if (v == nullable2 && v2 == nullable1) { context.Step("NullableLiftingTransform: 3vl.bool.and(bool?, bool?)", ifInst); return(new ThreeValuedBoolAnd(falseInst, trueInst).WithILRange(ifInst)); } } } } else if (falseInst.MatchLdLoc(out v)) { if (MatchNullableCtor(trueInst, out var utype, out var arg) && utype.IsKnownType(KnownTypeCode.Boolean) && arg.MatchLdcI4(1)) { // condition ? (bool?)true : v // => condition | v context.Step("NullableLiftingTransform: 3vl.logic.or(bool, bool?)", ifInst); return(new ThreeValuedBoolOr(condition, falseInst).WithILRange(ifInst)); } } return(null); }
private void HandleType(ResolveResult resolveOperator, string variable, string op_name, KnownTypeCode typeCode) { if (this.AssignmentExpression.Operator == AssignmentOperatorType.Assign) { if (variable != null) { this.Write(variable); } else { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Right }, null, null, 0).Emit(); } return; } var orr = resolveOperator as OperatorResolveResult; var method = orr != null ? orr.UserDefinedOperatorMethod : null; var assigmentType = Helpers.TypeOfAssignment(this.AssignmentExpression.Operator); if (orr != null && method == null) { var name = Helpers.GetBinaryOperatorMethodName(assigmentType); var type = NullableType.IsNullable(orr.Type) ? NullableType.GetUnderlyingType(orr.Type) : orr.Type; method = type.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); } if (method != null) { var inline = this.Emitter.GetInline(method); if (orr.IsLiftedOperator) { this.Write(JS.Types.SYSTEM_NULLABLE + "."); string action = JS.Funcs.Math.LIFT2; this.Write(action); this.WriteOpenParentheses(); this.WriteScript(op_name); this.WriteComma(); if (variable != null) { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left }, null, null, 0).Emit(); } else { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left, this.AssignmentExpression.Right }, null, null, 0).Emit(); } this.AddOveflowFlag(typeCode, op_name); this.WriteCloseParentheses(); } else if (!string.IsNullOrWhiteSpace(inline)) { new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.AssignmentExpression, orr, method), inline).Emit(); } else if (!this.Emitter.Validator.IsExternalType(method.DeclaringTypeDefinition)) { this.Write(BridgeTypes.ToJsName(method.DeclaringType, this.Emitter)); this.WriteDot(); this.Write(OverloadsCollection.Create(this.Emitter, method).GetOverloadName()); this.WriteOpenParentheses(); if (variable != null) { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left }, null, null, 0).Emit(); this.Write(", " + variable); } else { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left, this.AssignmentExpression.Right }, null, null, 0).Emit(); } this.WriteCloseParentheses(); } } else { if (orr.IsLiftedOperator) { this.Write(JS.Types.SYSTEM_NULLABLE + "."); string action = JS.Funcs.Math.LIFT2; this.Write(action); this.WriteOpenParentheses(); this.WriteScript(op_name); this.WriteComma(); if (variable != null) { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left }, null, null, 0).Emit(); } else { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left, this.AssignmentExpression.Right }, null, null, 0).Emit(); } this.AddOveflowFlag(typeCode, op_name); this.WriteCloseParentheses(); } else { this.AssignmentExpression.Left.AcceptVisitor(this.Emitter); this.WriteDot(); this.Write(op_name); this.WriteOpenParentheses(); this.AssignmentExpression.Right.AcceptVisitor(this.Emitter); this.AddOveflowFlag(typeCode, op_name); this.WriteCloseParentheses(); } } }
public static string ToJavascriptName(IType type, IEmitter emitter) { if (type.Kind == TypeKind.Delegate) { var delegateName = BridgeTypes.ConvertName(type.FullName); if (!emitter.JsDoc.Callbacks.Contains(delegateName)) { var method = type.GetDelegateInvokeMethod(); JsDocComment comment = new JsDocComment(); var parameters = method.Parameters; if (parameters != null && parameters.Count > 0) { foreach (var param in parameters) { var jsParam = new JsDocParam(); jsParam.Name = param.Name; jsParam.Type = XmlToJsDoc.ToJavascriptName(param.Type, emitter); comment.Parameters.Add(jsParam); } } comment.Returns.Add(new JsDocParam { Type = XmlToJsDoc.ToJavascriptName(method.ReturnType, emitter) }); comment.Callback = delegateName; comment.MemberOf = type.Namespace; if (!emitter.JsDoc.Namespaces.Contains(type.Namespace)) { emitter.JsDoc.Namespaces.Add(type.Namespace); comment.Namespace = type.Namespace; } emitter.JsDoc.Callbacks.Add(delegateName); emitter.Output.Insert(0, comment.ToString() + newLine + newLine); } return(delegateName); } if (type.IsKnownType(KnownTypeCode.String)) { return("string"); } if (type.IsKnownType(KnownTypeCode.Boolean)) { return("boolean"); } if (type.IsKnownType(KnownTypeCode.Void)) { return("void"); } if (type.IsKnownType(KnownTypeCode.Byte) || type.IsKnownType(KnownTypeCode.Char) || type.IsKnownType(KnownTypeCode.Decimal) || type.IsKnownType(KnownTypeCode.Double) || type.IsKnownType(KnownTypeCode.Int16) || type.IsKnownType(KnownTypeCode.Int32) || type.IsKnownType(KnownTypeCode.Int64) || type.IsKnownType(KnownTypeCode.SByte) || type.IsKnownType(KnownTypeCode.Single) || type.IsKnownType(KnownTypeCode.UInt16) || type.IsKnownType(KnownTypeCode.UInt32) || type.IsKnownType(KnownTypeCode.UInt64)) { return("number"); } if (type.Kind == TypeKind.Array) { ICSharpCode.NRefactory.TypeSystem.ArrayType arrayType = (ICSharpCode.NRefactory.TypeSystem.ArrayType)type; return("Array.<" + XmlToJsDoc.ToJavascriptName(arrayType.ElementType, emitter) + ">"); } if (type.Kind == TypeKind.Dynamic) { return("object"); } if (type.Kind == TypeKind.Enum && type.DeclaringType != null) { return("number"); } if (NullableType.IsNullable(type)) { return("?" + XmlToJsDoc.ToJavascriptName(NullableType.GetUnderlyingType(type), emitter)); } BridgeType bridgeType = emitter.BridgeTypes.Get(type, true); //string name = BridgeTypes.ConvertName(type.FullName); var name = type.Namespace; var hasTypeDef = bridgeType != null && bridgeType.TypeDefinition != null; if (hasTypeDef) { var typeDef = bridgeType.TypeDefinition; if (typeDef.IsNested) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(typeDef); } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(typeDef.Name); } else { if (type.DeclaringType != null) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(type); if (type.DeclaringType.TypeArguments.Count > 0) { name += "$" + type.TypeArguments.Count; } } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(type.Name); } bool isCustomName = false; if (bridgeType != null) { name = BridgeTypes.AddModule(name, bridgeType, out isCustomName); } if (!hasTypeDef && !isCustomName && type.TypeArguments.Count > 0) { name += "$" + type.TypeArguments.Count; } return(name); }
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); 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; 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; } } 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(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.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(add ? JS.Funcs.BRIDGE_COMBINE : JS.Funcs.BRIDGE_REMOVE); this.WriteOpenParentheses(); } } if (isStringConcat) { 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); if (isCoalescing) { this.Write(", "); this.Write(variable); this.Write(strictNullChecks ? " !== null" : " != null"); this.Write(" ? "); this.Write(variable); } 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) { 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) { 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) { this.WriteCloseParentheses(); } }
public static string ToJsName(IType type, IEmitter emitter, bool asDefinition = false, bool excludens = false, bool isAlias = false) { var itypeDef = type.GetDefinition(); if (itypeDef != null) { string globalTarget = BridgeTypes.GetGlobalTarget(itypeDef, null); if (globalTarget != null) { return(globalTarget); } } if (itypeDef != null && itypeDef.Attributes.Any(a => a.AttributeType.FullName == "Bridge.NonScriptableAttribute")) { throw new EmitterException(emitter.Translator.EmitNode, "Type " + type.FullName + " is marked as not usable from script"); } if (type.Kind == TypeKind.Array) { return(JS.Types.ARRAY); } if (type.Kind == TypeKind.Delegate) { return(JS.Types.FUNCTION); } if (type.Kind == TypeKind.Dynamic) { return(JS.Types.OBJECT); } if (NullableType.IsNullable(type)) { return(BridgeTypes.ToJsName(NullableType.GetUnderlyingType(type), emitter)); } if (type.Kind == TypeKind.Anonymous) { var at = type as AnonymousType; if (at != null && emitter.AnonymousTypes.ContainsKey(at)) { return(emitter.AnonymousTypes[at].Name); } else { return("Object"); } } BridgeType bridgeType = emitter.BridgeTypes.Get(type, true); var name = excludens ? "" : type.Namespace; var hasTypeDef = bridgeType != null && bridgeType.TypeDefinition != null; if (hasTypeDef) { var typeDef = bridgeType.TypeDefinition; if (typeDef.IsNested && !excludens) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(typeDef); } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(typeDef.Name); } else { if (type.DeclaringType != null && !excludens) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(type); if (type.DeclaringType.TypeArguments.Count > 0) { name += Helpers.PrefixDollar(type.TypeArguments.Count); } } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(type.Name); } bool isCustomName = false; if (bridgeType != null) { name = BridgeTypes.AddModule(name, bridgeType, out isCustomName); } if (!hasTypeDef && !isCustomName && type.TypeArguments.Count > 0) { name += Helpers.PrefixDollar(type.TypeArguments.Count); } if (isAlias) { name = OverloadsCollection.NormalizeInterfaceName(name); } if (type.TypeArguments.Count > 0 && !Helpers.IsIgnoreGeneric(type, emitter)) { if (isAlias) { StringBuilder sb = new StringBuilder(name); bool needComma = false; sb.Append(JS.Vars.D); bool isStr = false; foreach (var typeArg in type.TypeArguments) { if (sb.ToString().EndsWith(")")) { sb.Append(" + \""); } if (needComma && !sb.ToString().EndsWith(JS.Vars.D.ToString())) { sb.Append(JS.Vars.D); } needComma = true; bool needGet = typeArg.Kind == TypeKind.TypeParameter && !asDefinition; if (needGet) { if (!isStr) { sb.Insert(0, "\""); isStr = true; } sb.Append("\" + Bridge.getTypeAlias("); } var typeArgName = BridgeTypes.ToJsName(typeArg, emitter, false, false, true); if (!needGet && typeArgName.StartsWith("\"")) { sb.Append(typeArgName.Substring(1)); if (!isStr) { isStr = true; sb.Insert(0, "\""); } } else { sb.Append(typeArgName); } if (needGet) { sb.Append(")"); } } if (isStr && !sb.ToString().EndsWith(")")) { sb.Append("\""); } name = sb.ToString(); } else if (!asDefinition) { StringBuilder sb = new StringBuilder(name); bool needComma = false; sb.Append("("); foreach (var typeArg in type.TypeArguments) { if (needComma) { sb.Append(","); } needComma = true; sb.Append(BridgeTypes.ToJsName(typeArg, emitter)); } sb.Append(")"); name = sb.ToString(); } } return(name); }
internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings?settings) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Unknown) { return(false); // avoid introducing a potentially-incorrect compound assignment } else if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, ((PointerType)type).ElementType, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } else if (type.IsKnownType(KnownTypeCode.IntPtr) || type.IsKnownType(KnownTypeCode.UIntPtr)) { // "target.intptr *= 2;" is compiler error, but // "target.intptr *= (nint)2;" works if (settings != null && !settings.NativeIntegers) { // But if native integers are not available, we cannot use compound assignment. return(false); } // The trick with casting the RHS to n(u)int doesn't work for shifts: switch (binary.Operator) { case BinaryNumericOperator.ShiftLeft: case BinaryNumericOperator.ShiftRight: return(false); } } if (binary.Sign != Sign.None) { if (type.IsCSharpSmallIntegerType()) { // C# will use numeric promotion to int, binary op must be signed if (binary.Sign != Sign.Signed) { return(false); } } else { // C# will use sign from type if (type.GetSign() != binary.Sign) { return(false); } } } // Can't transform if the RHS value would be need to be truncated for the LHS type. if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted)) { return(false); } return(true); }
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); 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 isStringConcat = false; /* * if ((leftIsNull || rightIsNull) && (binaryOperatorExpression.Operator == BinaryOperatorType.Equality || binaryOperatorExpression.Operator == BinaryOperatorType.InEquality)) * { * if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality) * { * this.Write("!"); * } * * this.Write(LuaHelper.Root,".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)) { isStringConcat = true; 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 delegateOperator = false; if (this.ResolveOperator(binaryOperatorExpression, orr)) { return; } /* * if (binaryOperatorExpression.Operator == BinaryOperatorType.Divide && * ( * (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("{0}.Number.div(".F(LuaHelper.Root)); * 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 isBool = NullableType.IsNullable(resolveOperator.Type) ? NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.Boolean) : resolveOperator.Type.IsKnownType(KnownTypeCode.Boolean); bool isBitwise = (binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseAnd && !isBool) || (binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseOr && !isBool) || binaryOperatorExpression.Operator == BinaryOperatorType.ExclusiveOr || binaryOperatorExpression.Operator == BinaryOperatorType.ShiftLeft || binaryOperatorExpression.Operator == BinaryOperatorType.ShiftRight; bool isIntDiv = binaryOperatorExpression.Operator == BinaryOperatorType.Divide && ( (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)) ); 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; if (!nullable) { if (isBitwise || isIntDiv) { root = Bridge.Translator.Emitter.ROOT + "."; special = true; rootSpecial = true; } } if (rootSpecial) { this.Write(root); } else if (isStringConcat) { VisitStringConcat(orr, true, charToString == 0); } else { if (isCoalescing) { this.Write("("); variable = this.GetTempVarName(); this.Write(variable); this.Write(" = "); } else if (charToString == 0) { this.Write("string.char("); } binaryOperatorExpression.Left.AcceptVisitor(this.Emitter); if (isCoalescing) { this.Write(", {0}.hasValue(".F(LuaHelper.Root)); this.Write(variable); this.Write(") ? "); this.Write(variable); } else if (charToString == 0) { this.Write(")"); } } if (!delegateOperator) { if (!special) { this.WriteSpace(); } bool isUint = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt16) || resolveOperator.Type.IsKnownType(KnownTypeCode.UInt32) || resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64); bool is64bit = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64) || resolveOperator.Type.IsKnownType(KnownTypeCode.Int64); if (isBitwise && is64bit) { throw new EmitterException(this.BinaryOperatorExpression, "Bitwise operations are not allowed on 64-bit types"); } switch (binaryOperatorExpression.Operator) { case BinaryOperatorType.Add: if (isStringConcat) { this.Write(rootSpecial ? "and" : ".."); } else { this.Write(rootSpecial ? "and" : "+"); } break; case BinaryOperatorType.BitwiseAnd: if (isBool) { this.Write(rootSpecial ? "and" : "and"); } else { this.Write(rootSpecial ? "band" : "&"); } break; case BinaryOperatorType.BitwiseOr: if (isBool) { this.Write(rootSpecial ? "or" : "or"); } else { this.Write(rootSpecial ? "bor" : "|"); } break; case BinaryOperatorType.ConditionalAnd: this.Write(rootSpecial ? "and" : "and"); break; case BinaryOperatorType.NullCoalescing: this.Write(":"); break; case BinaryOperatorType.ConditionalOr: this.Write(rootSpecial ? "or" : "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 ? ">" : ">"); 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 (isStringConcat) { this.WriteSpace(); VisitStringConcat(orr, false, charToString == 1); } else { if (special) { this.WriteOpenParentheses(); if (charToString == 0) { this.Write("string.char("); } binaryOperatorExpression.Left.AcceptVisitor(this.Emitter); if (charToString == 0) { this.Write(")"); } this.WriteComma(); } else { this.WriteSpace(); } if (charToString == 1) { this.Write("string.char("); } binaryOperatorExpression.Right.AcceptVisitor(this.Emitter); if (charToString == 1 || isCoalescing) { this.Write(")"); } if (delegateOperator || special) { this.WriteCloseParentheses(); } } }
private void HandleDecimal(ResolveResult resolveOperator) { if (this.AssignmentExpression.Operator == AssignmentOperatorType.Assign) { new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Right }, null).Emit(); return; } var orr = resolveOperator as OperatorResolveResult; var method = orr != null ? orr.UserDefinedOperatorMethod : null; var assigmentType = Helpers.TypeOfAssignment(this.AssignmentExpression.Operator); if (orr != null && method == null) { var name = Helpers.GetBinaryOperatorMethodName(assigmentType); var type = NullableType.IsNullable(orr.Type) ? NullableType.GetUnderlyingType(orr.Type) : orr.Type; method = type.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); } if (method != null) { var inline = this.Emitter.GetInline(method); if (orr.IsLiftedOperator) { this.Write(Bridge.Translator.Emitter.ROOT + ".Nullable."); string action = "lift2"; string op_name = null; switch (assigmentType) { case BinaryOperatorType.GreaterThan: op_name = "gt"; break; case BinaryOperatorType.GreaterThanOrEqual: op_name = "gte"; break; case BinaryOperatorType.Equality: op_name = "equals"; break; case BinaryOperatorType.InEquality: op_name = "ne"; break; case BinaryOperatorType.LessThan: op_name = "lt"; break; case BinaryOperatorType.LessThanOrEqual: op_name = "lte"; break; case BinaryOperatorType.Add: op_name = "add"; break; case BinaryOperatorType.Subtract: op_name = "sub"; break; case BinaryOperatorType.Multiply: op_name = "mul"; break; case BinaryOperatorType.Divide: op_name = "div"; break; case BinaryOperatorType.Modulus: op_name = "mod"; break; default: throw new ArgumentOutOfRangeException(); } this.Write(action); this.WriteOpenParentheses(); this.WriteScript(op_name); this.WriteComma(); new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left, this.AssignmentExpression.Right }, null).Emit(); this.WriteCloseParentheses(); } else if (!string.IsNullOrWhiteSpace(inline)) { new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.AssignmentExpression, orr, method), inline).Emit(); } else if (!this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition)) { this.Write(BridgeTypes.ToJsName(method.DeclaringType, this.Emitter)); this.WriteDot(); this.Write(OverloadsCollection.Create(this.Emitter, method).GetOverloadName()); this.WriteOpenParentheses(); new ExpressionListBlock(this.Emitter, new Expression[] { this.AssignmentExpression.Left, this.AssignmentExpression.Right }, null).Emit(); this.WriteCloseParentheses(); } } }
public static string ToJsName(IType type, IEmitter emitter, bool asDefinition = false, bool excludens = false, ToNameTypeEnum kind = ToNameTypeEnum.None) { if (NullableType.IsNullable(type)) { return(BridgeTypes.ToJsName(NullableType.GetUnderlyingType(type), emitter)); } if (type.Kind == TypeKind.Delegate) { return("System.Delegate"); } BridgeType bridgeType = emitter.BridgeTypes.Get(type, true); var name = excludens ? "" : XmlMetaMaker.GetNamespace(bridgeType != null ? bridgeType.Type.Namespace : type.Namespace); var hasTypeDef = bridgeType != null && bridgeType.TypeDefinition != null; if (hasTypeDef) { var typeDef = bridgeType.TypeDefinition; if (typeDef.IsNested && !excludens) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(typeDef); } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(typeDef.Name); } else { if (type.DeclaringType != null && !excludens) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(type); if (type.DeclaringType.TypeArguments.Count > 0) { name += "_" + type.TypeArguments.Count; } } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(type.Name); } bool isCustomName = false; if (bridgeType != null) { name = BridgeTypes.AddModule(name, bridgeType, out isCustomName); } if (kind == ToNameTypeEnum.None) { int pos = name.LastIndexOf('.'); if (pos != -1) { string prefix = name.Substring(0, pos); if (prefix != "System") { TransformCtx.CurUsingNamespaces.Add(prefix); string newPrefix = prefix.Replace(".", ""); if (newPrefix == prefix) { newPrefix = '_' + newPrefix; } name = newPrefix + name.Substring(pos); } } } if (!hasTypeDef && !isCustomName && type.TypeArguments.Count > 0) { name += "_" + type.TypeArguments.Count; } if (!asDefinition && type.TypeArguments.Count > 0 && !Helpers.IsIgnoreGeneric(type, emitter)) { StringBuilder sb = new StringBuilder(name); bool needComma = false; sb.Append("("); foreach (var typeArg in type.TypeArguments) { if (needComma) { sb.Append(", "); } needComma = true; sb.Append(BridgeTypes.ToNameIgnoreEnum(typeArg, emitter, kind)); } sb.Append(")"); name = sb.ToString(); } else if (type.Kind == TypeKind.Array) { name += "(" + BridgeTypes.ToNameIgnoreEnum(((ICSharpCode.NRefactory.TypeSystem.ArrayType)type).ElementType, emitter) + ")"; } return(name); }
public static void CheckInteger(ConversionBlock block, Expression expression, IType type) { NarrowingNumericOrEnumerationConversion(block, expression, NullableType.IsNullable(type) ? NullableType.GetUnderlyingType(type) : type, false, true, NullableType.IsNullable(type)); }
public static void FloatToInt(ConversionBlock block, Expression expression, IType sourceType, IType targetType, bool isChecked) { NarrowingNumericOrEnumerationConversion(block, expression, NullableType.IsNullable(targetType) ? NullableType.GetUnderlyingType(targetType) : targetType, true, isChecked, NullableType.IsNullable(sourceType)); }
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 += ")"; } } } }
private static void CheckLong(ConversionBlock block, Expression expression, IType expectedType, IType fromType, bool isChecked) { if (!NeedsNarrowingNumericConversion(fromType, expectedType)) { return; } if (isChecked) { expectedType = NullableType.IsNullable(expectedType) ? NullableType.GetUnderlyingType(expectedType) : expectedType; block.Write(JS.Types.System.Int64.CHECK); block.WriteOpenParentheses(); block.AfterOutput += ", "; block.AfterOutput += BridgeTypes.ToJsName(expectedType, block.Emitter); block.AfterOutput += ")"; } else { string action = null; expectedType = NullableType.IsNullable(expectedType) ? NullableType.GetUnderlyingType(expectedType) : expectedType; if (block.Emitter.IsJavaScriptOverflowMode && !InsideOverflowContext(block.Emitter, expression)) { action = "toNumber"; } else if (expectedType.IsKnownType(KnownTypeCode.Char)) { action = "clipu16"; } else if (expectedType.IsKnownType(KnownTypeCode.SByte)) { action = "clip8"; } else if (expectedType.IsKnownType(KnownTypeCode.Byte)) { action = "clipu8"; } else if (expectedType.IsKnownType(KnownTypeCode.Int16)) { action = "clip16"; } else if (expectedType.IsKnownType(KnownTypeCode.UInt16)) { action = "clipu16"; } else if (expectedType.IsKnownType(KnownTypeCode.Int32)) { action = "clip32"; } else if (expectedType.IsKnownType(KnownTypeCode.UInt32)) { action = "clipu32"; } else if (expectedType.IsKnownType(KnownTypeCode.Int64)) { action = "clip64"; } else if (expectedType.IsKnownType(KnownTypeCode.UInt64)) { action = "clipu64"; } else { throw new ArgumentException("Can not narrow to " + expectedType, "expectedType"); } block.Write(JS.Types.System.Int64.NAME + "."); block.Write(action); block.Write("("); block.AfterOutput += ")"; } }
bool MatchDisposeBlock(BlockContainer container, ILVariable objVar, bool usingNull) { var entryPoint = container.EntryPoint; if (entryPoint.Instructions.Count < 2 || entryPoint.Instructions.Count > 3 || entryPoint.IncomingEdgeCount != 1) { return(false); } int leaveIndex = entryPoint.Instructions.Count == 2 ? 1 : 2; int checkIndex = entryPoint.Instructions.Count == 2 ? 0 : 1; int castIndex = entryPoint.Instructions.Count == 3 ? 0 : -1; bool isReference = objVar.Type.IsReferenceType != false; if (castIndex > -1) { if (!entryPoint.Instructions[castIndex].MatchStLoc(out var tempVar, out var isinst)) { return(false); } if (!isinst.MatchIsInst(out var load, out var disposableType) || !load.MatchLdLoc(objVar) || !disposableType.IsKnownType(KnownTypeCode.IDisposable)) { return(false); } if (tempVar.StoreCount != 1 || tempVar.LoadCount != 2) { return(false); } objVar = tempVar; isReference = true; } if (!entryPoint.Instructions[leaveIndex].MatchLeave(container, out var returnValue) || !returnValue.MatchNop()) { return(false); } CallVirt callVirt; if (objVar.Type.IsKnownType(KnownTypeCode.NullableOfT)) { if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst)) { return(false); } if (!(NullableLiftingTransform.MatchHasValueCall(condition, out var v) && v == objVar)) { return(false); } if (!(disposeInst is Block disposeBlock) || disposeBlock.Instructions.Count != 1) { return(false); } if (!(disposeBlock.Instructions[0] is CallVirt cv)) { return(false); } callVirt = cv; if (callVirt.Method.FullName != "System.IDisposable.Dispose") { return(false); } if (callVirt.Method.Parameters.Count > 0) { return(false); } if (callVirt.Arguments.Count != 1) { return(false); } var firstArg = cv.Arguments.FirstOrDefault(); if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) { if (!firstArg.MatchAddressOf(out var innerArg2)) { return(false); } return(NullableLiftingTransform.MatchGetValueOrDefault(innerArg2, objVar)); } else { if (!(innerArg1.MatchBox(out firstArg, out var boxType) && boxType.IsKnownType(KnownTypeCode.NullableOfT) && NullableType.GetUnderlyingType(boxType).Equals(NullableType.GetUnderlyingType(objVar.Type)))) { return(false); } return(firstArg.MatchLdLoc(objVar)); } }
protected virtual void EmitCastExpression(Expression expression, AstType type, string method) { var castToEnum = this.Emitter.BridgeTypes.ToType(type).Kind == TypeKind.Enum; if (method != Bridge.Translator.Emitter.IS && (Helpers.IsIgnoreCast(type, this.Emitter) || castToEnum)) { expression.AcceptVisitor(this.Emitter); return; } if (method == Bridge.Translator.Emitter.IS && castToEnum) { this.Write("Bridge.hasValue("); expression.AcceptVisitor(this.Emitter); this.Write(")"); return; } var expressionrr = this.Emitter.Resolver.ResolveNode(expression, this.Emitter); var typerr = this.Emitter.Resolver.ResolveNode(type, this.Emitter); if (expressionrr.Type.Equals(typerr.Type)) { if (method == Bridge.Translator.Emitter.IS) { this.WriteScript(true); } else { expression.AcceptVisitor(this.Emitter); } return; } bool isInlineCast; string castCode = this.GetCastCode(expression, type, out isInlineCast); bool isNullable = NullableType.IsNullable(expressionrr.Type); bool isResultNullable = NullableType.IsNullable(typerr.Type); if (isInlineCast) { if (isNullable) { isNullable = !NullableType.GetUnderlyingType(expressionrr.Type).Equals(typerr.Type); } this.EmitInlineCast(expression, type, castCode, isNullable, isResultNullable); return; } if (method == Bridge.Translator.Emitter.CAST) { if (Helpers.IsIntegerType(typerr.Type, this.Emitter.Resolver)) { if (expressionrr.Type != null && Helpers.IsFloatType(expressionrr.Type, this.Emitter.Resolver)) { this.Write("Bridge.Int.trunc("); if (isNullable && !isResultNullable) { this.Write("Bridge.Nullable.getValue("); } expression.AcceptVisitor(this.Emitter); if (isNullable && !isResultNullable) { this.WriteCloseParentheses(); } this.Write(")"); return; } } if (ConversionBlock.IsUserDefinedConversion(this, this.CastExpression.Expression)) { expression.AcceptVisitor(this.Emitter); return; } } var simpleType = type as SimpleType; bool hasValue = false; if (simpleType != null && simpleType.Identifier == "dynamic") { if (method == Bridge.Translator.Emitter.CAST || method == Bridge.Translator.Emitter.AS) { expression.AcceptVisitor(this.Emitter); return; } else if (method == Bridge.Translator.Emitter.IS) { hasValue = true; method = "hasValue"; } } this.Write(Bridge.Translator.Emitter.ROOT); this.WriteDot(); this.Write(method); this.WriteOpenParentheses(); if (isNullable && !isResultNullable) { this.Write("Bridge.Nullable.getValue("); } expression.AcceptVisitor(this.Emitter); if (isNullable && !isResultNullable) { this.WriteCloseParentheses(); } if (!hasValue) { this.WriteComma(); if (castCode != null) { this.Write(castCode); } else { this.EmitCastType(type); } } if (isResultNullable && method != Bridge.Translator.Emitter.IS) { this.WriteComma(); this.WriteScript(true); } this.WriteCloseParentheses(); }
public static string ToTypeScriptName(IType type, IEmitter emitter, bool asDefinition = false, bool excludens = false, bool ignoreDependency = false) { if (type.Kind == TypeKind.Delegate) { var method = type.GetDelegateInvokeMethod(); StringBuilder sb = new StringBuilder(); sb.Append("{"); sb.Append("("); var last = method.Parameters.LastOrDefault(); foreach (var p in method.Parameters) { var ptype = BridgeTypes.ToTypeScriptName(p.Type, emitter); if (p.IsOut || p.IsRef) { ptype = "{v: " + ptype + "}"; } sb.Append(p.Name + ": " + ptype); if (p != last) { sb.Append(", "); } } sb.Append(")"); sb.Append(": "); sb.Append(BridgeTypes.ToTypeScriptName(method.ReturnType, emitter)); sb.Append("}"); return(sb.ToString()); } if (type.IsKnownType(KnownTypeCode.String)) { return("string"); } if (type.IsKnownType(KnownTypeCode.Boolean)) { return("boolean"); } if (type.IsKnownType(KnownTypeCode.Void)) { return("void"); } if (type.IsKnownType(KnownTypeCode.Byte) || type.IsKnownType(KnownTypeCode.Char) || type.IsKnownType(KnownTypeCode.Decimal) || type.IsKnownType(KnownTypeCode.Double) || type.IsKnownType(KnownTypeCode.Int16) || type.IsKnownType(KnownTypeCode.Int32) || type.IsKnownType(KnownTypeCode.Int64) || type.IsKnownType(KnownTypeCode.SByte) || type.IsKnownType(KnownTypeCode.Single) || type.IsKnownType(KnownTypeCode.UInt16) || type.IsKnownType(KnownTypeCode.UInt32) || type.IsKnownType(KnownTypeCode.UInt64)) { return("number"); } if (type.Kind == TypeKind.Array) { ICSharpCode.NRefactory.TypeSystem.ArrayType arrayType = (ICSharpCode.NRefactory.TypeSystem.ArrayType)type; return(BridgeTypes.ToTypeScriptName(arrayType.ElementType, emitter, asDefinition, excludens) + "[]"); } if (type.Kind == TypeKind.Dynamic) { return("any"); } if (type.Kind == TypeKind.Enum && type.DeclaringType != null && !excludens) { return("number"); } if (NullableType.IsNullable(type)) { return(BridgeTypes.ToTypeScriptName(NullableType.GetUnderlyingType(type), emitter, asDefinition, excludens)); } BridgeType bridgeType = emitter.BridgeTypes.Get(type, true); //string name = BridgeTypes.ConvertName(excludens ? type.Name : type.FullName); var name = excludens ? "" : type.Namespace; var hasTypeDef = bridgeType != null && bridgeType.TypeDefinition != null; if (hasTypeDef) { var typeDef = bridgeType.TypeDefinition; if (typeDef.IsNested && !excludens) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(typeDef); } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(typeDef.Name); } else { if (type.DeclaringType != null && !excludens) { name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(type); if (type.DeclaringType.TypeArguments.Count > 0) { name += "$" + type.TypeArguments.Count; } } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(type.Name); } bool isCustomName = false; if (bridgeType != null) { if (!ignoreDependency && emitter.AssemblyInfo.OutputBy != OutputBy.Project && bridgeType.TypeInfo != null && bridgeType.TypeInfo.Namespace != emitter.TypeInfo.Namespace) { var info = BridgeTypes.GetNamespaceFilename(bridgeType.TypeInfo, emitter); var ns = info.Item1; var fileName = info.Item2; if (!emitter.CurrentDependencies.Any(d => d.DependencyName == fileName)) { emitter.CurrentDependencies.Add(new ModuleDependency() { DependencyName = fileName }); } } name = BridgeTypes.AddModule(name, bridgeType, out isCustomName); } if (!hasTypeDef && !isCustomName && type.TypeArguments.Count > 0) { name += "$" + type.TypeArguments.Count; } if (!asDefinition && type.TypeArguments.Count > 0 && !Helpers.IsIgnoreGeneric(type, emitter)) { StringBuilder sb = new StringBuilder(name); bool needComma = false; sb.Append("<"); foreach (var typeArg in type.TypeArguments) { if (needComma) { sb.Append(","); } needComma = true; sb.Append(BridgeTypes.ToTypeScriptName(typeArg, emitter, asDefinition, excludens)); } sb.Append(">"); name = sb.ToString(); } return(name); }
protected virtual string GetCastCode(Expression expression, AstType astType, out bool isInline) { var resolveResult = this.Emitter.Resolver.ResolveNode(astType, this.Emitter) as TypeResolveResult; var exprResolveResult = this.Emitter.Resolver.ResolveNode(expression, this.Emitter); string inline = null; isInline = false; var method = this.GetCastMethod(exprResolveResult.Type, resolveResult.Type, out inline); if (method == null && (NullableType.IsNullable(exprResolveResult.Type) || NullableType.IsNullable(resolveResult.Type))) { method = this.GetCastMethod(NullableType.IsNullable(exprResolveResult.Type) ? NullableType.GetUnderlyingType(exprResolveResult.Type) : exprResolveResult.Type, NullableType.IsNullable(resolveResult.Type) ? NullableType.GetUnderlyingType(resolveResult.Type) : resolveResult.Type, out inline); } if (inline != null) { this.InlineMethod = method; isInline = true; return(inline); } return(null); }
protected virtual void EmitCastExpression(Expression expression, AstType type, string method) { var itype = this.Emitter.BridgeTypes.ToType(type); bool isCastAttr; string castCode = this.GetCastCode(expression, type, out isCastAttr); var enumType = itype; if (NullableType.IsNullable(enumType)) { enumType = NullableType.GetUnderlyingType(enumType); } var castToEnum = enumType.Kind == TypeKind.Enum; if (castToEnum) { itype = enumType.GetDefinition().EnumUnderlyingType; var enumMode = Helpers.EnumEmitMode(enumType); if (enumMode >= 3 && enumMode < 7) { itype = this.Emitter.Resolver.Compilation.FindType(KnownTypeCode.String); } } if (expression is NullReferenceExpression || (method != CS.Ops.IS && Helpers.IsIgnoreCast(type, this.Emitter))) { if (expression is ParenthesizedExpression) { expression = ((ParenthesizedExpression)expression).Expression; } expression.AcceptVisitor(this.Emitter); return; } var expressionrr = this.Emitter.Resolver.ResolveNode(expression, this.Emitter); var typerr = this.Emitter.Resolver.ResolveNode(type, this.Emitter); if (expressionrr.Type.Kind == TypeKind.Enum) { var enumMode = Helpers.EnumEmitMode(expressionrr.Type); if (enumMode >= 3 && enumMode < 7 && Helpers.IsIntegerType(itype, this.Emitter.Resolver)) { throw new EmitterException(this.CastExpression, "Enum underlying type is string and cannot be casted to number"); } } if (method == CS.Ops.CAST && expressionrr.Type.Kind != TypeKind.Enum) { var cast_rr = this.Emitter.Resolver.ResolveNode(this.CastExpression, this.Emitter); if (cast_rr is ConstantResolveResult) { var expectedType = this.Emitter.Resolver.Resolver.GetExpectedType(this.CastExpression); var value = ((ConstantResolveResult)cast_rr).ConstantValue; this.WriteCastValue(value, expectedType); return; } else { var conv_rr = cast_rr as ConversionResolveResult; if (conv_rr != null && conv_rr.Input is ConstantResolveResult && !conv_rr.Conversion.IsUserDefined) { var expectedType = this.Emitter.Resolver.Resolver.GetExpectedType(this.CastExpression); var value = ((ConstantResolveResult)conv_rr.Input).ConstantValue; this.WriteCastValue(value, expectedType); return; } } } if (method == CS.Ops.IS && castToEnum) { this.Write(JS.Types.Bridge.IS); this.WriteOpenParentheses(); expression.AcceptVisitor(this.Emitter); this.Write(", "); this.Write(BridgeTypes.ToJsName(itype, this.Emitter)); this.Write(")"); return; } if (expressionrr.Type.Equals(itype)) { if (method == CS.Ops.IS) { this.Write(JS.Funcs.BRIDGE_HASVALUE); this.WriteOpenParentheses(); } expression.AcceptVisitor(this.Emitter); if (method == CS.Ops.IS) { this.Write(")"); } return; } bool isResultNullable = NullableType.IsNullable(typerr.Type); if (castCode != null) { this.EmitInlineCast(expressionrr, expression, type, castCode, isCastAttr, method); return; } bool isCast = method == CS.Ops.CAST; if (isCast) { if (ConversionBlock.IsUserDefinedConversion(this, this.CastExpression.Expression) || ConversionBlock.IsUserDefinedConversion(this, this.CastExpression)) { expression.AcceptVisitor(this.Emitter); return; } } var conversion = this.Emitter.Resolver.Resolver.GetConversion(expression); if (conversion.IsNumericConversion || conversion.IsEnumerationConversion || (isCast && conversion.IsIdentityConversion)) { expression.AcceptVisitor(this.Emitter); return; } var simpleType = type as SimpleType; bool hasValue = false; if (simpleType != null && simpleType.Identifier == "dynamic") { if (method == CS.Ops.CAST || method == CS.Ops.AS) { expression.AcceptVisitor(this.Emitter); return; } else if (method == CS.Ops.IS) { hasValue = true; method = "hasValue"; } } bool unbox = !(itype.IsReferenceType.HasValue ? itype.IsReferenceType.Value : true) && !NullableType.IsNullable(itype) && isCast && conversion.IsUnboxingConversion; if (unbox) { this.Write("System.Nullable.getValue("); } this.Write(JS.NS.BRIDGE); this.WriteDot(); this.Write(method); this.WriteOpenParentheses(); expression.AcceptVisitor(this.Emitter); if (!hasValue) { this.WriteComma(); this.EmitCastType(itype); } if (isResultNullable && method != CS.Ops.IS) { this.WriteComma(); this.WriteScript(true); } this.WriteCloseParentheses(); if (unbox) { this.Write(")"); } }
protected void VisitIdentifierExpression() { IdentifierExpression identifierExpression = this.IdentifierExpression; int pos = this.Emitter.Output.Length; ResolveResult resolveResult = null; this.isRefArg = this.Emitter.IsRefArg; this.Emitter.IsRefArg = false; resolveResult = this.Emitter.Resolver.ResolveNode(identifierExpression, this.Emitter); var id = identifierExpression.Identifier; var isResolved = resolveResult != null && !(resolveResult is ErrorResolveResult); var memberResult = resolveResult as MemberResolveResult; if (this.Emitter.Locals != null && this.Emitter.Locals.ContainsKey(id) && resolveResult is LocalResolveResult) { var lrr = (LocalResolveResult)resolveResult; if (this.Emitter.LocalsMap != null && this.Emitter.LocalsMap.ContainsKey(lrr.Variable) && !(identifierExpression.Parent is DirectionExpression)) { this.Write(this.Emitter.LocalsMap[lrr.Variable]); } else if (this.Emitter.LocalsNamesMap != null && this.Emitter.LocalsNamesMap.ContainsKey(id)) { this.Write(this.Emitter.LocalsNamesMap[id]); } else { this.Write(id); } Helpers.CheckValueTypeClone(resolveResult, identifierExpression, this, pos); return; } if (resolveResult is TypeResolveResult) { this.Write(BridgeTypes.ToJsName(resolveResult.Type, this.Emitter)); /*if (this.Emitter.Validator.IsExternalType(resolveResult.Type.GetDefinition()) || resolveResult.Type.Kind == TypeKind.Enum) * { * this.Write(BridgeTypes.ToJsName(resolveResult.Type, this.Emitter)); * } * else * { * this.Write("Bridge.get(" + BridgeTypes.ToJsName(resolveResult.Type, this.Emitter) + ")"); * }*/ return; } string inlineCode = memberResult != null?this.Emitter.GetInline(memberResult.Member) : null; var isInvoke = identifierExpression.Parent is InvocationExpression && (((InvocationExpression)(identifierExpression.Parent)).Target == identifierExpression); if (memberResult != null && memberResult.Member is IMethod && isInvoke) { var i_rr = this.Emitter.Resolver.ResolveNode(identifierExpression.Parent, this.Emitter) as CSharpInvocationResolveResult; if (i_rr != null && !i_rr.IsExpandedForm) { var tpl = this.Emitter.GetAttribute(memberResult.Member.Attributes, JS.NS.BRIDGE + ".TemplateAttribute"); if (tpl != null && tpl.PositionalArguments.Count == 2) { inlineCode = tpl.PositionalArguments[1].ConstantValue.ToString(); } } } if (string.IsNullOrEmpty(inlineCode) && memberResult != null && memberResult.Member is IMethod && !(memberResult is InvocationResolveResult) && !( identifierExpression.Parent is InvocationExpression && identifierExpression.NextSibling != null && identifierExpression.NextSibling.Role is TokenRole && ((TokenRole)identifierExpression.NextSibling.Role).Token == "(" ) ) { var method = (IMethod)memberResult.Member; if (method.TypeArguments.Count > 0) { inlineCode = MemberReferenceBlock.GenerateInlineForMethodReference(method, this.Emitter); } } bool hasInline = !string.IsNullOrEmpty(inlineCode); bool hasThis = hasInline && inlineCode.Contains("{this}"); if (hasInline && inlineCode.StartsWith("<self>")) { hasThis = true; inlineCode = inlineCode.Substring(6); } if (hasThis) { Emitter.ThisRefCounter++; this.Write(""); var oldBuilder = this.Emitter.Output; this.Emitter.Output = new StringBuilder(); if (memberResult.Member.IsStatic) { this.Write(BridgeTypes.ToJsName(memberResult.Member.DeclaringType, this.Emitter)); /*if (!this.Emitter.Validator.IsExternalType(memberResult.Member.DeclaringTypeDefinition) && memberResult.Member.DeclaringTypeDefinition.Kind != TypeKind.Enum) * { * this.Write("(Bridge.get(" + BridgeTypes.ToJsName(memberResult.Member.DeclaringType, this.Emitter) + "))"); * } * else * { * this.Write(BridgeTypes.ToJsName(memberResult.Member.DeclaringType, this.Emitter)); * }*/ } else { this.WriteThis(); } var oldInline = inlineCode; var thisArg = this.Emitter.Output.ToString(); int thisIndex = inlineCode.IndexOf("{this}"); inlineCode = inlineCode.Replace("{this}", thisArg); this.Emitter.Output = oldBuilder; int[] range = null; if (thisIndex > -1) { range = new[] { thisIndex, thisIndex + thisArg.Length }; } if (resolveResult is InvocationResolveResult) { this.PushWriter(inlineCode, null, thisArg, range); } else { if (memberResult.Member is IMethod) { ResolveResult targetrr = null; if (memberResult.Member.IsStatic) { targetrr = new TypeResolveResult(memberResult.Member.DeclaringType); } new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.IdentifierExpression, resolveResult), oldInline, (IMethod)memberResult.Member, targetrr).EmitFunctionReference(); } else if (memberResult != null && memberResult.Member is IField && inlineCode.Contains("{0}")) { this.PushWriter(inlineCode, null, thisArg, range); } else if (InlineArgumentsBlock.FormatArgRegex.IsMatch(inlineCode)) { this.PushWriter(inlineCode, null, thisArg, range); } else { this.Write(inlineCode); } } return; } if (hasInline) { if (!memberResult.Member.IsStatic) { inlineCode = "this." + inlineCode; } if (resolveResult is InvocationResolveResult) { this.PushWriter(inlineCode); } else { if (memberResult.Member is IMethod) { ResolveResult targetrr = null; if (memberResult.Member.IsStatic) { targetrr = new TypeResolveResult(memberResult.Member.DeclaringType); } new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.IdentifierExpression, resolveResult), inlineCode, (IMethod)memberResult.Member, targetrr).EmitFunctionReference(); } else if (InlineArgumentsBlock.FormatArgRegex.IsMatch(inlineCode)) { this.PushWriter(inlineCode); } else { this.Write(inlineCode); } } return; } string appendAdditionalCode = null; if (memberResult != null && memberResult.Member is IMethod && !(memberResult is InvocationResolveResult) && !( identifierExpression.Parent is InvocationExpression && identifierExpression.NextSibling != null && identifierExpression.NextSibling.Role is TokenRole && ((TokenRole)identifierExpression.NextSibling.Role).Token == "(" ) ) { if (!string.IsNullOrEmpty(inlineCode)) { ResolveResult targetrr = null; if (memberResult.Member.IsStatic) { targetrr = new TypeResolveResult(memberResult.Member.DeclaringType); } new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, identifierExpression, resolveResult), inlineCode, (IMethod)memberResult.Member, targetrr).EmitFunctionReference(); } else { var resolvedMethod = (IMethod)memberResult.Member; bool isStatic = resolvedMethod != null && resolvedMethod.IsStatic; if (!isStatic) { var isExtensionMethod = resolvedMethod.IsExtensionMethod; this.Write(isExtensionMethod ? JS.Funcs.BRIDGE_BIND_SCOPE : JS.Funcs.BRIDGE_CACHE_BIND); this.WriteOpenParentheses(); this.WriteThis(); this.Write(", "); appendAdditionalCode = ")"; } } } if (memberResult != null && memberResult.Member.SymbolKind == SymbolKind.Field && this.Emitter.IsMemberConst(memberResult.Member) && this.Emitter.IsInlineConst(memberResult.Member)) { this.WriteScript(memberResult.ConstantValue); return; } if (memberResult != null && memberResult.Member.SymbolKind == SymbolKind.Property && memberResult.TargetResult.Type.Kind != TypeKind.Anonymous) { bool isStatement = false; string valueVar = null; if (this.Emitter.IsUnaryAccessor) { isStatement = identifierExpression.Parent is UnaryOperatorExpression && identifierExpression.Parent.Parent is ExpressionStatement; if (NullableType.IsNullable(memberResult.Type)) { isStatement = false; } if (!isStatement) { this.WriteOpenParentheses(); valueVar = this.GetTempVarName(); this.Write(valueVar); this.Write(" = "); } } this.WriteTarget(memberResult); if (!string.IsNullOrWhiteSpace(inlineCode)) { //this.Write(inlineCode); if (resolveResult is InvocationResolveResult || (memberResult.Member.SymbolKind == SymbolKind.Property && this.Emitter.IsAssignment)) { this.PushWriter(inlineCode); } else { this.Write(inlineCode); } } else if (memberResult.Member is IProperty) { var name = Helpers.GetPropertyRef(memberResult.Member, this.Emitter); this.WriteIdentifier(name); } else if (!this.Emitter.IsAssignment) { if (this.Emitter.IsUnaryAccessor) { bool isDecimal = Helpers.IsDecimalType(memberResult.Member.ReturnType, this.Emitter.Resolver); bool isLong = Helpers.Is64Type(memberResult.Member.ReturnType, this.Emitter.Resolver); bool isNullable = NullableType.IsNullable(memberResult.Member.ReturnType); if (isStatement) { this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, true)); this.WriteOpenParentheses(); if (isDecimal || isLong) { if (isNullable) { this.Write(JS.Types.SYSTEM_NULLABLE + "." + JS.Funcs.Math.LIFT1); this.WriteOpenParentheses(); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.PostIncrement) { this.WriteScript(JS.Funcs.Math.INC); } else { this.WriteScript(JS.Funcs.Math.DEC); } this.WriteComma(); this.WriteTarget(memberResult); this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, false)); this.WriteOpenParentheses(); this.WriteCloseParentheses(); this.WriteCloseParentheses(); } else { this.WriteTarget(memberResult); this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, false)); this.WriteOpenParentheses(); this.WriteCloseParentheses(); this.WriteDot(); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.PostIncrement) { this.Write(JS.Funcs.Math.INC); } else { this.Write(JS.Funcs.Math.DEC); } this.WriteOpenParentheses(); this.WriteCloseParentheses(); } } else { this.WriteTarget(memberResult); this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, false)); this.WriteOpenParentheses(); this.WriteCloseParentheses(); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.PostIncrement) { this.Write("+"); } else { this.Write("-"); } this.Write("1"); } this.WriteCloseParentheses(); } else { this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, false)); this.WriteOpenParentheses(); this.WriteCloseParentheses(); this.WriteComma(); this.WriteTarget(memberResult); this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, true)); this.WriteOpenParentheses(); if (isDecimal || isLong) { if (isNullable) { this.Write(JS.Types.SYSTEM_NULLABLE + "." + JS.Funcs.Math.LIFT1); this.WriteOpenParentheses(); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.PostIncrement) { this.WriteScript(JS.Funcs.Math.INC); } else { this.WriteScript(JS.Funcs.Math.DEC); } this.WriteComma(); this.Write(valueVar); this.WriteCloseParentheses(); } else { this.Write(valueVar); this.WriteDot(); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.PostIncrement) { this.Write(JS.Funcs.Math.INC); } else { this.Write(JS.Funcs.Math.DEC); } this.WriteOpenParentheses(); this.WriteCloseParentheses(); } } else { this.Write(valueVar); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.PostIncrement) { this.Write("+"); } else { this.Write("-"); } this.Write("1"); } this.WriteCloseParentheses(); this.WriteComma(); if (this.Emitter.UnaryOperatorType == UnaryOperatorType.Increment || this.Emitter.UnaryOperatorType == UnaryOperatorType.Decrement) { this.WriteTarget(memberResult); this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, false)); this.WriteOpenParentheses(); this.WriteCloseParentheses(); } else { this.Write(valueVar); } this.WriteCloseParentheses(); if (valueVar != null) { this.RemoveTempVar(valueVar); } } } else { this.Write(Helpers.GetPropertyRef(memberResult.Member, this.Emitter)); this.WriteOpenParentheses(); this.WriteCloseParentheses(); } } else if (this.Emitter.AssignmentType != AssignmentOperatorType.Assign) { string trg; if (memberResult.Member.IsStatic) { trg = BridgeTypes.ToJsName(memberResult.Member.DeclaringType, this.Emitter); } else { trg = "this"; } bool isBool = memberResult != null && NullableType.IsNullable(memberResult.Member.ReturnType) ? NullableType.GetUnderlyingType(memberResult.Member.ReturnType).IsKnownType(KnownTypeCode.Boolean) : memberResult.Member.ReturnType.IsKnownType(KnownTypeCode.Boolean); bool skipGet = false; var orr = this.Emitter.Resolver.ResolveNode(identifierExpression.Parent, this.Emitter) as OperatorResolveResult; bool special = orr != null && orr.IsLiftedOperator; if (!special && isBool && (this.Emitter.AssignmentType == AssignmentOperatorType.BitwiseAnd || this.Emitter.AssignmentType == AssignmentOperatorType.BitwiseOr)) { skipGet = true; } if (skipGet) { this.PushWriter(string.Concat(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, true), "({0})")); } else { this.PushWriter(string.Concat(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, true), "(", trg, ".", Helpers.GetPropertyRef(memberResult.Member, this.Emitter, false), "()", "{0})")); } } else { this.PushWriter(Helpers.GetPropertyRef(memberResult.Member, this.Emitter, true) + "({0})"); } } else if (memberResult != null && memberResult.Member is IEvent) { if (this.Emitter.IsAssignment && (this.Emitter.AssignmentType == AssignmentOperatorType.Add || this.Emitter.AssignmentType == AssignmentOperatorType.Subtract)) { this.WriteTarget(memberResult); if (!string.IsNullOrWhiteSpace(inlineCode)) { this.Write(inlineCode); } else { this.Write(Helpers.GetAddOrRemove(this.Emitter.AssignmentType == AssignmentOperatorType.Add)); this.Write( OverloadsCollection.Create(this.Emitter, memberResult.Member, this.Emitter.AssignmentType == AssignmentOperatorType.Subtract).GetOverloadName()); } this.WriteOpenParentheses(); } else { this.WriteTarget(memberResult); this.Write(this.Emitter.GetEntityName(memberResult.Member)); } } else { if (!string.IsNullOrWhiteSpace(inlineCode)) { this.Write(inlineCode); } else if (isResolved) { if (resolveResult is LocalResolveResult) { var localResolveResult = (LocalResolveResult)resolveResult; this.Write(localResolveResult.Variable.Name); } else if (memberResult != null) { this.WriteTarget(memberResult); string name = OverloadsCollection.Create(this.Emitter, memberResult.Member).GetOverloadName(); if (isRefArg) { this.WriteScript(name); } else if (memberResult.Member is IField) { this.WriteIdentifier(name); } else { this.Write(name); } } else { this.Write(resolveResult.ToString()); } } else { throw new EmitterException(identifierExpression, "Cannot resolve identifier: " + id); } } if (appendAdditionalCode != null) { this.Write(appendAdditionalCode); } Helpers.CheckValueTypeClone(resolveResult, identifierExpression, this, pos); }
/// <summary> /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// </summary> internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Unknown) { return(false); // avoid introducing a potentially-incorrect compound assignment } else if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, (PointerType)type, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } if (binary.Sign != Sign.None) { if (type.IsCSharpSmallIntegerType()) { // C# will use numeric promotion to int, binary op must be signed if (binary.Sign != Sign.Signed) { return(false); } } else { // C# will use sign from type if (type.GetSign() != binary.Sign) { return(false); } } } // Can't transform if the RHS value would be need to be truncated for the LHS type. if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, binary.IsLifted)) { return(false); } return(true); }
Expression ResolveResultExpression(ResolveContext ec) { IType d = expr.Type; bool d_is_nullable = false; // // If E is a method group or the null literal, or if the type of E is a reference // type or a nullable type and the value of E is null, the result is false // if (expr is NullConstant || expr.eclass == ExprClass.MethodGroup) { return(CreateConstantResult(ec, false)); } if (NullableType.IsNullable(d)) { var ut = NullableType.GetUnderlyingType(d); if (!(ut is TypeParameterSpec)) { d = ut; d_is_nullable = true; } } IType t = probe_type_expr; bool t_is_nullable = false; if (NullableType.IsNullable(t)) { var ut = NullableType.GetUnderlyingType(t); if (!(ut is TypeParameterSpec)) { t = ut; t_is_nullable = true; } } //if (t.Kind == TypeKind.Struct) //{ // if (d == t) // { // // // // D and T are the same value types but D can be null // // // if (d_is_nullable && !t_is_nullable) // { // expr_unwrap = Nullable.Unwrap.Create(expr, true); // return this; // } // // // // The result is true if D and T are the same value types // // // return CreateConstantResult(ec, true); // } // var tp = d as TypeParameterSpec; // if (tp != null) // return ResolveGenericParameter(ec, t, tp); // // // // An unboxing conversion exists // // // if (Convert.ExplicitReferenceConversionExists(d, t)) // return this; // // // // open generic type // // // if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter(d)) // return this; //} //else //{ // var tps = t as TypeParameterSpec; // if (tps != null) // return ResolveGenericParameter(ec, d, tps); // if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) // { // ec.Report.Warning(1981, 3, loc, // "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'", // OperatorName, t.GetSignatureForError()); // } // if (TypeManager.IsGenericParameter(d)) // return ResolveGenericParameter(ec, t, (TypeParameterSpec)d); // if (TypeSpec.IsValueType(d)) // { // if (Convert.ImplicitBoxingConversion(null, d, t) != null) // { // if (d_is_nullable && !t_is_nullable) // { // expr_unwrap = Nullable.Unwrap.Create(expr, false); // return this; // } // return CreateConstantResult(ec, true); // } // } // else // { // if (Convert.ImplicitReferenceConversionExists(d, t)) // { // var c = expr as Constant; // if (c != null) // return CreateConstantResult(ec, !c.IsNull); // // // // Do not optimize for imported type or dynamic type // // // if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None && // d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) // { // return this; // } // if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic) // return this; // // // // Turn is check into simple null check for implicitly convertible reference types // // // return ReducedExpression.Create( // new Binary(Binary.Operator.Inequality, expr, new NullLiteral(loc), Binary.State.UserOperatorsExcluded).Resolve(ec), // this).Resolve(ec); // } // if (Convert.ExplicitReferenceConversionExists(d, t)) // return this; // // // // open generic type // // // if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter(d)) // return this; // } //} //TODO:Full Support IS EXPRESSION return(CreateConstantResult(ec, false)); }
/// <summary> /// stloc v(value) /// if (logic.not(call get_HasValue(ldloca v))) throw(...) /// ... Call(arg1, arg2, call GetValueOrDefault(ldloca v), arg4) ... /// => /// ... Call(arg1, arg2, if.notnull(value, throw(...)), arg4) ... /// </summary> bool TransformThrowExpressionValueTypes(Block block, int pos, StatementTransformContext context) { if (pos + 2 >= block.Instructions.Count) { return(false); } if (!(block.Instructions[pos] is StLoc stloc)) { return(false); } ILVariable v = stloc.Variable; if (!(v.StoreCount == 1 && v.LoadCount == 0 && v.AddressCount == 2)) { return(false); } if (!block.Instructions[pos + 1].MatchIfInstruction(out var condition, out var trueInst)) { return(false); } if (!(Block.Unwrap(trueInst) is Throw throwInst)) { return(false); } if (!condition.MatchLogicNot(out var arg)) { return(false); } if (!(arg is CallInstruction call && NullableLiftingTransform.MatchHasValueCall(call, v))) { return(false); } var throwInstParent = throwInst.Parent; var throwInstChildIndex = throwInst.ChildIndex; var nullCoalescingWithThrow = new NullCoalescingInstruction( NullCoalescingKind.NullableWithValueFallback, stloc.Value, throwInst); var resultType = NullableType.GetUnderlyingType(call.Method.DeclaringType).GetStackType(); nullCoalescingWithThrow.UnderlyingResultType = resultType; var result = ILInlining.FindLoadInNext(block.Instructions[pos + 2], v, nullCoalescingWithThrow, InliningOptions.None); if (result.Type == ILInlining.FindResultType.Found && NullableLiftingTransform.MatchGetValueOrDefault(result.LoadInst.Parent, v)) { context.Step("NullCoalescingTransform (value types + throw expression)", stloc); throwInst.resultType = resultType; result.LoadInst.Parent.ReplaceWith(nullCoalescingWithThrow); block.Instructions.RemoveRange(pos, 2); // remove store(s) and if instruction return(true); } else { // reset the primary position (see remarks on ILInstruction.Parent) stloc.Value = stloc.Value; var children = throwInstParent.Children; children[throwInstChildIndex] = throwInst; return(false); } }
private void HandleDecimal(ResolveResult resolveOperator, bool isLong = false) { var orr = resolveOperator as OperatorResolveResult; var op = this.UnaryOperatorExpression.Operator; var oldType = this.Emitter.UnaryOperatorType; var oldAccessor = this.Emitter.IsUnaryAccessor; var typeCode = isLong ? KnownTypeCode.Int64 : KnownTypeCode.Decimal; this.Emitter.UnaryOperatorType = op; var argResolverResult = this.Emitter.Resolver.ResolveNode(this.UnaryOperatorExpression.Expression, this.Emitter); bool nullable = NullableType.IsNullable(argResolverResult.Type); bool isAccessor = false; var memberArgResolverResult = argResolverResult as MemberResolveResult; if (memberArgResolverResult != null && memberArgResolverResult.Member is IProperty) { var isIgnore = this.Emitter.Validator.IsIgnoreType(memberArgResolverResult.Member.DeclaringTypeDefinition); var inlineAttr = this.Emitter.GetAttribute(memberArgResolverResult.Member.Attributes, Translator.Bridge_ASSEMBLY + ".TemplateAttribute"); var ignoreAccessor = this.Emitter.Validator.IsIgnoreType(((IProperty)memberArgResolverResult.Member).Getter); var isAccessorsIndexer = this.Emitter.Validator.IsAccessorsIndexer(memberArgResolverResult.Member); isAccessor = true; if (inlineAttr == null && (isIgnore || ignoreAccessor) && !isAccessorsIndexer) { isAccessor = false; } } else if (argResolverResult is ArrayAccessResolveResult) { isAccessor = ((ArrayAccessResolveResult)argResolverResult).Indexes.Count > 1; } var isOneOp = op == UnaryOperatorType.Increment || op == UnaryOperatorType.Decrement || op == UnaryOperatorType.PostIncrement || op == UnaryOperatorType.PostDecrement; if (isAccessor && isOneOp) { this.Emitter.IsUnaryAccessor = true; if (nullable) { this.Write("(Bridge.hasValue("); this.Emitter.IsUnaryAccessor = false; this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(") ? "); this.Emitter.IsUnaryAccessor = true; this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" : null)"); } else { this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); } this.Emitter.UnaryOperatorType = oldType; this.Emitter.IsUnaryAccessor = oldAccessor; return; } var method = orr != null ? orr.UserDefinedOperatorMethod : null; if (orr != null && method == null) { var name = Helpers.GetUnaryOperatorMethodName(this.UnaryOperatorExpression.Operator); var type = NullableType.IsNullable(orr.Type) ? NullableType.GetUnderlyingType(orr.Type) : orr.Type; method = type.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); } if (orr.IsLiftedOperator) { if (!isOneOp) { this.Write(Bridge.Translator.Emitter.ROOT + ".Nullable."); } string action = "lift1"; string op_name = null; switch (this.UnaryOperatorExpression.Operator) { case UnaryOperatorType.Minus: op_name = "neg"; break; case UnaryOperatorType.Plus: op_name = "clone"; break; case UnaryOperatorType.BitNot: op_name = "not"; break; case UnaryOperatorType.Increment: case UnaryOperatorType.Decrement: this.Write("(Bridge.hasValue("); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(") ? "); this.WriteOpenParentheses(); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" = Bridge.Nullable.lift1('" + (op == UnaryOperatorType.Decrement ? "dec" : "inc") + "', "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.AddOveflowFlag(typeCode, "dec", true); this.Write(")"); this.WriteCloseParentheses(); this.Write(" : null)"); break; case UnaryOperatorType.PostIncrement: case UnaryOperatorType.PostDecrement: this.Write("(Bridge.hasValue("); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(") ? "); this.WriteOpenParentheses(); var valueVar = this.GetTempVarName(); this.Write(valueVar); this.Write(" = "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.WriteComma(); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" = Bridge.Nullable.lift1('" + (op == UnaryOperatorType.PostDecrement ? "dec" : "inc") + "', "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.AddOveflowFlag(typeCode, "dec", true); this.Write(")"); this.WriteComma(); this.Write(valueVar); this.WriteCloseParentheses(); this.RemoveTempVar(valueVar); this.Write(" : null)"); break; } if (!isOneOp) { this.Write(action); this.WriteOpenParentheses(); this.WriteScript(op_name); this.WriteComma(); new ExpressionListBlock(this.Emitter, new Expression[] { this.UnaryOperatorExpression.Expression }, null).Emit(); this.AddOveflowFlag(typeCode, op_name, true); this.WriteCloseParentheses(); } } else if (method == null) { string op_name = null; var isStatement = this.UnaryOperatorExpression.Parent is ExpressionStatement; if (isStatement) { if (op == UnaryOperatorType.PostIncrement) { op = UnaryOperatorType.Increment; } else if (op == UnaryOperatorType.PostDecrement) { op = UnaryOperatorType.Decrement; } } switch (op) { case UnaryOperatorType.Minus: op_name = "neg"; break; case UnaryOperatorType.Plus: op_name = "clone"; break; case UnaryOperatorType.BitNot: op_name = "not"; break; case UnaryOperatorType.Increment: case UnaryOperatorType.Decrement: if (!isStatement) { this.WriteOpenParentheses(); } this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" = "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write("." + (op == UnaryOperatorType.Decrement ? "dec" : "inc") + "("); this.AddOveflowFlag(typeCode, "dec", false); this.Write(")"); if (!isStatement) { this.WriteCloseParentheses(); } break; case UnaryOperatorType.PostIncrement: case UnaryOperatorType.PostDecrement: this.WriteOpenParentheses(); var valueVar = this.GetTempVarName(); this.Write(valueVar); this.Write(" = "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.WriteComma(); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" = "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write("." + (op == UnaryOperatorType.PostDecrement ? "dec" : "inc") + "("); this.AddOveflowFlag(typeCode, "dec", false); this.Write("), "); this.Write(valueVar); this.WriteCloseParentheses(); this.RemoveTempVar(valueVar); break; } if (!isOneOp) { this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.WriteDot(); this.Write(op_name); this.WriteOpenParentheses(); this.AddOveflowFlag(typeCode, op_name, false); this.WriteCloseParentheses(); } } else { var inline = this.Emitter.GetInline(method); if (!string.IsNullOrWhiteSpace(inline)) { if (isOneOp) { var isStatement = this.UnaryOperatorExpression.Parent is ExpressionStatement; if (isStatement || this.UnaryOperatorExpression.Operator == UnaryOperatorType.Increment || this.UnaryOperatorExpression.Operator == UnaryOperatorType.Decrement) { if (!isStatement) { this.WriteOpenParentheses(); } this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" = "); new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.UnaryOperatorExpression, orr, method), inline).Emit (); if (!isStatement) { this.WriteCloseParentheses(); } } else { this.WriteOpenParentheses(); var valueVar = this.GetTempVarName(); this.Write(valueVar); this.Write(" = "); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.WriteComma(); this.UnaryOperatorExpression.Expression.AcceptVisitor(this.Emitter); this.Write(" = "); new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.UnaryOperatorExpression, orr, method), inline).Emit(); this.WriteComma(); this.Write(valueVar); this.WriteCloseParentheses(); this.RemoveTempVar(valueVar); } } else { new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, this.UnaryOperatorExpression, orr, method), inline).Emit(); } } else if (!this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition)) { this.Write(BridgeTypes.ToJsName(method.DeclaringType, this.Emitter)); this.WriteDot(); this.Write(OverloadsCollection.Create(this.Emitter, method).GetOverloadName()); this.WriteOpenParentheses(); new ExpressionListBlock(this.Emitter, new Expression[] { this.UnaryOperatorExpression.Expression }, null).Emit(); this.WriteCloseParentheses(); } } this.Emitter.UnaryOperatorType = oldType; }
protected void VisitBinaryOperatorExpression() { BinaryOperatorExpression binaryOperatorExpression = BinaryOperatorExpression; if (Emitter.IsAsync && ( binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseAnd || binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseOr || binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalOr || binaryOperatorExpression.Operator == BinaryOperatorType.ConditionalAnd ) && GetAwaiters(binaryOperatorExpression).Length > 0) { if (Emitter.AsyncBlock.WrittenAwaitExpressions.Contains(binaryOperatorExpression)) { var index = Array.IndexOf(Emitter.AsyncBlock.AwaitExpressions, binaryOperatorExpression) + 1; Write(JS.Vars.ASYNC_TASK_RESULT + index); } else { var index = Array.IndexOf(Emitter.AsyncBlock.AwaitExpressions, binaryOperatorExpression) + 1; WriteAsyncBinaryExpression(index); } return; } var resolveOperator = Emitter.Resolver.ResolveNode(binaryOperatorExpression); var expectedType = Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression); bool isDecimalExpected = Helpers.IsDecimalType(expectedType, Emitter.Resolver); bool isDecimal = Helpers.IsDecimalType(resolveOperator.Type, Emitter.Resolver); bool isLongExpected = Helpers.Is64Type(expectedType, Emitter.Resolver); bool isLong = Helpers.Is64Type(resolveOperator.Type, Emitter.Resolver); OperatorResolveResult orr = resolveOperator as OperatorResolveResult; var leftResolverResult = Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left); var rightResolverResult = Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right); var charToString = -1; string variable = null; bool leftIsNull = BinaryOperatorExpression.Left is NullReferenceExpression; bool rightIsNull = 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, Emitter.Resolver); var leftExpected = Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left); var rightExpected = Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right); var strictNullChecks = Emitter.AssemblyInfo.StrictNullChecks; if (orr != null && orr.Type.IsKnownType(KnownTypeCode.String)) { for (int i = 0; i < orr.Operands.Count; i++) { if (orr.Operands[i] is ConversionResolveResult crr && crr.Input.Type.IsKnownType(KnownTypeCode.Char)) { charToString = i; } } } if (resolveOperator is ConstantResolveResult) { 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 = Emitter.Resolver.ResolveNode(binaryOperatorExpression.Parent) as OperatorResolveResult; if (parentResolveOperator != null && parentResolveOperator.UserDefinedOperatorMethod != null || IsOperatorSimple(parentBinary, Emitter)) { parentIsString = false; } } bool isSimpleConcat = isStringConcat && IsOperatorSimple(binaryOperatorExpression, 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, Emitter.Resolver) || Helpers.IsDecimalType(rightResolverResult.Type, Emitter.Resolver))) { isDecimal = true; isDecimalExpected = true; } if (isDecimal && isDecimalExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing) { HandleDecimal(resolveOperator); return; } var isLeftLong = Helpers.Is64Type(leftExpected, Emitter.Resolver); var isRightLong = Helpers.Is64Type(rightExpected, Emitter.Resolver); if (!isLeftLong && !isRightLong) { if (leftExpected.Kind == TypeKind.Enum && Helpers.Is64Type(leftExpected.GetDefinition().EnumUnderlyingType, Emitter.Resolver)) { isLeftLong = true; } if (rightExpected.Kind == TypeKind.Enum && Helpers.Is64Type(rightExpected.GetDefinition().EnumUnderlyingType, 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) { HandleLong(resolveOperator, isUint); return; } } var delegateOperator = false; if (ResolveOperator(binaryOperatorExpression, orr)) { return; } if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality || binaryOperatorExpression.Operator == BinaryOperatorType.InEquality) { if (leftIsNull || rightIsNull) { WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult); if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality) { Write(strictNullChecks ? " === " : " == "); } else { Write(strictNullChecks ? " !== " : " != "); } WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult); return; } } var insideOverflowContext = InsideOverflowContext(Emitter, binaryOperatorExpression); if (binaryOperatorExpression.Operator == BinaryOperatorType.Divide && Emitter.Rules.Integer == IntegerRule.Managed && !(Emitter.IsJavaScriptOverflowMode && !insideOverflowContext) && ( (Helpers.IsIntegerType(leftResolverResult.Type, Emitter.Resolver) && Helpers.IsIntegerType(rightResolverResult.Type, Emitter.Resolver)) || (Helpers.IsIntegerType(Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), Emitter.Resolver) && Helpers.IsIntegerType(Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), Emitter.Resolver)) )) { Write(JS.Types.H5_INT + "." + JS.Funcs.Math.DIV + "("); WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult); Write(", "); WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult); Write(")"); return; } if (binaryOperatorExpression.Operator == BinaryOperatorType.Multiply && Emitter.Rules.Integer == IntegerRule.Managed && !(Emitter.IsJavaScriptOverflowMode && !insideOverflowContext) && ( (Helpers.IsInteger32Type(leftResolverResult.Type, Emitter.Resolver) && Helpers.IsInteger32Type(rightResolverResult.Type, Emitter.Resolver) && Helpers.IsInteger32Type(resolveOperator.Type, Emitter.Resolver)) || (Helpers.IsInteger32Type(Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), Emitter.Resolver) && Helpers.IsInteger32Type(Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), Emitter.Resolver) && Helpers.IsInteger32Type(resolveOperator.Type, Emitter.Resolver)) )) { isUint = NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.UInt32); Write(JS.Types.H5_INT + "." + (isUint ? JS.Funcs.Math.UMUL : JS.Funcs.Math.MUL) + "("); WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult); Write(", "); WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult); if (IsInCheckedContext(Emitter, BinaryOperatorExpression)) { Write(", 1"); } Write(")"); return; } if (binaryOperatorExpression.Operator == BinaryOperatorType.Add || binaryOperatorExpression.Operator == BinaryOperatorType.Subtract) { var add = binaryOperatorExpression.Operator == BinaryOperatorType.Add; if (expectedType.Kind == TypeKind.Delegate || Emitter.Validator.IsDelegateOrLambda(leftResolverResult) && Emitter.Validator.IsDelegateOrLambda(rightResolverResult)) { delegateOperator = true; Write(add ? JS.Funcs.H5_COMBINE : JS.Funcs.H5_REMOVE); WriteOpenParentheses(); } } NullStringCheck = isStringConcat && !parentIsString && isSimpleConcat; if (isStringConcat && !parentIsString && !isSimpleConcat) { Write(JS.Types.System.String.CONCAT); WriteOpenParentheses(); } bool nullable = orr != null && orr.IsLiftedOperator; bool isCoalescing = (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) { Write(root); } else if (!isRefEquals) { if (isCoalescing) { Write("("); variable = GetTempVarName(); Write(variable); Write(" = "); } else if (charToString == 0) { Write(JS.Funcs.STRING_FROMCHARCODE + "("); } if (toBool) { Write("!!("); } WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult, isCoalescing); if (isCoalescing) { Write(", "); Write(variable); Write(strictNullChecks ? " !== null" : " != null"); Write(" ? "); expressionMap.Add(binaryOperatorExpression.Left, variable); //this.Write(variable); binaryOperatorExpression.Left.AcceptVisitor(Emitter); expressionMap.Remove(binaryOperatorExpression.Left); } else if (charToString == 0) { Write(")"); } } if (isRefEquals) { if (binaryOperatorExpression.Operator == BinaryOperatorType.InEquality) { Write("!"); } Write(JS.Funcs.H5_REFERENCEEQUALS); special = true; } if (!delegateOperator && (!isStringConcat || isSimpleConcat)) { if (!special) { WriteSpace(); } switch (binaryOperatorExpression.Operator) { case BinaryOperatorType.Add: Write(rootSpecial ? JS.Funcs.Math.ADD : "+"); break; case BinaryOperatorType.BitwiseAnd: if (isBool) { Write(rootSpecial ? JS.Funcs.Math.AND : "&"); } else { Write(rootSpecial ? JS.Funcs.Math.BAND : "&"); } break; case BinaryOperatorType.BitwiseOr: if (isBool) { Write(rootSpecial ? JS.Funcs.Math.OR : "|"); } else { Write(rootSpecial ? JS.Funcs.Math.BOR : "|"); } break; case BinaryOperatorType.ConditionalAnd: Write(rootSpecial ? JS.Funcs.Math.AND : "&&"); break; case BinaryOperatorType.NullCoalescing: Write(isCoalescing ? ":" : "||"); break; case BinaryOperatorType.ConditionalOr: Write(rootSpecial ? JS.Funcs.Math.OR : "||"); break; case BinaryOperatorType.Divide: Write(rootSpecial ? JS.Funcs.Math.DIV : "/"); break; case BinaryOperatorType.Equality: if (!isRefEquals) { Write(rootSpecial ? "eq" : "==="); } break; case BinaryOperatorType.ExclusiveOr: Write(rootSpecial ? JS.Funcs.Math.XOR : (isBool ? "!=" : "^")); break; case BinaryOperatorType.GreaterThan: Write(rootSpecial ? JS.Funcs.Math.GT : ">"); break; case BinaryOperatorType.GreaterThanOrEqual: Write(rootSpecial ? JS.Funcs.Math.GTE : ">="); break; case BinaryOperatorType.InEquality: if (!isRefEquals) { Write(rootSpecial ? "neq" : "!=="); } break; case BinaryOperatorType.LessThan: Write(rootSpecial ? JS.Funcs.Math.LT : "<"); break; case BinaryOperatorType.LessThanOrEqual: Write(rootSpecial ? JS.Funcs.Math.LTE : "<="); break; case BinaryOperatorType.Modulus: Write(rootSpecial ? JS.Funcs.Math.MOD : "%"); break; case BinaryOperatorType.Multiply: Write(rootSpecial ? JS.Funcs.Math.MUL : "*"); break; case BinaryOperatorType.ShiftLeft: Write(rootSpecial ? JS.Funcs.Math.SL : "<<"); break; case BinaryOperatorType.ShiftRight: if (isUint) { Write(rootSpecial ? JS.Funcs.Math.SRR : ">>>"); } else { Write(rootSpecial ? JS.Funcs.Math.SR : ">>"); } break; case BinaryOperatorType.Subtract: Write(rootSpecial ? JS.Funcs.Math.SUB : "-"); break; default: throw new EmitterException(binaryOperatorExpression, "Unsupported binary operator: " + binaryOperatorExpression.Operator.ToString()); } } else { WriteComma(); } if (special) { WriteOpenParentheses(); if (charToString == 0) { Write(JS.Funcs.STRING_FROMCHARCODE + "("); } WritePart(binaryOperatorExpression.Left, toStringForLeft, leftResolverResult); if (charToString == 0) { Write(")"); } WriteComma(); } else if (!delegateOperator && (!isStringConcat || isSimpleConcat)) { WriteSpace(); } if (charToString == 1) { Write(JS.Funcs.STRING_FROMCHARCODE + "("); } WritePart(binaryOperatorExpression.Right, toStringForRight, rightResolverResult); if (toBool) { WriteCloseParentheses(); } if (charToString == 1 || isCoalescing) { WriteCloseParentheses(); } if (delegateOperator || special || isStringConcat && !parentIsString && !isSimpleConcat) { WriteCloseParentheses(); } }
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); var rrType = rr.Type; if (rrType.Kind == TypeKind.Enum) { rrType = rrType.GetDefinition().EnumUnderlyingType; } bool isUint = rrType.IsKnownType(KnownTypeCode.UInt16) || rrType.IsKnownType(KnownTypeCode.UInt32) || rrType.IsKnownType(KnownTypeCode.UInt64); if (!isLong && rr.Type.Kind == TypeKind.Enum && Helpers.Is64Type(rr.Type.GetDefinition().EnumUnderlyingType, this.Emitter.Resolver)) { isLong = true; } if (!isLongExpected && expectedType.Kind == TypeKind.Enum && Helpers.Is64Type(expectedType.GetDefinition().EnumUnderlyingType, this.Emitter.Resolver)) { isLongExpected = true; } 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.Rules.Integer == IntegerRule.Managed && !(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; this.AcceptLeftExpression(assignmentExpression.Left, memberTargetrr); 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.Multiply && this.Emitter.Rules.Integer == IntegerRule.Managed && !(this.Emitter.IsJavaScriptOverflowMode && !ConversionBlock.InsideOverflowContext(this.Emitter, assignmentExpression)) && !isLong && !isLongExpected && ( (Helpers.IsInteger32Type(leftResolverResult.Type, this.Emitter.Resolver) && Helpers.IsInteger32Type(rightResolverResult.Type, this.Emitter.Resolver) && Helpers.IsInteger32Type(rr.Type, this.Emitter.Resolver)) || (Helpers.IsInteger32Type(this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Left), this.Emitter.Resolver) && Helpers.IsInteger32Type(this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression.Right), this.Emitter.Resolver) && Helpers.IsInteger32Type(rr.Type, this.Emitter.Resolver)) )) { this.Emitter.IsAssignment = true; this.Emitter.AssignmentType = AssignmentOperatorType.Assign; var oldValue1 = this.Emitter.ReplaceAwaiterByVar; this.Emitter.ReplaceAwaiterByVar = true; this.AcceptLeftExpression(assignmentExpression.Left, memberTargetrr); if (this.Emitter.Writers.Count == initCount) { this.Write(" = "); } this.Emitter.ReplaceAwaiterByVar = oldValue1; this.Emitter.AssignmentType = oldAssigmentType; this.Emitter.IsAssignment = oldAssigment; isUint = NullableType.GetUnderlyingType(rr.Type).IsKnownType(KnownTypeCode.UInt32); this.Write(JS.Types.BRIDGE_INT + "." + (isUint ? JS.Funcs.Math.UMUL : JS.Funcs.Math.MUL) + "("); assignmentExpression.Left.AcceptVisitor(this.Emitter); this.Write(", "); oldValue1 = this.Emitter.ReplaceAwaiterByVar; this.Emitter.ReplaceAwaiterByVar = true; assignmentExpression.Right.AcceptVisitor(this.Emitter); if (ConversionBlock.IsInCheckedContext(this.Emitter, assignmentExpression)) { this.Write(", 1"); } 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; } bool templateDelegateAssigment = false; 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; this.Emitter.IsAssignment = true; this.Emitter.AssignmentType = assignmentExpression.Operator; templateDelegateAssigment = !string.IsNullOrWhiteSpace(this.Emitter.GetInline(leftMemberResolveResult.Member)); this.Emitter.IsAssignment = false; } if (!isEvent) { this.Emitter.IsAssignment = true; this.Emitter.AssignmentType = AssignmentOperatorType.Assign; this.AcceptLeftExpression(assignmentExpression.Left, memberTargetrr); 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; } this.AcceptLeftExpression(assignmentExpression.Left, memberTargetrr); 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) { int pos = this.Emitter.Output.Length; this.Write(variable); Helpers.CheckValueTypeClone(rr, assignmentExpression.Right, this, pos); } 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 && !templateDelegateAssigment) { 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 virtual string GetCastCode(Expression expression, AstType astType, out bool isInline) { var resolveResult = this.Emitter.Resolver.ResolveNode(astType, this.Emitter) as TypeResolveResult; var exprResolveResult = this.Emitter.Resolver.ResolveNode(expression, this.Emitter); string inline = null; isInline = false; var method = this.GetCastMethod(exprResolveResult.Type, resolveResult.Type, out inline); if (method == null && (NullableType.IsNullable(exprResolveResult.Type) || NullableType.IsNullable(resolveResult.Type))) { method = this.GetCastMethod(NullableType.IsNullable(exprResolveResult.Type) ? NullableType.GetUnderlyingType(exprResolveResult.Type) : exprResolveResult.Type, NullableType.IsNullable(resolveResult.Type) ? NullableType.GetUnderlyingType(resolveResult.Type) : resolveResult.Type, out inline); } if (inline != null) { this.InlineMethod = method; isInline = true; return(inline); } if (resolveResult != null) { IEnumerable <IAttribute> attributes = null; DefaultResolvedTypeDefinition type = resolveResult.Type as DefaultResolvedTypeDefinition; if (type != null) { attributes = type.Attributes; } else { ParameterizedType paramType = resolveResult.Type as ParameterizedType; if (paramType != null) { attributes = paramType.GetDefinition().Attributes; } } if (attributes != null) { var attribute = this.Emitter.GetAttribute(attributes, Translator.Bridge_ASSEMBLY + ".CastAttribute"); if (attribute != null) { return(attribute.PositionalArguments[0].ConstantValue.ToString()); } } } return(null); }
/// <summary> /// Make lower bound inference from U to V. /// C# 4.0 spec: §7.5.2.9 Lower-bound inferences /// </summary> void MakeLowerBoundInference(IType U, IType V) { Log.WriteLine(" MakeLowerBoundInference from " + U + " to " + V); if (U.Nullability == V.Nullability) { U = U.WithoutNullability(); V = V.WithoutNullability(); } // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.IsFixed == false) { Log.WriteLine(" Add lower bound '" + U + "' to " + tp); tp.LowerBounds.Add(U); return; } // Handle nullable covariance: if (NullableType.IsNullable(U) && NullableType.IsNullable(V)) { MakeLowerBoundInference(NullableType.GetUnderlyingType(U), NullableType.GetUnderlyingType(V)); return; } // Handle by reference types: ByReferenceType brU = U as ByReferenceType; ByReferenceType brV = V as ByReferenceType; if (brU != null && brV != null) { MakeExactInference(brU.ElementType, brV.ElementType); return; } // Handle array types: ArrayType arrU = U as ArrayType; ArrayType arrV = V as ArrayType; ParameterizedType pV = V.TupleUnderlyingTypeOrSelf() as ParameterizedType; if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) { MakeLowerBoundInference(arrU.ElementType, arrV.ElementType); return; } else if (arrU != null && IsGenericInterfaceImplementedByArray(pV) && arrU.Dimensions == 1) { MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0)); return; } // Handle parameterized types: if (pV != null) { ParameterizedType uniqueBaseType = null; foreach (IType baseU in U.GetAllBaseTypes()) { ParameterizedType pU = baseU.TupleUnderlyingTypeOrSelf() as ParameterizedType; if (pU != null && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) { if (uniqueBaseType == null) { uniqueBaseType = pU; } else { return; // cannot make an inference because it's not unique } } } Log.Indent(); if (uniqueBaseType != null) { for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { IType Ui = uniqueBaseType.GetTypeArgument(i); IType Vi = pV.GetTypeArgument(i); if (Ui.IsReferenceType == true) { // look for variance ITypeParameter Xi = pV.TypeParameters[i]; switch (Xi.Variance) { case VarianceModifier.Covariant: MakeLowerBoundInference(Ui, Vi); break; case VarianceModifier.Contravariant: MakeUpperBoundInference(Ui, Vi); break; default: // invariant MakeExactInference(Ui, Vi); break; } } else { // not known to be a reference type MakeExactInference(Ui, Vi); } } } Log.Unindent(); } }
bool MatchDisposeCheck(ILVariable objVar, ILInstruction checkInst, bool isReference, bool usingNull, out int numObjVarLoadsInCheck) { numObjVarLoadsInCheck = 2; CallVirt callVirt; if (objVar.Type.IsKnownType(KnownTypeCode.NullableOfT)) { if (checkInst.MatchIfInstruction(out var condition, out var disposeInst)) { if (!NullableLiftingTransform.MatchHasValueCall(condition, objVar)) { return(false); } if (!(disposeInst is Block disposeBlock) || disposeBlock.Instructions.Count != 1) { return(false); } callVirt = disposeBlock.Instructions[0] as CallVirt; } else if (checkInst.MatchNullableRewrap(out disposeInst)) { callVirt = disposeInst as CallVirt; } else { return(false); } if (callVirt == null) { return(false); } if (callVirt.Method.FullName != "System.IDisposable.Dispose") { return(false); } if (callVirt.Method.Parameters.Count > 0) { return(false); } if (callVirt.Arguments.Count != 1) { return(false); } var firstArg = callVirt.Arguments.FirstOrDefault(); if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) { if (!firstArg.MatchAddressOf(out var innerArg2, out _)) { return(false); } return(NullableLiftingTransform.MatchGetValueOrDefault(innerArg2, objVar) || (innerArg2 is NullableUnwrap unwrap && unwrap.Argument.MatchLdLoc(objVar))); } else { if (!(innerArg1.MatchBox(out firstArg, out var boxType) && boxType.IsKnownType(KnownTypeCode.NullableOfT) && NullableType.GetUnderlyingType(boxType).Equals(NullableType.GetUnderlyingType(objVar.Type)))) { return(false); } return(firstArg.MatchLdLoc(objVar)); } }
public static string ToTypeScriptName(IType type, IEmitter emitter, bool asDefinition = false, bool excludens = false, bool ignoreDependency = false, List <string> guard = null) { if (type.Kind == TypeKind.Delegate) { if (guard == null) { guard = new List <string>(); } if (guard.Contains(type.FullName)) { return("Function"); } guard.Add(type.FullName); var method = type.GetDelegateInvokeMethod(); StringBuilder sb = new StringBuilder(); sb.Append("{"); sb.Append("("); var last = method.Parameters.LastOrDefault(); foreach (var p in method.Parameters) { var ptype = BridgeTypes.ToTypeScriptName(p.Type, emitter, guard: guard); if (p.IsOut || p.IsRef) { ptype = "{v: " + ptype + "}"; } sb.Append(p.Name + ": " + ptype); if (p != last) { sb.Append(", "); } } sb.Append(")"); sb.Append(": "); sb.Append(BridgeTypes.ToTypeScriptName(method.ReturnType, emitter, guard: guard)); sb.Append("}"); guard.Remove(type.FullName); return(sb.ToString()); } var oname = ObjectLiteralSignature(type, emitter); if (oname != null) { return(oname); } if (type.IsKnownType(KnownTypeCode.String)) { return("string"); } if (type.IsKnownType(KnownTypeCode.Boolean)) { return("boolean"); } if (type.IsKnownType(KnownTypeCode.Void)) { return("void"); } if (type.IsKnownType(KnownTypeCode.Array)) { return("any[]"); } if (type.IsKnownType(KnownTypeCode.Byte) || type.IsKnownType(KnownTypeCode.Char) || type.IsKnownType(KnownTypeCode.Double) || type.IsKnownType(KnownTypeCode.Int16) || type.IsKnownType(KnownTypeCode.Int32) || type.IsKnownType(KnownTypeCode.SByte) || type.IsKnownType(KnownTypeCode.Single) || type.IsKnownType(KnownTypeCode.UInt16) || type.IsKnownType(KnownTypeCode.UInt32)) { return("number"); } if (type.Kind == TypeKind.Array) { ICSharpCode.NRefactory.TypeSystem.ArrayType arrayType = (ICSharpCode.NRefactory.TypeSystem.ArrayType)type; return(BridgeTypes.ToTypeScriptName(arrayType.ElementType, emitter, asDefinition, excludens, guard: guard) + "[]"); } if (type.Kind == TypeKind.Dynamic || type.IsKnownType(KnownTypeCode.Object)) { return("any"); } if (type.Kind == TypeKind.Enum && type.DeclaringType != null && !excludens) { return("number"); } if (NullableType.IsNullable(type)) { return(BridgeTypes.ToTypeScriptName(NullableType.GetUnderlyingType(type), emitter, asDefinition, excludens, guard: guard)); } BridgeType bridgeType = emitter.BridgeTypes.Get(type, true); //string name = BridgeTypes.ConvertName(excludens ? type.Name : type.FullName); var name = excludens ? "" : type.Namespace; var hasTypeDef = bridgeType != null && bridgeType.TypeDefinition != null; bool isNested = false; if (hasTypeDef) { var typeDef = bridgeType.TypeDefinition; if (typeDef.IsNested && !excludens) { //name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(emitter, typeDef); name = BridgeTypes.ToJsName(typeDef.DeclaringType, emitter, true, ignoreVirtual: true); isNested = true; } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(emitter.GetTypeName(bridgeType.Type.GetDefinition(), typeDef)); } else { if (type.DeclaringType != null && !excludens) { //name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.GetParentNames(emitter, type); name = BridgeTypes.ToJsName(type.DeclaringType, emitter, true, ignoreVirtual: true); if (type.DeclaringType.TypeArguments.Count > 0) { name += Helpers.PrefixDollar(type.TypeArguments.Count); } isNested = true; } name = (string.IsNullOrEmpty(name) ? "" : (name + ".")) + BridgeTypes.ConvertName(type.Name); } bool isCustomName = false; if (bridgeType != null) { if (!ignoreDependency && emitter.AssemblyInfo.OutputBy != OutputBy.Project && bridgeType.TypeInfo != null && bridgeType.TypeInfo.Namespace != emitter.TypeInfo.Namespace) { var info = BridgeTypes.GetNamespaceFilename(bridgeType.TypeInfo, emitter); var ns = info.Item1; var fileName = info.Item2; if (!emitter.CurrentDependencies.Any(d => d.DependencyName == fileName)) { emitter.CurrentDependencies.Add(new ModuleDependency() { DependencyName = fileName }); } } name = BridgeTypes.GetCustomName(name, bridgeType, excludens, isNested, ref isCustomName, null); } if (!hasTypeDef && !isCustomName && type.TypeArguments.Count > 0) { name += Helpers.PrefixDollar(type.TypeArguments.Count); } if (isCustomName && excludens && name != null) { var idx = name.LastIndexOf('.'); if (idx > -1) { name = name.Substring(idx + 1); } } if (!asDefinition && type.TypeArguments.Count > 0 && !Helpers.IsIgnoreGeneric(type, emitter, true)) { StringBuilder sb = new StringBuilder(name); bool needComma = false; sb.Append("<"); foreach (var typeArg in type.TypeArguments) { if (needComma) { sb.Append(","); } needComma = true; sb.Append(BridgeTypes.ToTypeScriptName(typeArg, emitter, asDefinition, excludens, guard: guard)); } sb.Append(">"); name = sb.ToString(); } return(name); }
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); var expectedType = this.Emitter.Resolver.Resolver.GetExpectedType(assignmentExpression); bool isDecimalExpected = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver); bool isUserOperator = this.IsUserOperator(orr); 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; } } } if (needReturnValue) { 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(", "); } if (assignmentExpression.Operator == AssignmentOperatorType.Divide && ( (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; if (needReturnValue) { this.Write(variable); } else { assignmentExpression.Right.AcceptVisitor(this.Emitter); } this.Write(")"); this.Emitter.ReplaceAwaiterByVar = oldValue1; this.Emitter.AsyncExpressionHandling = asyncExpressionHandling; if (this.Emitter.Writers.Count > initCount) { this.PopWriter(); } 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) || 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 == 0 && !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 (needReturnValue) { this.Write(", " + variable + ")"); } 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(">>"); 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("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(", "); } int count = this.Emitter.Writers.Count; if (count == 0 && !thisAssignment && !special) { this.Write("= "); } } else if (!isEvent) { this.WriteComma(); } if (!special && isBool && (assignmentExpression.Operator == AssignmentOperatorType.BitwiseAnd || assignmentExpression.Operator == AssignmentOperatorType.BitwiseOr)) { 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 (needReturnValue) { this.Write(variable); } else { assignmentExpression.Right.AcceptVisitor(this.Emitter); } if (charToString == 1) { this.Write(")"); } 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 (needReturnValue) { this.Write(", " + variable + ")"); } }