Пример #1
0
        public static void Go(HaxeWriter writer, SyntaxTokenList modifiers, string name, TypeSyntax type, EqualsValueClauseSyntax initializerOpt = null)
        {
            writer.WriteIndent();

            var isConst = IsConst(modifiers, initializerOpt, type);

            WriteFieldModifiers(writer, modifiers);
            if (isConst)
            {
                writer.Write("inline ");
            }

            writer.Write("var ");

            writer.Write(name);
            writer.Write(TypeProcessor.ConvertTypeWithColon(type));

            if (isConst)
            {
                writer.Write(" = ");
                Core.Write(writer, initializerOpt.Value);
            }

            writer.Write(";");
            writer.WriteLine();
        }
Пример #2
0
        public static bool IsConst(SyntaxTokenList modifiers, EqualsValueClauseSyntax initializerOpt, TypeSyntax type)
        {
            var t = TypeProcessor.ConvertType(type);

            return((modifiers.Any(SyntaxKind.ConstKeyword) ||
                    (modifiers.Any(SyntaxKind.ReadOnlyKeyword) && modifiers.Any(SyntaxKind.StaticKeyword) && initializerOpt != null)) &&
                   (t == "Int" || t == "String" || t == "Bool" || t == "Float"));
        }
Пример #3
0
 private static void WriteCastOperator(HaxeWriter writer, CastExpressionSyntax expression, IMethodSymbol symbol, string destTypeHaxe)
 {
     writer.Write(TypeProcessor.ConvertType(symbol.ContainingType));
     writer.Write(".op_Explicit_");
     writer.Write(destTypeHaxe.TrySubstringBeforeFirst('<').Replace('.', '_'));
     writer.Write("(");
     Core.Write(writer, expression.Expression);
     writer.Write(")");
 }
        public static void Go(HaxeWriter writer, ElementAccessExpressionSyntax expression)
        {
            Core.Write(writer, expression.Expression);

            var typeHaxe = TypeProcessor.ConvertType(Program.GetModel(expression).GetTypeInfo(expression.Expression).ConvertedType);

            if (typeHaxe.StartsWith("Array<"))             //arrays are the only thing haxe allows using the [] syntax with
            {
                if (expression.ArgumentList.Arguments.Count != 1)
                {
                    throw new Exception("Expect array index to have a single argument " + Utility.Descriptor(expression));
                }

                writer.Write("[");
                Core.Write(writer, expression.ArgumentList.Arguments.Single().Expression);
                writer.Write("]");
            }
            else if (typeHaxe == "haxe.io.Bytes")
            {
                writer.Write(".get(");
                Core.Write(writer, expression.ArgumentList.Arguments.Single().Expression);
                writer.Write(")");
            }
            else if (typeHaxe == "String")
            {
                //indexing into string to get its character results in a call to charCodeAt
                writer.Write(".charCodeAt(");
                Core.Write(writer, expression.ArgumentList.Arguments.Single().Expression);
                writer.Write(")");
            }
            else
            {
                writer.Write(".GetValue");

                var symbol = Program.GetModel(expression).GetSymbolInfo(expression).Symbol.OriginalDefinition.As <IPropertySymbol>();

                writer.Write(string.Join("", symbol.Parameters.ToArray().Select(o => "_" + o.Type.Name)));


                writer.Write("(");
                bool first = true;
                foreach (var arg in expression.ArgumentList.Arguments)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    Core.Write(writer, arg.Expression);
                }
                writer.Write(")");
            }
        }
Пример #5
0
 private static bool GenerateInitializerForFieldWithoutInitializer(TypeSyntax parentType)
 {
     //Determine if we need to write an initializer for this field which does not have an initializer.
     if (TypeProcessor.ValueToReference(parentType))
     {
         return(true);
     }
     else
     {
         return(TypeProcessor.DefaultValue(TypeProcessor.ConvertType(parentType)) != "null");
     }
 }
Пример #6
0
        public static void WriteIndexerDeclaration(HaxeWriter writer, IndexerDeclarationSyntax decl)
        {
            foreach (var accessor in decl.AccessorList.Accessors)
            {
                writer.WriteIndent();

                if (decl.Modifiers.Any(SyntaxKind.OverrideKeyword) || decl.Modifiers.Any(SyntaxKind.NewKeyword))
                {
                    writer.Write("override ");
                }
                if (decl.Modifiers.Any(SyntaxKind.PublicKeyword) || decl.Modifiers.Any(SyntaxKind.ProtectedKeyword) || decl.Modifiers.Any(SyntaxKind.InternalKeyword))
                {
                    writer.Write("public ");
                }
                if (decl.Modifiers.Any(SyntaxKind.PrivateKeyword))
                {
                    writer.Write("private ");
                }

                var isGet = accessor.Kind() == SyntaxKind.GetAccessorDeclaration;


                writer.Write("function ");
                writer.Write(isGet ? "Get" : "Set");
                writer.Write("Value_");
                writer.Write(Program.GetModel(decl).GetTypeInfo(decl.ParameterList.Parameters.Single().Type).Type.Name);
                writer.Write("(");

                foreach (var prm in decl.ParameterList.Parameters)
                {
                    writer.Write(prm.Identifier.ValueText);
                    writer.Write(TypeProcessor.ConvertTypeWithColon(prm.Type));
                }

                if (isGet)
                {
                    writer.Write(")");
                    writer.Write(TypeProcessor.ConvertTypeWithColon(decl.Type));
                }
                else
                {
                    writer.Write(", value");
                    writer.Write(TypeProcessor.ConvertTypeWithColon(decl.Type));
                    writer.Write("):Void");
                }
                writer.WriteLine();

                if (accessor.Body != null)
                {
                    Core.Write(writer, accessor.Body);
                }
            }
        }
Пример #7
0
        public static void Go(HaxeWriter writer, LocalDeclarationStatementSyntax declaration)
        {
            foreach (var variable in declaration.Declaration.Variables)
            {
                var symbol = Program.GetModel(declaration).GetDeclaredSymbol(variable);

                var isRef = UsedAsRef(variable, symbol);

                writer.WriteIndent();
                writer.Write("var ");
                writer.Write(variable.Identifier.ValueText);

                if (isRef)
                {
                    var typeStr = TypeProcessor.ConvertType(declaration.Declaration.Type);

                    writer.Write(":CsRef<");
                    writer.Write(typeStr);
                    writer.Write(">");

                    Program.RefOutSymbols.TryAdd(symbol, null);

                    writer.Write(" = new CsRef<");
                    writer.Write(typeStr);
                    writer.Write(">(");

                    if (variable.Initializer == null)
                    {
                        writer.Write(TypeProcessor.DefaultValue(typeStr));
                    }
                    else
                    {
                        Core.Write(writer, variable.Initializer.As <EqualsValueClauseSyntax>().Value);
                    }

                    writer.Write(")");
                }
                else
                {
                    writer.Write(TypeProcessor.ConvertTypeWithColon(declaration.Declaration.Type));

                    if (variable.Initializer != null)
                    {
                        writer.Write(" = ");
                        Core.Write(writer, variable.Initializer.As <EqualsValueClauseSyntax>().Value);
                    }
                }

                writer.Write(";\r\n");
            }
        }
Пример #8
0
        public static string TypeName(INamedTypeSymbol symbol)
        {
            var fields = symbol.GetMembers().OfType <IPropertySymbol>();

            var typeParams = fields.Where(o => o.Type.TypeKind == TypeKind.TypeParameter);

            var genericSuffix = typeParams.None() ? "" : ("<" + string.Join(", ", typeParams.Select(o => o.Type.Name).Distinct()) + ">");

            return("Anon_" + string.Join("__",
                                         fields
                                         .OrderBy(o => o.Name)
                                         .Select(o => o.Name + "_" + TypeProcessor.ConvertType(o.Type).Replace('.', '_')))
                   + genericSuffix);
        }
