Exemplo n.º 1
0
        public static void Go(HaxeWriter writer, TryStatementSyntax tryStatement)
        {
            if (tryStatement.Finally != null)
            {
                throw new Exception("Finally blocks are not supported in haxe. " + Utility.Descriptor(tryStatement.Finally));
            }

            writer.WriteLine("try");
            Core.Write(writer, tryStatement.Block);

            foreach (var catchClause in tryStatement.Catches)
            {
                if (Program.DoNotWrite.ContainsKey(catchClause))
                {
                    continue;
                }

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

                if (catchClause.Declaration == null)
                {
                    writer.Write("__ex:Dynamic");
                }
                else
                {
                    var varName = catchClause.Declaration.Identifier.ValueText;

                    if (string.IsNullOrWhiteSpace(varName))
                    {
                        varName = "__ex";
                    }


                    writer.Write(varName);

                    var type = TypeProcessor.ConvertTypeWithColon(catchClause.Declaration.Type);

                    if (type == ":system.Exception")
                    {
                        //when the C# code catches Exception, we assume they want to catch everything, and in haxe we do that by catching Dynamic.  In this case, we also want to ensure the C# code never treats the exception as an Exception, since it might not be an actual Exception type in haxe.  C# code should be changed to only call .ToString() on it.
                        writer.Write(":Dynamic");

                        Func <IdentifierNameSyntax, bool> isOkUseOfException = node =>
                        {
                            //Calling .ToString() is OK on exceptions
                            if (node.Parent is MemberAccessExpressionSyntax &&
                                node.Parent.Parent is InvocationExpressionSyntax &&
                                node.Parent.Parent.As <InvocationExpressionSyntax>().Expression is MemberAccessExpressionSyntax &&
                                node.Parent.Parent.As <InvocationExpressionSyntax>().Expression.As <MemberAccessExpressionSyntax>().Name.Identifier.ValueText == "ToString")
                            {
                                return(true);
                            }

                            //Using them as concatenation in strings is OK
                            if (node.Parent is BinaryExpressionSyntax && node.Parent.As <BinaryExpressionSyntax>().OperatorToken.Kind() == SyntaxKind.PlusToken)
                            {
                                return(true); //we only check that it's a PlusToken, which could be addition or string concatenation, but C# doesn't allow adding exceptions so it's not necessary to check further
                            }
                            var typeInfo = Program.GetModel(node).GetTypeInfo(node);
                            if (typeInfo.ConvertedType.SpecialType == SpecialType.System_Object)
                            {
                                return(true); //OK to use it as an object, since that becomes Dynamic in haxe
                            }
                            return(false);
                        };

                        var usesException = catchClause.Block.DescendantNodes()
                                            .OfType <IdentifierNameSyntax>()
                                            .Where(o => o.Identifier.ValueText == varName)
                                            .Where(o => !isOkUseOfException(o))
                                            .ToList();

                        if (usesException.Count > 0)
                        {
                            throw new Exception("When catching an Exception, you cannot use the object as an Exception object, since the destination platform supports throwing things that don't derive from Exception.  Instead, call .ToString() on it if you need details of it.  " + string.Join(",  ", usesException.Select(Utility.Descriptor)));
                        }
                    }
                    else
                    {
                        writer.Write(type);
                    }
                }
                writer.Write(")\r\n");
                Core.Write(writer, catchClause.Block);
            }
        }
