예제 #1
0
        public static void Go(ScalaWriter 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;
                }
            }

            var methodSymbol = Program.GetModel(method).GetDeclaredSymbol(method);


            if (method.Identifier.ValueText == "GetEnumerator")
            {
                WriteGetEnumeratorFunction(writer, method, methodSymbol);
                return;
            }


            writer.WriteIndent();

            if (ShouldUseOverrideKeyword(method, methodSymbol))
            {
                writer.Write("override ");
            }
            if (method.Modifiers.Any(SyntaxKind.PrivateKeyword))
            {
                writer.Write("private ");
            }

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

            if (methodName == "ToString")
            {
                methodName = "toString";
            }
            else if (methodName == "Equals")
            {
                methodName = "equals";
            }
            else if (methodName == "GetHashCode")
            {
                methodName = "hashCode";
            }
            else if (methodName == "Main")
            {
                methodName = "main";
            }

            writer.Write(methodName);

            if (method.TypeParameterList != null)
            {
                writer.Write("[");
                writer.Write(string.Join(", ", method.TypeParameterList.Parameters.Select(o => TypeParameter(o, methodSymbol, method))));
                writer.Write("]");
            }

            writer.Write("(");

            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(WriteIdentifierName.TransformIdentifier(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(" = ");
                    Core.Write(writer, parameter.Default.Value);
                }
            }

            writer.Write(")");
            bool returnsVoid = method.ReturnType.ToString() == "void";

            if (!returnsVoid)
            {
                writer.Write(TypeProcessor.ConvertTypeWithColon(method.ReturnType));
            }

            if (method.Modifiers.Any(SyntaxKind.AbstractKeyword) || method.Parent is InterfaceDeclarationSyntax)
            {
                writer.Write(";\r\n");
            }
            else
            {
                if (!returnsVoid)
                {
                    writer.Write(" =");
                }

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

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

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

                writer.WriteCloseBrace();
            }
        }
예제 #2
0
        public static void Go(ScalaWriter 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("symbolInfo.Symbol null at " + Utility.Descriptor(invocationExpression));
            }
            if (symbolInfo.Symbol.OriginalDefinition == null)
            {
                throw new Exception("symbolInfo.Symbol.OriginalDefinition null at " + 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 firstParameter = true;

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

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

                if (methodSymbol.Name == "TryParse")
                {
                    WriteEnumTryParse(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":
                    if (invocationExpression.ArgumentList.Arguments.Count > 1)
                    {
                        throw new Exception("Multiple arguments to .Parse methods are not supported: " + Utility.Descriptor(invocationExpression));
                    }
                    Core.Write(writer, invocationExpression.ArgumentList.Arguments.Single().Expression);

                    writer.Write(".trim().to");     //we must trim strings before parsing them.  In C#, a string like "4 " parses just fine, but if we don't trim this same string would false to parse in java
                    writer.Write(TypeProcessor.ConvertType(methodSymbol.ReturnType));

                    return;

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

                default:
                    methodName         = methodSymbol.Name;
                    extensionNamespace = "CsScala";
                    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);
                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;
            }



            //When the code specifically names generic arguments, include them in the method name
            var genNameExpression = invocationExpression.Expression as GenericNameSyntax;

            if (genNameExpression == null && memberReferenceExpressionOpt != null)
            {
                genNameExpression = memberReferenceExpressionOpt.Name as GenericNameSyntax;
            }
            if (genNameExpression != null && genNameExpression.TypeArgumentList.Arguments.Count > 0)
            {
                typeParameters = "[" + string.Join(", ", genNameExpression.TypeArgumentList.Arguments.Select(TypeProcessor.ConvertType)) + "]";
            }


            //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;
            }

            var memberType     = memberReferenceExpressionOpt == null ? null : model.GetTypeInfo(memberReferenceExpressionOpt.Expression).Type;
            var isNullableEnum = memberType != null && (memberType.Name == "Nullable" && memberType.ContainingNamespace.FullName() == "System") && memberType.As <INamedTypeSymbol>().TypeArguments.Single().TypeKind == TypeKind.Enum;

            if (isNullableEnum && methodSymbol.Name == "ToString")
            {
                extensionNamespace = null; //override Translations.xml for nullable enums. We want them to convert to the enum's ToString method
                methodName         = "toString";
            }


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

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

                WriteTypeParameters(writer, translateOpt, typeParameters, invocationExpression);


                writer.Write("(");

                if (subExpressionOpt != null)
                {
                    firstParameter = false;
                    Core.Write(writer, subExpressionOpt);
                }
            }
            else
            {
                if (memberReferenceExpressionOpt != null)
                {
                    //Check against lowercase toString since it gets replaced with the lowered version before we get here
                    if (methodName == "toString")
                    {
                        if (memberType.TypeKind == TypeKind.Enum || isNullableEnum)
                        {
                            var enumType = memberType.TypeKind == TypeKind.Enum ? memberType : memberType.As <INamedTypeSymbol>().TypeArguments.Single();

                            //calling ToString() on an enum forwards to our enum's special ToString method
                            writer.Write(enumType.ContainingNamespace.FullNameWithDot());
                            writer.Write(WriteType.TypeName((INamedTypeSymbol)enumType));
                            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_Byte)
                        {
                            //Calling ToString on a byte needs to take special care since it's signed in the JVM
                            writer.Write("System.CsScala.ByteToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

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

                            return;
                        }
                    }
                }

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

                    if (methodName != null)
                    {
                        writer.Write(".");
                    }
                }
                else if (methodSymbol.IsStatic && extensionNamespace == null)
                {
                    writer.Write(methodSymbol.ContainingNamespace.FullNameWithDot());
                    writer.Write(WriteType.TypeName(methodSymbol.ContainingType));
                    writer.Write(".");
                }


                writer.Write(methodName);
                WriteTypeParameters(writer, translateOpt, typeParameters, invocationExpression);
                writer.Write("(");
            }

            bool inParams         = false;
            bool foundParamsArray = false;

            foreach (var arg in TranslateParameters(translateOpt, invocationExpression.ArgumentList.Arguments, invocationExpression))
            {
                if (firstParameter)
                {
                    firstParameter = false;
                }
                else
                {
                    writer.Write(", ");
                }

                if (!inParams && IsParamsArgument(invocationExpression, arg.ArgumentOpt, methodSymbol))
                {
                    foundParamsArray = true;

                    if (!TypeProcessor.ConvertType(model.GetTypeInfo(arg.ArgumentOpt.Expression).Type).StartsWith("Array["))
                    {
                        inParams = true;
                        writer.Write("Array(");
                    }
                }


                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
                {
                    arg.Write(writer);
                }
            }

            if (inParams)
            {
                writer.Write(")");
            }
            else if (!foundParamsArray && methodSymbol.Parameters.Any() && methodSymbol.Parameters.Last().IsParams)
            {
                writer.Write(", Array()"); //params method called without any params argument.  Send an empty array.
            }
            writer.Write(")");
        }