Beispiel #1
0
        private static void WriteEnumerator(HaxeWriter writer, ExpressionSyntax expression, ITypeSymbol type, bool isFirstParameterToExtensionMethod)
        {
            var typeStr = TypeProcessor.GenericTypeName(type);

            if (typeStr == "System.String")
            {
                writer.Write("Cs2Hx.ToCharArray(");
                Core.Write(writer, expression);
                writer.Write(")");
            }
            else
            {
                var haxeType = TypeProcessor.ConvertType(type);

                if (haxeType == "haxe.io.Bytes")
                {
                    throw new Exception("Cannot use byte[] as an enumerable.  Consider using a for loop instead " + Utility.Descriptor(expression));
                }

                //Array types support enumerating natively.  For other types, we append GetEnumerator so they can be enumerated on.  We check type.Name != "Array" as a special case for the System.Array type for which ConvertType returns null, yet haxe supports enumerating natively.
                if ((haxeType == null || !haxeType.StartsWith("Array")) && type.Name != "Array")
                {
                    if (isFirstParameterToExtensionMethod)
                    {
                        //When we're being called as the first parameter to an extension method, we also have to take care not to call .GetEnumerator() on something that's null. Since we could be calling an extension method on this, and in C# calling extension methods on something that's null will not generate a nullref exception.
                        writer.Write("Cs2Hx.GetEnumeratorNullCheck(");
                        Core.Write(writer, expression);
                        writer.Write(")");
                    }
                    else
                    {
                        Core.Write(writer, expression);
                        writer.Write(".GetEnumerator()");
                    }
                }
                else
                {
                    Core.Write(writer, expression);
                }
            }
        }
Beispiel #2
0
        public static void Go(HaxeWriter writer, CastExpressionSyntax expression)
        {
            var model = Program.GetModel(expression);

            var symbol = model.GetSymbolInfo(expression);

            var castingFrom = model.GetTypeInfo(expression.Expression).Type;

            if (castingFrom == null)
            {
                castingFrom = model.GetTypeInfo(expression).Type;
            }

            var castingFromStr  = TypeProcessor.GenericTypeName(castingFrom);
            var castingFromHaxe = TypeProcessor.ConvertType((ITypeSymbol)castingFrom);
            var destType        = model.GetTypeInfo(expression.Type).Type;
            var destTypeHaxe    = TypeProcessor.TryConvertType(expression.Type);



            var subExpression = expression.Expression;

            //Since we output parenthesis, we can eat one set of them
            if (subExpression is ParenthesizedExpressionSyntax)
            {
                subExpression = subExpression.As <ParenthesizedExpressionSyntax>().Expression;
            }

            if (symbol.Symbol != null && castingFromHaxe != "Int" && castingFromHaxe != "String" && castingFromHaxe != "Bool")
            {
                //when the symbol is non-null, this indicates we're calling a cast operator function
                WriteCastOperator(writer, expression, (IMethodSymbol)symbol.Symbol, destTypeHaxe);
            }
            else if (destTypeHaxe.StartsWith("Nullable"))
            {
                //Casting to a nullable type results in creation of that nullable type. No cast necessary.
                writer.Write("new ");
                writer.Write(destTypeHaxe);
                writer.Write("(");

                if (subExpression.Kind() != SyntaxKind.NullLiteralExpression)
                {
                    Core.Write(writer, subExpression);
                }

                writer.Write(")");
            }
            else if (subExpression.Kind() == SyntaxKind.NullLiteralExpression)
            {
                //no cast necessary for null. haxe can infer the type better than C#
                writer.Write("null");
            }
            else if (destTypeHaxe == null)
            {
                //Sometimes roslyn can't determine the type for some reason. Just fall back to haxe's dynamic cast
                writer.Write("cast(");
                Core.Write(writer, subExpression);
                writer.Write(")");
            }
            else if (castingFromHaxe == "Dynamic")
            {
                //casts to and from dynamic will be automatic, however we have to manually specify the type.  Otherwise, we saw cases on the js target where haxe would not translate properties from "X" to "get_X()".
                //The only way I've found to specify the type of an expression is to in-line an anonymous function.  Haxe optimizes this away so there's no runtime hit.
                writer.Write("(function():" + destTypeHaxe + " return ");
                Core.Write(writer, expression.Expression);
                writer.Write(")()");
            }
            else if (destTypeHaxe == "Int" && castingFromHaxe == "Int" && expression.DescendantNodes().OfType <BinaryExpressionSyntax>().Where(o => o.OperatorToken.Kind() == SyntaxKind.SlashToken).None())
            {
                //Eat casts from Int to Int.  Enums getting casted to int fall here, and since we use ints to represent enums anyway, it's not necessary.  However, if we contain the division operator, and since haxe division always produces floating points and C# integer division produces integers, we can't rely on the C# expression type so cast anyway.
                Core.Write(writer, expression.Expression);
            }
            else if (destTypeHaxe.Contains("<"))
            {
                //Eat casts with type parameters.  haxe doesn't allow this.
                Core.Write(writer, expression.Expression);
            }
            else if (destTypeHaxe == "Int")
            {
                //Casting from int to float is handled by Std.int in haxe
                writer.Write("Std.int(");
                Core.Write(writer, subExpression);
                writer.Write(")");
            }
            else if (destTypeHaxe == "Float" && castingFromHaxe == "Int")
            {
                //Eat casts from Int to Float.  C# does this so it can do floating division, but in haxe all division is floating so there's no reason to do it.
                Core.Write(writer, expression.Expression);
            }
            else if (destTypeHaxe == castingFromHaxe)
            {
                //Eat casts between identical types
                Core.Write(writer, expression.Expression);
            }
            else if (destType.TypeKind == TypeKind.TypeParameter)
            {
                //ignore casts to template types
                Core.Write(writer, expression.Expression);
            }
            else
            {
                writer.Write("cast(");
                Core.Write(writer, subExpression);
                writer.Write(", ");
                writer.Write(destTypeHaxe);
                writer.Write(")");
            }
        }