Пример #9
0
        private static void Go(HaxeWriter writer, IEnumerable <ParameterSyntax> parameters, SyntaxNode body, TypeInfo type)
        {
            var methodSymbol = type.ConvertedType.As <INamedTypeSymbol>().DelegateInvokeMethod.As <IMethodSymbol>();

            writer.Write("function (");

            for (int pi = 0; pi < parameters.Count(); pi++)
            {
                var parameter = parameters.ElementAt(pi);
                if (pi > 0)
                {
                    writer.Write(", ");
                }

                writer.Write(parameter.Identifier.ValueText);
                if (parameter.Type != null)
                {
                    writer.Write(TypeProcessor.ConvertTypeWithColon(parameter.Type));
                }
                else
                {
                    writer.Write(TypeProcessor.ConvertTypeWithColon(methodSymbol.Parameters[pi].Type));
                }
            }

            writer.Write(")");
            writer.Write(TypeProcessor.ConvertTypeWithColon(methodSymbol.ReturnType));

            if (body is BlockSyntax)
            {
                writer.Write("\r\n");
                Core.Write(writer, body);
                writer.WriteIndent();
            }
            else
            {
                writer.Write(" { ");

                if (methodSymbol.ReturnsVoid == false)
                {
                    writer.Write("return ");
                }

                Core.Write(writer, body);

                writer.Write("; } ");
            }
        }
Пример #10
0
        public static void Go(HaxeWriter writer, ObjectCreationExpressionSyntax expression)
        {
            if (expression.ArgumentList == null)
            {
                throw new Exception("Types must be initialized with parenthesis. Object initialization syntax is not supported. " + Utility.Descriptor(expression));
            }

            var model = Program.GetModel(expression);
            var type  = model.GetTypeInfo(expression).Type;

            if (type.SpecialType == SpecialType.System_Object)
            {
                //new object() results in the CsObject type being made.  This is only really useful for locking
                writer.Write("new CsObject()");
            }
            else
            {
                var methodSymbol = model.GetSymbolInfo(expression).Symbol.As <IMethodSymbol>();

                var translateOpt = MethodTranslation.Get(methodSymbol);


                writer.Write("new ");
                writer.Write(TypeProcessor.ConvertType(expression.Type));
                writer.Write("(");

                bool first = true;
                foreach (var param in TranslateParameters(translateOpt, WriteInvocationExpression.SortArguments(methodSymbol, expression.ArgumentList.Arguments, expression), expression))
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    param.Write(writer);
                }

                writer.Write(")");
            }
        }
Пример #11
0
        public static void Go(HaxeWriter writer, PostfixUnaryExpressionSyntax expression)
        {
            //Check for ++ and -- after a element access, such as a dictionary<int,int> being called as dict[4]++
            if (expression.Operand is ElementAccessExpressionSyntax)
            {
                var elementAccess = (ElementAccessExpressionSyntax)expression.Operand;

                var typeHaxe = TypeProcessor.ConvertType(Program.GetModel(expression).GetTypeInfo(elementAccess.Expression).ConvertedType);

                if (!typeHaxe.StartsWith("Array<"))                 //arrays are the only thing haxe allows assignments into via indexing
                {
                    WriteBinaryExpression.WriteIndexingExpression(writer, expression.OperatorToken, null, elementAccess);
                    return;
                }
            }

            Core.Write(writer, expression.Operand);
            writer.Write(expression.OperatorToken.ToString());             //haxe operators are the same as C#
        }
        public static void Go(HaxeWriter writer, ConversionOperatorDeclarationSyntax method)
        {
            if (method.ImplicitOrExplicitKeyword.Kind() != SyntaxKind.ExplicitKeyword)
            {
                throw new Exception("Implicit cast operators are not supported " + Utility.Descriptor(method));
            }

            writer.WriteIndent();
            writer.Write("public static function op_Explicit_");
            writer.Write(TypeProcessor.ConvertType(method.Type));
            writer.Write("(");

            bool firstParam = true;

            foreach (var param in method.ParameterList.Parameters)
            {
                if (firstParam)
                {
                    firstParam = false;
                }
                else
                {
                    writer.Write(", ");
                }

                writer.Write(param.Identifier.ValueText);
                writer.Write(TypeProcessor.ConvertTypeWithColon(param.Type));
            }

            writer.Write(")");
            writer.Write(TypeProcessor.ConvertTypeWithColon(method.Type));
            writer.Write("\r\n");

            writer.WriteOpenBrace();

            foreach (var statement in method.Body.Statements)
            {
                Core.Write(writer, statement);
            }

            writer.WriteCloseBrace();
        }
Пример #13
0
        public static void Go(HaxeWriter writer, SyntaxTokenList modifiers, string name, TypeSyntax type, EqualsValueClauseSyntax initializerOpt = null)
        {
            writer.WriteIndent();

            var isConst = IsConst(modifiers, initializerOpt, type);

            WriteFieldModifiers(writer, modifiers);
            if (isConst)
            {
                writer.Write("inline ");
            }

            writer.Write("var ");

            writer.Write(name);
            writer.Write(TypeProcessor.ConvertTypeWithColon(type));

            if (initializerOpt != null)
            {
                writer.Write(" = ");
                Core.Write(writer, initializerOpt.Value);
            }
            else if (GenerateInitializerForFieldWithoutInitializer(type))
            {
                writer.Write(" = ");
                if (TypeProcessor.ValueToReference(type))
                {
                    writer.Write("new ");
                    writer.Write(TypeProcessor.ConvertType(type));
                    writer.Write("()");
                }
                else
                {
                    writer.Write(TypeProcessor.DefaultValue(TypeProcessor.ConvertType(type)));
                }
            }


            writer.Write(";");
            writer.WriteLine();
        }
Пример #14
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);
                }
            }
        }
Пример #15
0
        public static void Write(HaxeWriter writer, SyntaxNode node)
        {
            TriviaProcessor.ProcessNode(writer, node);

            if (Program.DoNotWrite.ContainsKey(node))
            {
                return;
            }

            if (!(node is ExpressionSyntax) || node is ParenthesizedExpressionSyntax)
            {
                Factory(writer, node);
            }
            else
            {
                var typeInfo = Program.GetModel(node).GetTypeInfo((ExpressionSyntax)node);

                if (typeInfo.ConvertedType != null && typeInfo.ConvertedType.Name == "Nullable" &&

                    (typeInfo.Type == null || (TypeProcessor.ConvertType(typeInfo.Type) != TypeProcessor.ConvertType(typeInfo.ConvertedType))))
                {
                    //When assigning into a nullable, we must construct the nullable type.
                    writer.Write("new ");
                    writer.Write(TypeProcessor.ConvertType(typeInfo.ConvertedType));
                    writer.Write("(");

                    if (typeInfo.Type != null)
                    {
                        Factory(writer, node);
                    }

                    writer.Write(")");
                }
                else
                {
                    Factory(writer, node);
                }
            }
        }
Пример #16
0
        public static void WriteIndexingExpression(HaxeWriter writer, SyntaxToken operatorToken, ExpressionSyntax subExpressionOpt, ElementAccessExpressionSyntax elementAccess)
        {
            Core.Write(writer, elementAccess.Expression);
            writer.Write(".");

            Action writeArgs = () =>
            {
                foreach (var arg in elementAccess.ArgumentList.Arguments)
                {
                    Core.Write(writer, arg.Expression);
                    writer.Write(", ");
                }
            };

            if (operatorToken.Kind() == SyntaxKind.EqualsToken)
            {
                var leftTypeHaxe = TypeProcessor.ConvertType(elementAccess.Expression);

                if (leftTypeHaxe == "haxe.io.Bytes")
                {
                    writer.Write("set(");
                }
                else
                {
                    var symbol = Program.GetModel(elementAccess).GetSymbolInfo(elementAccess).Symbol.OriginalDefinition.As <IPropertySymbol>();
                    var types  = string.Join("", symbol.Parameters.ToArray().Select(o => "_" + o.Type.Name));
                    writer.Write("SetValue" + types + "(");
                }

                writeArgs();
                Core.Write(writer, subExpressionOpt);
                writer.Write(")");
            }
            else
            {
                throw new Exception("Unexpected token following an element access expression " + Utility.Descriptor(elementAccess.Parent));
            }
        }