Exemplo n.º 2
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 = symbolInfo.Symbol.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;

            var              extensionNamespace = methodSymbol.IsExtensionMethod ? methodSymbol.ContainingNamespace.FullNameWithDot().ToLower() + methodSymbol.ContainingType.Name : null; //null means it's not an extension method, non-null means it is
            string           methodName;
            ExpressionSyntax subExpressionOpt;

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

                if (methodSymbol.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 (methodSymbol.Name)
                {
                case "Parse":
                    var t = TypeProcessor.ConvertType(methodSymbol.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(methodSymbol.Parameters[1].Type);
                    extensionNamespace = "Cs2Hx";
                    break;

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

            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 (methodSymbol.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() == methodSymbol.ContainingNamespace + "." + methodSymbol.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 (methodSymbol.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(methodSymbol, 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(methodSymbol))
            {
                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 = methodSymbol.TypeParameters.IndexOf(methodSymbol.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, methodSymbol) && 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(")");
        }
        public static void Go(HaxeWriter writer, ObjectCreationExpressionSyntax expression)
        {
            if (expression.ArgumentList == null || expression.Initializer != null)
            {
                throw new Exception("Object initialization syntax is not supported. " + Utility.Descriptor(expression));
            }

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

            if (methodSymbolUntyped == null)
            {
                throw new Exception("methodSymbolUntyped is null");
            }
            var methodSymbol = (IMethodSymbol)methodSymbolUntyped;

            if (type.SpecialType == SpecialType.System_DateTime && expression.ArgumentList.Arguments.Count == 1)
            {
                throw new Exception("You cannot use the DateTime constructor with one argument (ticks).  .net Ticks and Haxe Ticks have different meanings, so this would result in problems. " + Utility.Descriptor(expression));
            }

            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 if (type.SpecialType == SpecialType.System_String)
            {
                //new String()
                writer.Write("Cs2Hx.NewString(");
                bool first = true;
                foreach (var param in WriteInvocationExpression.SortArguments(methodSymbol, expression.ArgumentList.Arguments, expression, false))
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    param.Write(writer);
                }
                writer.Write(")");
            }
            else
            {
                var translateOpt = MethodTranslation.Get(methodSymbol);

                var convertedType = TypeProcessor.ConvertType(expression.Type);

                if (convertedType == "String")
                {
                    //Normally, writing "new String(" in C# will fall under the above check which calls Cs2Hx.NewString.  However, if a translation changes a type into a string, such as with guids, it falls here.  It's important not to ever write "new String(" in haxe since that makes copies of strings which don't compare properly with ==.  So just embed the string straight.
                    Core.Write(writer, expression.ArgumentList.Arguments.Single().Expression);
                }
                else
                {
                    writer.Write("new ");
                    writer.Write(convertedType);
                    writer.Write("(");

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

                        param.Write(writer);
                    }

                    writer.Write(")");
                }
            }
        }
Exemplo n.º 4
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");
            }
        }
Exemplo n.º 5
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" && castingFromHaxe != "Float")
            {
                //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(")");
            }
        }
Exemplo n.º 6
0
        public static void Go(HaxeWriter writer, UsingStatementSyntax usingStatement)
        {
            if (usingStatement.DescendantNodes().OfType <ReturnStatementSyntax>().Any())
            {
                throw new Exception("CS2HX does not support returning from within a using block. " + Utility.Descriptor(usingStatement));
            }

            var expression = usingStatement.Expression;
            //if (expression is ExpressionStatement)
            //	expression = expression.As<ExpressionStatement>().Expression;

            //Generate a resource to identify this using block.  If it's a local variable, we'll use that.
            var resource = Utility.TryGetIdentifier(expression);

            if (resource == null)
            {
                var parent = expression.Parent;
                while (!(parent is MethodDeclarationSyntax))
                {
                    parent = parent.Parent;
                }
                var containingMethod = (MethodDeclarationSyntax)parent;
                if (_identities == null)
                {
                    throw new Exception("_identities is null");
                }
                var id = _identities.ValueOrZero(containingMethod);
                _identities.AddTo(containingMethod, 1);

                resource = "__" + id + "_using";

                writer.WriteIndent();
                writer.Write("var " + resource + " = ");
                Core.Write(writer, expression);
                writer.WriteLine(";");
            }

            writer.WriteLine("var __" + resource + "_usingDisposed:Bool = false;");

            writer.WriteLine("try");
            writer.WriteOpenBrace();

            if (usingStatement.Statement is BlockSyntax)
            {
                foreach (var s in usingStatement.Statement.As <BlockSyntax>().Statements)
                {
                    Core.Write(writer, s);
                }
            }
            else
            {
                Core.Write(writer, usingStatement.Statement);
            }

            writer.WriteLine("__" + resource + "_usingDisposed = true;");
            writer.WriteLine(resource + ".Dispose();");
            writer.WriteCloseBrace();

            writer.WriteLine("catch (__catch_" + resource + ":Dynamic)");
            writer.WriteOpenBrace();
            writer.WriteLine("if (!__" + resource + "_usingDisposed)");
            writer.WriteLine("    " + resource + ".Dispose();");
            writer.WriteLine("throw __catch_" + resource + ";");
            writer.WriteCloseBrace();
        }
