示例#1
0
        /// <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);
        }
示例#2
0
        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();
                }
            }
        }
示例#3
0
        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);
        }
示例#4
0
        protected void VisitBinaryOperatorExpression()
        {
            BinaryOperatorExpression binaryOperatorExpression = this.BinaryOperatorExpression;
            var  resolveOperator       = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression, this.Emitter);
            var  expectedType          = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression);
            bool isDecimalExpected     = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal             = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            bool isLongExpected        = Helpers.Is64Type(expectedType, this.Emitter.Resolver);
            bool isLong                = Helpers.Is64Type(resolveOperator.Type, this.Emitter.Resolver);
            OperatorResolveResult orr  = resolveOperator as OperatorResolveResult;
            var    leftResolverResult  = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left, this.Emitter);
            var    rightResolverResult = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right, this.Emitter);
            var    charToString        = -1;
            string variable            = null;
            bool   leftIsNull          = this.BinaryOperatorExpression.Left is NullReferenceExpression;
            bool   rightIsNull         = this.BinaryOperatorExpression.Right is NullReferenceExpression;
            bool   isUint              = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt16) ||
                                         resolveOperator.Type.IsKnownType(KnownTypeCode.UInt32) ||
                                         resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64);

            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();
            }
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#7
0
        protected void VisitBinaryOperatorExpression()
        {
            BinaryOperatorExpression binaryOperatorExpression = this.BinaryOperatorExpression;
            var  resolveOperator       = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression, this.Emitter);
            var  expectedType          = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression);
            bool isDecimalExpected     = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal             = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            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();
                }
            }
        }
示例#8
0
        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();
                }
            }
        }
示例#9
0
        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);
        }
示例#10
0
 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));
 }
示例#11
0
 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));
 }
示例#12
0
        private static void NarrowingNumericOrEnumerationConversion(ConversionBlock block, Expression expression, IType targetType, bool fromFloatingPoint, bool isChecked, bool isNullable, bool isExplicit = true)
        {
            if (block.Emitter.IsJavaScriptOverflowMode && !InsideOverflowContext(block.Emitter, expression))
            {
                return;
            }

            var binaryOperatorExpression = expression as BinaryOperatorExpression;

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

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

            var assignmentExpression = expression as AssignmentExpression;

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

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

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

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

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

                //expression.AcceptVisitor(block.Emitter);

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

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

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

                    bool skipInnerWrap = false;

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

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

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

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

                    if (!skipOuterWrap)
                    {
                        block.AfterOutput += ")";
                    }
                }
            }
        }
示例#13
0
        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 += ")";
            }
        }
示例#14
0
        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));
                }
            }
示例#15
0
        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();
        }
示例#16
0
        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);
        }
示例#17
0
        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);
        }
示例#18
0
        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(")");
            }
        }
示例#19
0
        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);
        }
示例#21
0
        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));
        }
示例#22
0
        /// <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);
            }
        }
示例#23
0
        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;
        }
示例#24
0
        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();
            }
        }
示例#25
0
        protected void VisitAssignmentExpression()
        {
            AssignmentExpression assignmentExpression = this.AssignmentExpression;
            var    oldAssigment     = this.Emitter.IsAssignment;
            var    oldAssigmentType = this.Emitter.AssignmentType;
            string variable         = null;

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

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

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

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

            var asyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

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

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

            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(")");
            }
        }
示例#26
0
        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);
        }
示例#27
0
        /// <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();
            }
        }
示例#28
0
        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));
                }
            }
示例#29
0
        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);
        }
示例#30
0
        protected void VisitAssignmentExpression()
        {
            AssignmentExpression assignmentExpression = this.AssignmentExpression;
            var    oldAssigment     = this.Emitter.IsAssignment;
            var    oldAssigmentType = this.Emitter.AssignmentType;
            string variable         = null;

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

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

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

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

            var asyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

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

            var  leftResolverResult  = this.Emitter.Resolver.ResolveNode(assignmentExpression.Left, this.Emitter);
            var  rightResolverResult = this.Emitter.Resolver.ResolveNode(assignmentExpression.Right, this.Emitter);
            var  rr                = this.Emitter.Resolver.ResolveNode(assignmentExpression, this.Emitter);
            var  orr               = rr as OperatorResolveResult;
            bool isDecimal         = Helpers.IsDecimalType(rr.Type, this.Emitter.Resolver);
            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 + ")");
            }
        }