Пример #17
0
        public static void WriteIndexingExpression(HaxeWriter writer, SyntaxToken operatorToken, ExpressionSyntax subExpressionOpt, ElementAccessExpressionSyntax elementAccess)
        {
            Core.Write(writer, elementAccess.Expression);
            writer.Write(".");

            Action writeArgs = () =>
            {
                foreach (var arg in elementAccess.ArgumentList.Arguments)
                {
                    Core.Write(writer, arg.Expression);
                    writer.Write(", ");
                }
            };

            if (operatorToken.Kind() == SyntaxKind.EqualsToken)
            {
                var leftTypeHaxe = TypeProcessor.ConvertType(elementAccess.Expression);

                if (leftTypeHaxe == "haxe.io.Bytes")
                {
                    writer.Write("set(");
                }
                else
                {
                    writer.Write("SetValue(");
                }

                writeArgs();
                Core.Write(writer, subExpressionOpt);
                writer.Write(")");
            }
            else
            {
                throw new Exception("Unexpected token following an element access expression " + Utility.Descriptor(elementAccess.Parent));
            }
        }
Пример #18
0
        public static void Go()
        {
            var partials = TypeState.Instance.Partials;
            var first    = partials.First();


            using (var writer = new HaxeWriter(first.Symbol.ContainingNamespace.FullName(), TypeState.Instance.TypeName))
            {
                var bases = partials
                            .Select(o => o.Syntax.BaseList)
                            .Where(o => o != null)
                            .SelectMany(o => o.Types)
                            .Select(o => Program.GetModel(o).GetTypeInfo(o.Type).ConvertedType)
                            .Distinct()
                            .ToList();

                var interfaces = bases.Where(o => o.TypeKind == TypeKind.Interface).ToList();

                TypeState.Instance.DerivesFromObject = bases.Count == interfaces.Count;

                writer.WriteLine("package " + first.Symbol.ContainingNamespace.FullName().ToLower() + @";");

                WriteImports.Go(writer);

                switch (first.Syntax.Kind())
                {
                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.StructDeclaration:
                case SyntaxKind.EnumDeclaration:
                    writer.Write("class ");
                    break;

                case SyntaxKind.InterfaceDeclaration:
                    writer.Write("interface ");
                    break;

                default:
                    throw new Exception(first.Syntax.Kind().ToString());
                }

                writer.Write(TypeState.Instance.TypeName);



                if (first.Syntax is TypeDeclarationSyntax)
                {
                    //Look for generic arguments
                    var genericArgs = partials
                                      .Select(o => o.Syntax)
                                      .Cast <TypeDeclarationSyntax>()
                                      .Where(o => o.TypeParameterList != null)
                                      .SelectMany(o => o.TypeParameterList.Parameters)
                                      .ToList();

                    if (genericArgs.Count > 0)
                    {
                        writer.Write("<");
                        writer.Write(string.Join(", ", genericArgs.Select(o => WriteMethod.TypeParameter(o, partials.SelectMany(z => z.Syntax.As <TypeDeclarationSyntax>().ConstraintClauses)))));
                        writer.Write(">");
                    }

                    foreach (var baseType in bases)
                    {
                        var baseTypeHaxe = TypeProcessor.ConvertType(baseType);

                        if (baseTypeHaxe.StartsWith("Array<"))
                        {
                            continue;
                        }

                        writer.Write(" ");

                        if (baseType.TypeKind == TypeKind.Interface)
                        {
                            writer.Write("implements ");
                            writer.Write(baseTypeHaxe);
                        }
                        else
                        {
                            writer.Write("extends ");
                            writer.Write(baseTypeHaxe);
                        }
                    }
                }

                writer.Write("\r\n");

                writer.WriteOpenBrace();

                if (first.Syntax is EnumDeclarationSyntax)
                {
                    WriteEnumBody.Go(writer, TypeState.Instance.Partials.Select(o => o.Syntax).Cast <EnumDeclarationSyntax>().SelectMany(o => o.Members).Where(o => !Program.DoNotWrite.ContainsKey(o)));
                }
                else
                {
                    TypeState.Instance.AllMembers = partials.Select(o => o.Syntax).Cast <TypeDeclarationSyntax>().SelectMany(o => o.Members).Where(o => !Program.DoNotWrite.ContainsKey(o)).ToList();

                    foreach (var partial in partials)
                    {
                        foreach (var member in partial.Syntax.As <TypeDeclarationSyntax>().Members)
                        {
                            if (!(member is ClassDeclarationSyntax) && !(member is EnumDeclarationSyntax))
                            {
                                Core.Write(writer, member);
                            }
                        }
                    }

                    if (first.Syntax.Kind() != SyntaxKind.InterfaceDeclaration)
                    {
                        //Normally constructors will be written as we traverse the tree.  However, if there are no constructors, we must manually write them out since there are cases where we need a constructor in haxe while C# had none.
                        var ctors         = TypeState.Instance.AllMembers.OfType <ConstructorDeclarationSyntax>().ToList();
                        var instanceCtors = ctors.Where(o => !o.Modifiers.Any(SyntaxKind.StaticKeyword));

                        if (instanceCtors.Count() > 1)
                        {
                            throw new Exception("Overloaded constructors are not supported.  Consider changing all but one to static Create methods " + Utility.Descriptor(first.Syntax));
                        }

                        if (ctors.None(o => o.Modifiers.Any(SyntaxKind.StaticKeyword)))
                        {
                            WriteConstructor.WriteStaticConstructor(writer, null);
                        }
                        if (instanceCtors.None())
                        {
                            WriteConstructor.WriteInstanceConstructor(writer, null);
                        }
                    }
                }

                writer.WriteCloseBrace();
            }
        }
Пример #19
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(")");
            }
        }
Пример #20
0
        public static void WriteAnonymousType(AnonymousObjectCreationExpressionSyntax syntax)
        {
            var type     = Program.GetModel(syntax).GetTypeInfo(syntax).Type.As <INamedTypeSymbol>();
            var anonName = TypeName(type);

            using (var writer = new HaxeWriter("anonymoustypes", StripGeneric(anonName)))
            {
                writer.WriteLine("package anonymoustypes;");
                WriteImports.Go(writer);

                writer.WriteLine("class " + anonName);
                writer.WriteOpenBrace();

                var fields = type.GetMembers().OfType <IPropertySymbol>().OrderBy(o => o.Name).ToList();

                foreach (var field in fields)
                {
                    writer.WriteIndent();
                    writer.Write("public var ");
                    writer.Write(field.Name);
                    writer.Write(TypeProcessor.ConvertTypeWithColon(field.Type));
                    writer.Write(";\r\n");
                }

                writer.WriteIndent();
                writer.Write("public function new(");

                bool first = true;
                foreach (var field in fields)
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    writer.Write(field.Name);
                    writer.Write(TypeProcessor.ConvertTypeWithColon(field.Type));
                }
                writer.Write(")\r\n");

                writer.WriteOpenBrace();

                foreach (var field in fields)
                {
                    writer.WriteIndent();
                    writer.Write("this.");
                    writer.Write(field.Name);
                    writer.Write(" = ");
                    writer.Write(field.Name);
                    writer.Write(";\r\n");
                }

                writer.WriteCloseBrace();

                writer.WriteCloseBrace();
            }
        }