Exemplo n.º 7
0
        public static void Go(HaxeWriter writer, MethodDeclarationSyntax 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)
                    .Where(o => o.Identifier.ValueText == method.Identifier.ValueText)
                    .Any())
                {
                    return;
                }
            }

            if (method.Identifier.ValueText == "GetEnumerator")
            {
                return;                 //skip GetEnumerator methods -- haxe can't enumerate on objects.  TODO: Render these out, but convert them to array-returning methods
            }
            var methodSymbol = Program.GetModel(method).GetDeclaredSymbol(method);

            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 (method.TypeParameterList != null)
            {
                writer.Write("<");
                writer.Write(string.Join(", ", method.TypeParameterList.Parameters.Select(o => TypeParameter(o, method.ConstraintClauses))));
                writer.Write(">");
            }

            writer.Write("(");
            var deferredDefaults = new Dictionary <string, ExpressionSyntax>();

            var firstParam = true;

            foreach (var parameter in method.ParameterList.Parameters)
            {
                bool isRef = parameter.Modifiers.Any(SyntaxKind.OutKeyword) || parameter.Modifiers.Any(SyntaxKind.RefKeyword);

                if (firstParam)
                {
                    firstParam = false;
                }
                else
                {
                    writer.Write(", ");
                }

                writer.Write(parameter.Identifier.ValueText);

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

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

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

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

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

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

                if (method.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();
            }
        }
Exemplo n.º 8
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<"))
                        {
                            if (baseType.ToString().StartsWith("System.Collections.Generic.IEnumerable<"))
                            {
                                writer.Write(" implements ");
                                writer.Write("system.collections.generic.IEnumerable<" + baseTypeHaxe.RemoveFromStartOfString("Array<"));
                            }


                            continue;
                        }

                        writer.Write(" ");

                        if (baseType.TypeKind == TypeKind.Interface && first.Syntax.Kind() != SyntaxKind.InterfaceDeclaration)
                        {
                            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("Haxe does not support overloaded constructors.  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();
            }
        }
Exemplo n.º 9
0
        public static void Go(HaxeWriter writer, ObjectCreationExpressionSyntax expression)
        {
            if (expression.ArgumentList == null || expression.Initializer != null)
            {
                throw new Exception("Object initialization syntax is not supported. " + Utility.Descriptor(expression));
            }

            var model        = Program.GetModel(expression);
            var type         = model.GetTypeInfo(expression).Type;
            var methodSymbol = model.GetSymbolInfo(expression).Symbol.As <IMethodSymbol>();

            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 if (type.SpecialType == SpecialType.System_String)
            {
                //new String()
                writer.Write("Cs2Hx.NewString(");
                bool first = true;
                foreach (var param in WriteInvocationExpression.SortArguments(methodSymbol, expression.ArgumentList.Arguments, expression, false))
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    param.Write(writer);
                }
                writer.Write(")");
            }
            else
            {
                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, false), expression))
                {
                    if (first)
                    {
                        first = false;
                    }
                    else
                    {
                        writer.Write(", ");
                    }

                    param.Write(writer);
                }

                writer.Write(")");
            }
        }
Exemplo n.º 10
0
 public static void Go(HaxeWriter writer, ThisExpressionSyntax expression)
 {
     writer.Write("this");
 }
Exemplo n.º 11
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("; } ");
            }
        }
Exemplo n.º 12
0
 public static void Go(HaxeWriter writer, GenericNameSyntax name)
 {
     writer.Write(name.Identifier.ValueText);             //leave off generic parameters for haxe
 }