Beispiel #3
0
        public static void Go(HaxeWriter writer, MemberAccessExpressionSyntax expression)
        {
            var model = Program.GetModel(expression);

            var memberName = expression.Name.Identifier.ValueText;
            var type       = model.GetTypeInfo(expression.Expression).ConvertedType;
            var typeStr    = TypeProcessor.GenericTypeName(type);

            if (expression.Expression is PredefinedTypeSyntax)
            {
                //Support int.MaxValue/int.MaxValue/etc. We change MinValue/MaxValue for some types since haXe can't deal with the real MinValue (it's even stricter when compiling to java).  Any checks against this should use <= in place of ==
                if (memberName == "Empty" && typeStr == "System.String")
                {
                    writer.Write("\"\"");
                }
                else if (memberName == "MaxValue" && typeStr == "System.Double")
                {
                    writer.Write("3.4028235e+38");
                }
                else if (memberName == "MinValue" && typeStr == "System.Double")
                {
                    writer.Write("1.4e-45");
                }
                else if (memberName == "MaxValue" && typeStr == "System.Int64")
                {
                    writer.Write("999900000000000000");
                }
                else if (memberName == "NaN")
                {
                    writer.Write("Math.NaN");
                }
                else
                {
                    var val = System.Type.GetType(typeStr).GetField(memberName).GetValue(null);
                    if (val is string)
                    {
                        writer.Write("\"" + val + "\"");
                    }
                    else
                    {
                        writer.Write(val.ToString());
                    }
                }
            }
            else
            {
                var translate = PropertyTranslation.Get(typeStr, memberName);

                if (translate != null && translate.ExtensionNamespace != null)
                {
                    writer.Write(translate.ExtensionNamespace);
                    writer.Write(".");
                    writer.Write(translate.ReplaceWith);
                    writer.Write("(");

                    if (!translate.SkipExtensionParameter)
                    {
                        WriteMember(writer, expression.Expression);
                    }

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

                if (translate != null)
                {
                    memberName = translate.ReplaceWith;
                }

                if (type != null)                 //if type is null, then we're just a namespace.  We can ignore these.
                {
                    WriteMember(writer, expression.Expression);
                    writer.Write(".");
                }

                writer.Write(memberName);

                if (expression.Name is GenericNameSyntax)
                {
                    var gen = expression.Name.As <GenericNameSyntax>();

                    writer.Write("<");

                    bool first = true;
                    foreach (var g in gen.TypeArgumentList.Arguments)
                    {
                        if (first)
                        {
                            first = false;
                        }
                        else
                        {
                            writer.Write(", ");
                        }

                        writer.Write(TypeProcessor.ConvertTypeWithColon(g));
                    }

                    writer.Write(">");
                }
            }
        }