Пример #21
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(">");
                }
            }
        }
Пример #22
0
        private static void GoInternal(HaxeWriter writer, BaseMethodDeclarationSyntax method, TypeSyntax returnType, TypeParameterListSyntax typeParameterListOpt, SyntaxList <TypeParameterConstraintClauseSyntax>?constraintClassesOpt)
        {
            var methodSymbol = Program.GetModel(method).GetDeclaredSymbol(method);

            if (method.Modifiers.Any(SyntaxKind.PartialKeyword) && method.Body == null)
            {
                //We only want to render out one of the two partial methods.  If there's another, skip this one.
                if (TypeState.Instance.Partials.SelectMany(o => o.Syntax.As <ClassDeclarationSyntax>().Members)
                    .OfType <MethodDeclarationSyntax>()
                    .Except(method as MethodDeclarationSyntax)
                    .Where(o => o.Identifier.ValueText == methodSymbol.Name)
                    .Any())
                {
                    return;
                }
            }

            if (methodSymbol.Name == "System.Collections.IEnumerable.GetEnumerator")
            {
                return; //we don't support the non-generic enumerator
            }
            if (methodSymbol.Name == "GetEnumerator")
            {
                WriteGetEnumeratorFunction(writer, method, methodSymbol);
                return;
            }

            writer.WriteIndent();

            if (ShouldUseOverrideKeyword(method, methodSymbol))
            {
                writer.Write("override ");
            }
            if (method.Modifiers.Any(SyntaxKind.PublicKeyword) || method.Modifiers.Any(SyntaxKind.ProtectedKeyword) || method.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                writer.Write("public ");
            }
            if (method.Modifiers.Any(SyntaxKind.PrivateKeyword))
            {
                writer.Write("private ");
            }
            if (method.Modifiers.Any(SyntaxKind.StaticKeyword))
            {
                writer.Write("static ");
            }

            writer.Write("function ");
            var methodName = OverloadResolver.MethodName(methodSymbol);

            if (methodName == "ToString")
            {
                methodName = "toString";
            }

            writer.Write(methodName);

            if (typeParameterListOpt != null)
            {
                writer.Write("<");
                writer.Write(string.Join(", ", typeParameterListOpt.Parameters.Select(o => TypeParameter(o, constraintClassesOpt))));
                writer.Write(">");
            }

            writer.Write("(");

            Dictionary <string, ExpressionSyntax> deferredDefaults;

            WriteParameters(writer, method, methodSymbol, out deferredDefaults);

            writer.Write(")");
            writer.Write(TypeProcessor.ConvertTypeWithColon(returnType));

            if (method.Modifiers.Any(SyntaxKind.AbstractKeyword))
            {
                writer.WriteLine();
                writer.WriteOpenBrace();
                writer.WriteIndent();

                if (returnType.ToString() != "void")
                {
                    writer.Write("return ");                     //"return" the throw statement to work around haxe limitations
                }
                writer.Write("throw new Exception(\"Abstract item called\");\r\n");
                writer.WriteCloseBrace();
            }
            else if (method.Parent is InterfaceDeclarationSyntax)
            {
                writer.Write(";\r\n");
            }
            else
            {
                writer.WriteLine();
                writer.WriteOpenBrace();

                foreach (var defer in deferredDefaults)
                {
                    writer.WriteLine("if (" + defer.Key + " == null)");
                    writer.Indent++;
                    writer.WriteIndent();
                    writer.Write(defer.Key);
                    writer.Write(" = ");
                    Core.Write(writer, defer.Value);
                    writer.Write(";\r\n");
                    writer.Indent--;
                }

                if (method.Body != null)
                {
                    foreach (var statement in method.Body.Statements)
                    {
                        Core.Write(writer, statement);
                    }

                    TriviaProcessor.ProcessTrivias(writer, method.Body.DescendantTrivia());
                }

                writer.WriteCloseBrace();
            }
        }
Пример #23
0
        private static void WriteGetEnumeratorFunction(HaxeWriter writer, BaseMethodDeclarationSyntax method, IMethodSymbol methodSymbol)
        {
            var returnType = TypeProcessor.ConvertType(methodSymbol.ReturnType);

            if (!returnType.StartsWith("system.collections.generic.IEnumerator<"))
            {
                return; //we only support the generic IEnumerator form of GetEnumerator.  Anything else, just don't write out the method.
            }
            var enumerableType = returnType.RemoveFromStartOfString("system.collections.generic.IEnumerator<").RemoveFromEndOfString(">");

            //We only support very simple GetEnumerator functions that pass on their call to some other collection.  The body should be like "return <expr>.GetEnumerator();", otherwise don't write out the function at all.
            if (method.Body == null)
            {
                return;
            }
            if (method.Body.Statements.Count > 1)
            {
                return;
            }
            var returnStatement = method.Body.Statements.Single() as ReturnStatementSyntax;

            if (returnStatement == null)
            {
                return;
            }
            var invocation = returnStatement.Expression as InvocationExpressionSyntax;

            if (invocation == null)
            {
                return;
            }
            var member = invocation.Expression as MemberAccessExpressionSyntax;

            if (member == null)
            {
                return;
            }

            var memberExpressionType     = Program.GetModel(member).GetTypeInfo(member.Expression).Type;
            var memberExpressionHaxeType = TypeProcessor.ConvertType(memberExpressionType);

            writer.WriteIndent();
            writer.Write("public function iterator():Iterator<");
            writer.Write(enumerableType);
            writer.Write(">\r\n");
            writer.WriteOpenBrace();

            writer.WriteIndent();
            writer.Write("return ");
            Core.Write(writer, member.Expression);
            writer.Write(".iterator();\r\n");
            writer.WriteCloseBrace();

            //Also write out a GetEnumerator(), which returns the same thing but as an array
            writer.WriteIndent();
            writer.Write("public function GetEnumerator():Array<");
            writer.Write(enumerableType);
            writer.Write(">\r\n");
            writer.WriteOpenBrace();

            writer.WriteIndent();
            writer.Write("return ");
            Core.Write(writer, member.Expression);

            if (!memberExpressionHaxeType.StartsWith("Array<"))
            {
                writer.Write(".GetEnumerator()");
            }
            writer.Write(";\r\n");
            writer.WriteCloseBrace();
        }
Пример #24
0
        public static void WriteParameters(HaxeWriter writer, BaseMethodDeclarationSyntax method, IMethodSymbol methodSymbol, out Dictionary <string, ExpressionSyntax> deferredDefaults)
        {
            deferredDefaults = new Dictionary <string, ExpressionSyntax>();

            var prms = method.ParameterList.Parameters.Select(o => new TransformedArgument(o)).ToList();

            var translateOpt = MethodTranslation.Get(methodSymbol);

            if (translateOpt != null)
            {
                prms = translateOpt.As <MethodTranslation>().TranslateParameters(prms, null).ToList();
            }

            var firstParam = true;

            foreach (var parameter in prms)
            {
                bool isRef = parameter.ParameterOpt != null && (parameter.ParameterOpt.Modifiers.Any(SyntaxKind.OutKeyword) || parameter.ParameterOpt.Modifiers.Any(SyntaxKind.RefKeyword));

                if (parameter.StringOpt != null)
                {
                    continue; //these are only used on invocations
                }
                if (firstParam)
                {
                    firstParam = false;
                }
                else
                {
                    writer.Write(", ");
                }

                writer.Write(parameter.ParameterOpt.Identifier.ValueText);


                if (isRef)
                {
                    writer.Write(":CsRef<");
                    writer.Write(TypeProcessor.ConvertType(parameter.ParameterOpt.Type));
                    writer.Write(">");

                    Program.RefOutSymbols.TryAdd(Program.GetModel(method).GetDeclaredSymbol(parameter.ParameterOpt), null);
                }
                else
                {
                    writer.Write(TypeProcessor.ConvertTypeWithColon(parameter.ParameterOpt.Type));
                }

                if (parameter.ParameterOpt.Default != null)
                {
                    writer.Write(" = ");

                    if (TypeProcessor.ConvertType(parameter.ParameterOpt.Type).StartsWith("Nullable"))
                    {
                        writer.Write("null");
                        deferredDefaults.Add(parameter.ParameterOpt.Identifier.ValueText, parameter.ParameterOpt.Default.Value);
                    }
                    else
                    {
                        Core.Write(writer, parameter.ParameterOpt.Default.Value);
                    }
                }
            }


            int tIndex = 1;

            foreach (var genericVar in Utility.PassTypeArgsToMethod(methodSymbol))
            {
                if (firstParam)
                {
                    firstParam = false;
                }
                else
                {
                    writer.Write(", ");
                }

                writer.Write("t" + tIndex.ToString());
                writer.Write(":Class<");
                writer.Write(TypeProcessor.ConvertType(genericVar));
                writer.Write(">");
                tIndex++;
            }
        }
Пример #25
0
        public static void Go(HaxeWriter writer, InvocationExpressionSyntax invocationExpression)
        {
            var model = Program.GetModel(invocationExpression);

            var symbolInfo       = model.GetSymbolInfo(invocationExpression);
            var expressionSymbol = model.GetSymbolInfo(invocationExpression.Expression);

            if (symbolInfo.Symbol == null)
            {
                throw new Exception("InvocationExpression could not be identified.  Are you sure the C# is valid? " + Utility.Descriptor(invocationExpression));
            }
            var methodSymbol     = (IMethodSymbol)symbolInfo.Symbol;
            var origMethodSymbol = methodSymbol.OriginalDefinition.As <IMethodSymbol>().UnReduce();

            var translateOpt = MethodTranslation.Get(symbolInfo.Symbol.As <IMethodSymbol>());
            var memberReferenceExpressionOpt = invocationExpression.Expression as MemberAccessExpressionSyntax;
            //var returnTypeHaxe = TypeProcessor.ConvertType(methodSymbol.ReturnType);
            var firstParameter = true;

            if (methodSymbol.TypeArguments.Any(o => o.SpecialType == SpecialType.System_Char) && origMethodSymbol.ContainingType.Name != "Enumerable")
            {
                throw new Exception("Char cannot be passed as a type argument. methodName=" + origMethodSymbol.Name + " " + Utility.Descriptor(invocationExpression));                                 //the called function could call .ToString on it, which would give the int representation instead of the char.  We could fix this by wrapping chars in a class but that would hit performance, so instead just re-write the offending C#.  Skip this requirement for System.Linq.Enumerable because it is typically just mapping to a lambda, such as Select or TakeWhile, and our lambda can handle it correctly.  Ideally we'd detect if the type parameter is only used in a lambda
            }
            var              extensionNamespace = origMethodSymbol.IsExtensionMethod ? origMethodSymbol.ContainingNamespace.FullNameWithDot().ToLower() + origMethodSymbol.ContainingType.Name : null; //null means it's not an extension method, non-null means it is
            string           methodName;
            ExpressionSyntax subExpressionOpt;

            if (origMethodSymbol.ContainingType.Name == "Enum")
            {
                if (origMethodSymbol.Name == "Parse")
                {
                    WriteEnumParse(writer, invocationExpression);
                    return;
                }

                if (origMethodSymbol.Name == "GetValues")
                {
                    WriteEnumGetValues(writer, invocationExpression);
                    return;
                }
            }

            if (expressionSymbol.Symbol is IEventSymbol)
            {
                methodName = "Invoke";                 //Would need to append the number of arguments to this to support events.  However, events are not currently supported
            }
            else if (memberReferenceExpressionOpt != null && memberReferenceExpressionOpt.Expression is PredefinedTypeSyntax)
            {
                switch (origMethodSymbol.Name)
                {
                case "Parse":
                    var t = TypeProcessor.ConvertType(origMethodSymbol.ReturnType);

                    if (t == "Bool")
                    {
                        methodName         = "ParseBool";
                        extensionNamespace = "Cs2Hx";
                    }
                    else if (t == "Int" || t == "Float")
                    {
                        methodName         = "parse" + t;
                        extensionNamespace = "Std";
                    }
                    else
                    {
                        throw new Exception("Parse method on " + t + " is not supported.  " + Utility.Descriptor(memberReferenceExpressionOpt));
                    }

                    break;

                case "TryParse":
                    methodName         = "TryParse" + TypeProcessor.ConvertType(origMethodSymbol.Parameters[1].Type);
                    extensionNamespace = "Cs2Hx";
                    break;

                default:
                    methodName         = origMethodSymbol.Name;
                    extensionNamespace = "Cs2Hx";
                    break;
                }
            }
            else if (translateOpt != null && translateOpt.ReplaceWith != null)
            {
                methodName = translateOpt.ReplaceWith;
            }
            else if (origMethodSymbol.MethodKind == MethodKind.DelegateInvoke)
            {
                methodName = null;
            }
            else
            {
                methodName = OverloadResolver.MethodName(origMethodSymbol);
            }

            if (translateOpt != null && translateOpt.HasComplexReplaceWith)
            {
                translateOpt.DoComplexReplaceWith(writer, memberReferenceExpressionOpt);                 //TODO: What if this is null?
                return;
            }

            if (translateOpt != null && translateOpt.SkipExtensionParameter)
            {
                subExpressionOpt = null;
            }
            else if (origMethodSymbol.MethodKind == MethodKind.DelegateInvoke)
            {
                subExpressionOpt = invocationExpression.Expression;
            }
            else if (memberReferenceExpressionOpt != null)
            {
                if (memberReferenceExpressionOpt.Expression is PredefinedTypeSyntax)
                {
                    subExpressionOpt = null;
                }
                else
                {
                    subExpressionOpt = memberReferenceExpressionOpt.Expression;
                }
            }
            else
            {
                subExpressionOpt = null;                 //TODO
            }
            //Determine if it's an extension method called in a non-extension way.  In this case, just pretend it's not an extension method
            if (extensionNamespace != null && subExpressionOpt != null && model.GetTypeInfo(subExpressionOpt).ConvertedType.ToString() == origMethodSymbol.ContainingNamespace + "." + origMethodSymbol.ContainingType.Name)
            {
                extensionNamespace = null;
            }

            if (translateOpt != null && !string.IsNullOrEmpty(translateOpt.ExtensionNamespace))
            {
                extensionNamespace = translateOpt.ExtensionNamespace;
            }
            else if (translateOpt != null && translateOpt.ExtensionNamespace == "")
            {
                extensionNamespace = null;
            }

            if (extensionNamespace != null)
            {
                writer.Write(extensionNamespace);

                if (methodName != null)
                {
                    writer.Write(".");
                    writer.Write(methodName);
                }

                writer.Write("(");

                if (subExpressionOpt != null)
                {
                    firstParameter = false;

                    if (origMethodSymbol.IsExtensionMethod)
                    {
                        WriteForEachStatement.CheckWriteEnumerator(writer, subExpressionOpt, true);
                    }
                    else
                    {
                        Core.Write(writer, subExpressionOpt);
                    }
                }
            }
            else
            {
                if (memberReferenceExpressionOpt != null)
                {
                    var memberType     = model.GetTypeInfo(memberReferenceExpressionOpt.Expression).Type;
                    var memberTypeHaxe = TypeProcessor.ConvertType(memberType);

                    //sort calls without any parameters need to get the default sort parameter
                    if (methodName == "sort" && invocationExpression.ArgumentList.Arguments.Count == 0)
                    {
                        Core.Write(writer, memberReferenceExpressionOpt.Expression);
                        writer.Write(".sort(");

                        switch (memberTypeHaxe)
                        {
                        case "Array<Int>":
                            writer.Write("Cs2Hx.SortInts");
                            break;

                        case "Array<Float>":
                            writer.Write("Cs2Hx.SortFloats");
                            break;

                        case "Array<String>":
                            writer.Write("Cs2Hx.SortStrings");
                            break;

                        default:
                            throw new Exception("Unknown default sort type: " + memberTypeHaxe + ".  " + Utility.Descriptor(invocationExpression));
                        }

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

                    //Check against lowercase toString since it gets replaced with the haxe name before we get here
                    if (methodName == "toString")
                    {
                        if (memberType.TypeKind == TypeKind.Enum)
                        {
                            //calling ToString() on an enum forwards to our enum's special ToString method
                            writer.Write(memberType.ContainingNamespace.FullNameWithDot().ToLower());
                            writer.Write(WriteType.TypeName((INamedTypeSymbol)memberType));
                            writer.Write(".ToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Enum's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;
                        }

                        if (memberType.SpecialType == SpecialType.System_Char)
                        {
                            writer.Write("Cs2Hx.CharToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Char's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;
                        }

                        if (memberTypeHaxe == "Int" || memberTypeHaxe == "Float" || memberTypeHaxe == "Bool" || memberType.TypeKind == TypeKind.TypeParameter)
                        {
                            //ToString()'s on primitive types get replaced with Std.string
                            writer.Write("Std.string(");

                            if (memberReferenceExpressionOpt.Expression is ParenthesizedExpressionSyntax)
                            {
                                Core.Write(writer, memberReferenceExpressionOpt.Expression.As <ParenthesizedExpressionSyntax>().Expression);                                //eat a set of parenthesis, just to make the output code a bit nicer.
                            }
                            else
                            {
                                Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            }

                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Primitive type's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;                             //Skip parameters
                        }
                    }
                }

                if (subExpressionOpt != null)
                {
                    WriteMemberAccessExpression.WriteMember(writer, subExpressionOpt);
                }

                if (subExpressionOpt != null && methodName != null)
                {
                    writer.Write(".");
                }

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

            var prms = TranslateParameters(translateOpt, SortArguments(origMethodSymbol, invocationExpression.ArgumentList.Arguments, invocationExpression, extensionNamespace != null), invocationExpression).ToList();

            //If we invoke a method with type parameters that aren't used in the argument list, the haxe function won't have a way to see what args were used. To give it a way, add those as parameters at the end
            foreach (var typePrm in Utility.PassTypeArgsToMethod(origMethodSymbol))
            {
                var name = invocationExpression.Expression.ChildNodes().OfType <GenericNameSyntax>().ToList();
                if (name.Count == 0)
                {
                    name = invocationExpression.Expression.DescendantNodesAndSelf().OfType <GenericNameSyntax>().ToList(); //TODO: This will pick up false positives, we need a proper recursion function here
                }
                if (name.Count != 1)
                {
                    throw new Exception("Expected a single generic name, got " + string.Join(", ", name) + "  " + Utility.Descriptor(invocationExpression));
                }
                if (name.Count > 0 && name.Single().TypeArgumentList.Arguments.Count > 0)
                {
                    var typePrmIndex = origMethodSymbol.TypeParameters.IndexOf(origMethodSymbol.TypeParameters.Single(o => SymbolEqualityComparer.Default.Equals(o, typePrm)));
                    var genericVar   = name.Single().TypeArgumentList.Arguments.ElementAt(typePrmIndex);
                    if (genericVar.ToString() == typePrm.ToString())
                    {
                        writer.Write("t" + (typePrmIndex + 1));
                    }
                    else
                    {
                        prms.Add(new TransformedArgument(TypeProcessor.ConvertType(genericVar)));
                    }
                }
            }


            bool inParams = false;

            foreach (var arg in prms)
            {
                if (firstParameter)
                {
                    firstParameter = false;
                }
                else
                {
                    writer.Write(", ");
                }

                if (!inParams && IsParamsArgument(invocationExpression, arg.ArgumentOpt, origMethodSymbol) && TypeProcessor.ConvertType(model.GetTypeInfo(arg.ArgumentOpt.Expression).Type).StartsWith("Array<") == false)
                {
                    inParams = true;
                    writer.Write("[ ");
                }


                if (arg.ArgumentOpt != null &&
                    arg.ArgumentOpt.RefOrOutKeyword.Kind() != SyntaxKind.None &&
                    model.GetSymbolInfo(arg.ArgumentOpt.Expression).Symbol is IFieldSymbol)
                {
                    throw new Exception("ref/out cannot reference fields, only local variables.  Consider using ref/out on a local variable and then assigning it into the field. " + Utility.Descriptor(invocationExpression));
                }


                //When passing an argument by ref or out, leave off the .Value suffix
                if (arg.ArgumentOpt != null && arg.ArgumentOpt.RefOrOutKeyword.Kind() != SyntaxKind.None)
                {
                    WriteIdentifierName.Go(writer, arg.ArgumentOpt.Expression.As <IdentifierNameSyntax>(), true);
                }
                else if (arg.ArgumentOpt != null)
                {
                    WriteForEachStatement.CheckWriteEnumerator(writer, arg.ArgumentOpt.Expression, false);
                }
                else
                {
                    arg.Write(writer);
                }
            }

            if (inParams)
            {
                writer.Write(" ]");
            }


            writer.Write(")");
        }
Пример #26
0
        public static void WriteStaticConstructor(HaxeWriter writer, ConstructorDeclarationSyntax staticConstructorOpt)
        {
            var staticFieldsNeedingInitialization = TypeState.Instance.AllMembers
                                                    .OfType <BaseFieldDeclarationSyntax>()
                                                    .Where(o => o.Modifiers.Any(SyntaxKind.StaticKeyword))
                                                    .SelectMany(o => o.Declaration.Variables)
                                                    .Where(o =>
                                                           (o.Initializer != null && !WriteField.IsConst(o.Parent.Parent.As <BaseFieldDeclarationSyntax>().Modifiers, o.Initializer, o.Parent.As <VariableDeclarationSyntax>().Type))
                                                           ||
                                                           (o.Initializer == null && GenerateInitializerForFieldWithoutInitializer(o.Parent.As <VariableDeclarationSyntax>().Type))
                                                           ||
                                                           o.Parent.Parent is EventFieldDeclarationSyntax)
                                                    .ToList();

            if (staticConstructorOpt == null && staticFieldsNeedingInitialization.Count == 0)
            {
                return; //No static constructor needed
            }
            writer.WriteLine("public static function cctor():Void");
            writer.WriteOpenBrace();

            foreach (var field in staticFieldsNeedingInitialization)
            {
                var parentType = field.Parent.As <VariableDeclarationSyntax>().Type;

                writer.WriteIndent();
                writer.Write(field.Identifier.ValueText);
                writer.Write(" = ");

                if (field.Parent.Parent is EventFieldDeclarationSyntax)
                {
                    writer.Write("new CsEvent<");
                    writer.Write(TypeProcessor.ConvertType(parentType));
                    writer.Write(">()");
                }
                else if (field.Initializer == null)
                {
                    if (TypeProcessor.ValueToReference(parentType))
                    {
                        writer.Write("new ");
                        writer.Write(TypeProcessor.ConvertType(parentType));
                        writer.Write("()");
                    }
                    else
                    {
                        writer.Write(TypeProcessor.DefaultValue(TypeProcessor.ConvertType(parentType)));
                    }
                }
                else
                {
                    Core.Write(writer, field.Initializer.As <EqualsValueClauseSyntax>().Value);
                }
                writer.Write(";\r\n");
            }

            if (staticConstructorOpt != null && staticConstructorOpt.Body != null)
            {
                foreach (var statement in staticConstructorOpt.Body.As <BlockSyntax>().Statements)
                {
                    Core.Write(writer, statement);
                }
            }

            writer.WriteCloseBrace();

            StaticConstructors.Add(TypeState.Instance.TypeName);
        }
Пример #27
0
        public static void Go(HaxeWriter writer, PropertyDeclarationSyntax property)
        {
            var  propertySymbol = Program.GetModel(property).GetDeclaredSymbol(property);
            var  isInterface    = propertySymbol.ContainingType.TypeKind == TypeKind.Interface;
            bool isAutoProperty = false;

            Action <AccessorDeclarationSyntax, bool> writeRegion = (region, get) =>
            {
                writer.WriteIndent();

                if (property.Modifiers.Any(SyntaxKind.OverrideKeyword))
                {
                    writer.Write("override ");
                }
                if (property.Modifiers.Any(SyntaxKind.PublicKeyword) || property.Modifiers.Any(SyntaxKind.ProtectedKeyword) || property.Modifiers.Any(SyntaxKind.InternalKeyword))
                {
                    writer.Write("public ");
                }
                if (property.Modifiers.Any(SyntaxKind.PrivateKeyword))
                {
                    writer.Write("private ");
                }
                if (property.Modifiers.Any(SyntaxKind.StaticKeyword))
                {
                    writer.Write("static ");
                }

                writer.Write("function ");
                writer.Write(get ? "get_" : "set_");
                writer.Write(property.Identifier.ValueText);

                string type = TypeProcessor.ConvertType(property.Type);

                if (get)
                {
                    writer.Write("():" + type);
                }
                else
                {
                    writer.Write("(value:" + type + "):" + type);
                }

                var isAbstract = property.Modifiers.Any(SyntaxKind.AbstractKeyword);

                writer.WriteLine();
                writer.WriteOpenBrace();

                if (isAbstract)
                {
                    writer.WriteLine("return throw new Exception(\"Abstract item called\");");
                }
                else
                {
                    if (region.Body == null)
                    {
                        //When we leave the body off in C#, it resolves to an automatic property.
                        isAutoProperty = true;
                        if (get)
                        {
                            writer.WriteLine("return __autoProp_" + property.Identifier.ValueText + ";");
                        }
                        else
                        {
                            writer.WriteLine("__autoProp_" + property.Identifier.Value + " = value;");
                        }
                    }
                    else
                    {
                        foreach (var statement in region.Body.As <BlockSyntax>().Statements)
                        {
                            Core.Write(writer, statement);
                        }
                    }

                    if (!get)
                    {
                        //all haXe property setters must return a value.
                        writer.WriteLine("return value;");
                    }
                }

                writer.WriteCloseBrace();
                writer.WriteLine();
            };

            var getter = property.AccessorList.Accessors.SingleOrDefault(o => o.Keyword.Kind() == SyntaxKind.GetKeyword);
            var setter = property.AccessorList.Accessors.SingleOrDefault(o => o.Keyword.Kind() == SyntaxKind.SetKeyword);

            if (getter == null && setter == null)
            {
                throw new Exception("Property must have either a get or a set");
            }


            if (!property.Modifiers.Any(SyntaxKind.OverrideKeyword))
            {
                //Write the property declaration.  Overridden properties don't need this.
                writer.WriteIndent();
                if (property.Modifiers.Any(SyntaxKind.PublicKeyword) || property.Modifiers.Any(SyntaxKind.InternalKeyword))
                {
                    writer.Write("public ");
                }
                if (property.Modifiers.Any(SyntaxKind.StaticKeyword))
                {
                    writer.Write("static ");
                }

                writer.Write("var ");
                writer.Write(property.Identifier.ValueText);
                writer.Write("(");

                if (getter != null)
                {
                    writer.Write("get_" + property.Identifier.ValueText);
                }
                else
                {
                    writer.Write("never");
                }

                writer.Write(", ");

                if (setter != null)
                {
                    writer.Write("set_" + property.Identifier.ValueText);
                }
                else
                {
                    writer.Write("never");
                }

                writer.Write("):");
                writer.Write(TypeProcessor.ConvertType(property.Type));
                writer.Write(";\r\n");
            }

            if (!isInterface) //interfaces get only the property decl, never the functions
            {
                if (getter != null)
                {
                    writeRegion(getter, true);
                }
                if (setter != null)
                {
                    writeRegion(setter, false);
                }
            }

            if (isAutoProperty)
            {
                writer.WriteLine("var __autoProp_" + property.Identifier.ValueText + TypeProcessor.ConvertTypeWithColon(property.Type) + " = " + TypeProcessor.DefaultValue(TypeProcessor.ConvertType(property.Type)) + ";");
            }
        }
Пример #28
0
        public static string TypeParameter(TypeParameterSyntax prm, IEnumerable <TypeParameterConstraintClauseSyntax> constraints)
        {
            var identifier = prm.Identifier.ValueText;

            var constraint = constraints.SingleOrDefault(o => o.Name.Identifier.ValueText == identifier);

            if (constraint == null)
            {
                return(identifier);
            }

            return(identifier + ": (" + string.Join(", ", constraint.Constraints.OfType <TypeConstraintSyntax>().ToList().Select(o => TypeProcessor.ConvertType(o.Type))) + ")");
        }
Пример #29
0
        public static void Go(HaxeWriter writer, ExpressionSyntax left, SyntaxToken operatorToken, ExpressionSyntax right)
        {
            //Check for index assignments, for example dictionary[4] = 3;
            if (left is ElementAccessExpressionSyntax && operatorToken.Kind() == SyntaxKind.EqualsToken)
            {
                var elementAccess = (ElementAccessExpressionSyntax)left;

                var typeHaxe = TypeProcessor.ConvertType(Program.GetModel(left).GetTypeInfo(elementAccess.Expression).ConvertedType);

                if (!typeHaxe.StartsWith("Array<"))                 //arrays are the only thing haxe allows assignments into via indexing
                {
                    WriteIndexingExpression(writer, operatorToken, right, elementAccess);
                    return;
                }
            }


            //Check for improper nullable access, unless it's assignment or string concat, which work fine.  Note that if they're trying to add nullable number types, it won't catch it since we can't tell if it's string concatentation or addition.  But haxe will fail to build, so it should still be caught easily enough.
            if (operatorToken.Kind() != SyntaxKind.EqualsToken && operatorToken.Kind() != SyntaxKind.PlusToken)
            {
                var model = Program.GetModel(left);
                Func <ExpressionSyntax, bool> isNullable = e =>
                {
                    var t = model.GetTypeInfo(e).Type;
                    return(t != null && t.Name == "Nullable");
                };

                if (isNullable(left) || isNullable(right))
                {
                    throw new Exception("When using nullable types, you must use the .Value and .HasValue properties instead of the object directly " + Utility.Descriptor(left.Parent));
                }
            }

            if (operatorToken.Kind() == SyntaxKind.PlusEqualsToken || operatorToken.Kind() == SyntaxKind.MinusEqualsToken)
            {
                //Check for event subscription/removal
                var leftSymbol = Program.GetModel(left).GetSymbolInfo(left);
                if (leftSymbol.Symbol is IEventSymbol)
                {
                    Core.Write(writer, left);
                    if (operatorToken.Kind() == SyntaxKind.PlusEqualsToken)
                    {
                        writer.Write(".Add(");
                    }
                    else
                    {
                        writer.Write(".Remove(");
                    }
                    Core.Write(writer, right);
                    writer.Write(")");
                    return;
                }
            }

            if (operatorToken.Kind() == SyntaxKind.AsKeyword)
            {
                var leftStr = Utility.TryGetIdentifier(left);

                if (leftStr == null)
                {
                    throw new Exception("The \"as\" keyword can only be used on simple names.  Declare it as a local variable. " + Utility.Descriptor(left.Parent));
                }

                var typeHaxe = TypeProcessor.ConvertType(right);

                writer.Write("(Std.is(" + leftStr + ", " + typeHaxe + ") ? cast(" + leftStr + ", " + typeHaxe + ") : null)");
            }
            else if (operatorToken.Kind() == SyntaxKind.IsKeyword)
            {
                writer.Write("Std.is(");
                Core.Write(writer, left);
                writer.Write(", ");
                writer.Write(TypeProcessor.RemoveGenericArguments(TypeProcessor.ConvertType(right)));
                writer.Write(")");
            }
            else if (operatorToken.Kind() == SyntaxKind.QuestionQuestionToken)
            {
                writer.Write("Cs2Hx.Coalesce(");
                Core.Write(writer, left);
                writer.Write(", ");
                Core.Write(writer, right);
                writer.Write(")");
            }
            else
            {
                var leftType  = Program.GetModel(left).GetTypeInfo(left);
                var rightType = Program.GetModel(right).GetTypeInfo(right);

                if ((operatorToken.Kind() == SyntaxKind.EqualsEqualsToken || operatorToken.Kind() == SyntaxKind.ExclamationEqualsToken) &&
                    leftType.ConvertedType.SpecialType == SpecialType.System_Boolean &&
                    rightType.ConvertedType.SpecialType == SpecialType.System_Boolean)
                {
                    //Anytime we == or != booleans, we need to take special care when dealing with the js target.  haxe seems to leave some variables as undefined, which works fine as booleans in most comparisons, but not when comparing against each other such as "x == false"
                    if (operatorToken.Kind() == SyntaxKind.ExclamationEqualsToken)
                    {
                        writer.Write("!");
                    }
                    writer.Write("Cs2Hx.BoolCompare(");
                    Core.Write(writer, left);
                    writer.Write(", ");
                    Core.Write(writer, right);
                    writer.Write(")");
                    return;
                }

                Action <ExpressionSyntax, ExpressionSyntax> write = (e, otherSide) =>
                {
                    var type      = Program.GetModel(left).GetTypeInfo(e);
                    var otherType = Program.GetModel(left).GetTypeInfo(otherSide);
                    //Check for enums being converted to strings by string concatenation
                    if (operatorToken.Kind() == SyntaxKind.PlusToken && type.Type.TypeKind == TypeKind.Enum)
                    {
                        writer.Write(type.Type.ContainingNamespace.FullNameWithDot().ToLower());
                        writer.Write(WriteType.TypeName(type.Type.As <INamedTypeSymbol>()));
                        writer.Write(".ToString(");
                        Core.Write(writer, e);
                        writer.Write(")");
                    }
                    else if (operatorToken.Kind() == SyntaxKind.PlusToken && type.Type.SpecialType == SpecialType.System_Char && otherType.Type.SpecialType != SpecialType.System_Char && otherType.Type.SpecialType != SpecialType.System_Int32)
                    {
                        //Chars are integers in haxe, so when string-concatening them we must convert them to strings
                        writer.Write("Cs2Hx.CharToString(");
                        Core.Write(writer, e);
                        writer.Write(")");
                    }
                    else if (operatorToken.Kind() == SyntaxKind.PlusToken && !(e is BinaryExpressionSyntax) && type.Type.SpecialType == SpecialType.System_String && CouldBeNullString(Program.GetModel(e), e))
                    {
                        //In .net, concatenating a null string does not alter the output. However, in haxe's js target, it produces the "null" string. To counter this, we must check non-const strings.
                        writer.Write("system.Cs2Hx.NullCheck(");
                        Core.Write(writer, e);
                        writer.Write(")");
                    }
                    else
                    {
                        Core.Write(writer, e);
                    }
                };

                write(left, right);
                writer.Write(" ");
                writer.Write(operatorToken.ToString());                 //we can do this since haxe operators work just like C# operators
                writer.Write(" ");
                write(right, left);
            }
        }
Пример #30
0
        public static void WriteInstanceConstructor(HaxeWriter writer, ConstructorDeclarationSyntax ctorOpt)
        {
            writer.WriteIndent();

            writer.Write("public function new(");


            if (ctorOpt != null)
            {
                var firstParameter = true;
                foreach (var parameter in ctorOpt.ParameterList.Parameters)
                {
                    if (firstParameter)
                    {
                        firstParameter = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    writer.Write(parameter.Identifier.ValueText);
                    writer.Write(TypeProcessor.ConvertTypeWithColon(parameter.Type));

                    if (parameter.Default != null)
                    {
                        writer.Write(" = ");
                        Core.Write(writer, parameter.Default.Value);
                    }
                }
            }

            writer.Write(")\r\n");
            writer.WriteOpenBrace();

            if (!TypeState.Instance.DerivesFromObject)
            {
                if (ctorOpt == null || ctorOpt.Initializer == null)
                {
                    writer.WriteLine("super();");
                }
                else
                {
                    if (ctorOpt.Initializer.ThisOrBaseKeyword.ToString() != "base")
                    {
                        throw new Exception("Constructor overloading not supported " + Utility.Descriptor(ctorOpt));
                    }

                    writer.WriteIndent();
                    writer.Write("super(");

                    bool first = true;
                    foreach (var init in ctorOpt.Initializer.ArgumentList.Arguments)
                    {
                        if (first)
                        {
                            first = false;
                        }
                        else
                        {
                            writer.Write(", ");
                        }

                        Core.Write(writer, init.Expression);
                    }

                    writer.Write(");\r\n");
                }
            }


            foreach (var field in TypeState.Instance.AllMembers
                     .OfType <BaseFieldDeclarationSyntax>()
                     .Where(o => !o.Modifiers.Any(SyntaxKind.StaticKeyword))
                     .SelectMany(o => o.Declaration.Variables)
                     .Where(o =>
                            (o.Initializer != null && !WriteField.IsConst(o.Parent.Parent.As <BaseFieldDeclarationSyntax>().Modifiers, o.Initializer, o.Parent.As <VariableDeclarationSyntax>().Type))
                            ||
                            (o.Initializer == null && GenerateInitializerForFieldWithoutInitializer(o.Parent.As <VariableDeclarationSyntax>().Type))
                            ||
                            o.Parent.Parent is EventFieldDeclarationSyntax))
            {
                var parentType = field.Parent.As <VariableDeclarationSyntax>().Type;

                writer.WriteIndent();
                writer.Write(field.Identifier.ValueText);
                writer.Write(" = ");

                if (field.Parent.Parent is EventFieldDeclarationSyntax)
                {
                    writer.Write("new CsEvent<");
                    writer.Write(TypeProcessor.ConvertType(parentType));
                    writer.Write(">()");
                }
                else if (field.Initializer == null)
                {
                    if (TypeProcessor.ValueToReference(parentType))
                    {
                        writer.Write("new ");
                        writer.Write(TypeProcessor.ConvertType(parentType));
                        writer.Write("()");
                    }
                    else
                    {
                        writer.Write(TypeProcessor.DefaultValue(TypeProcessor.ConvertType(parentType)));
                    }
                }
                else
                {
                    Core.Write(writer, field.Initializer.Value);
                }

                writer.Write(";\r\n");
            }



            if (ctorOpt != null && ctorOpt.Body != null)
            {
                foreach (var statement in ctorOpt.Body.As <BlockSyntax>().Statements)
                {
                    Core.Write(writer, statement);
                }

                TriviaProcessor.ProcessTrivias(writer, ctorOpt.Body.DescendantTrivia());
            }

            writer.WriteCloseBrace();
        }