public static void Go(ScalaWriter writer, ElementAccessExpressionSyntax expression) { var typeStr = TypeProcessor.GenericTypeName(Program.GetModel(expression).GetTypeInfo(expression.Expression).Type); var trans = ElementAccessTranslation.Get(typeStr); Core.Write(writer, expression.Expression); if (trans != null) { writer.Write("."); writer.Write(trans.ReplaceGet); } writer.Write("("); bool first = true; foreach (var argument in expression.ArgumentList.Arguments) { if (first) { first = false; } else { writer.Write(", "); } Core.Write(writer, argument.Expression); } writer.Write(")"); }
public static void Go(ScalaWriter 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("final val "); } else { writer.Write("var "); } writer.Write(name); writer.Write(TypeProcessor.ConvertTypeWithColon(type)); writer.Write(" = "); if (initializerOpt != null) { Core.Write(writer, initializerOpt.Value); } else { writer.Write(TypeProcessor.DefaultValue(type)); } writer.Write(";"); writer.WriteLine(); }
public static void Write(ScalaWriter writer, SyntaxNode node, bool isConst = false) { TriviaProcessor.ProcessNode(writer, node); if (Program.DoNotWrite.ContainsKey(node)) { return; } var exprOpt = node as ExpressionSyntax; string postFactory = null; if (exprOpt != null) { var type = Program.GetModel(node).GetTypeInfo(exprOpt); if (type.Type != null && type.Type.SpecialType == SpecialType.System_Byte && type.ConvertedType.SpecialType != SpecialType.System_Byte && Utility.IsNumeric(type.ConvertedType)) { //Bytes are signed in the JVM, so we have to take care when up-converting them writer.Write("System.CsScala.ByteTo"); writer.Write(TypeProcessor.ConvertType(type.ConvertedType)); writer.Write("("); postFactory = ")"; } } Factory(writer, node, isConst); writer.Write(postFactory); }
public static void Go(ScalaWriter 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 srcTypeScala = TypeProcessor.ConvertType((ITypeSymbol)castingFrom); var destType = model.GetTypeInfo(expression.Type).Type; var destTypeScala = TypeProcessor.TryConvertType(expression.Type); if (destTypeScala == srcTypeScala) { //Eat casts where the types are identical. Enums getting casted to int fall here, and since we use ints to represent enums anyway, it's not necessary. Core.Write(writer, expression.Expression); } else if (symbol.Symbol != null && srcTypeScala != "Int" && srcTypeScala != "String" && srcTypeScala != "Bool") { //when the symbol is non-null, this indicates we're calling a cast operator function writer.Write(TypeProcessor.ConvertType(symbol.Symbol.ContainingType)); writer.Write(".op_Explicit_"); writer.Write(destTypeScala.TrySubstringBeforeFirst('[').Replace('.', '_')); writer.Write("("); Core.Write(writer, expression.Expression); writer.Write(")"); } else if (TypeProcessor.IsPrimitiveType(srcTypeScala) && TypeProcessor.IsPrimitiveType(destTypeScala)) { if (srcTypeScala == "Byte") { //JVM's bytes are signed, so we must take care when upcasting writer.Write("System.CsScala.ByteTo"); writer.Write(destTypeScala); writer.Write("("); Core.Write(writer, expression.Expression); writer.Write(")"); } else { //Casting between primitives is handled in scala bo the .toXX functions Core.Write(writer, expression.Expression); writer.Write(".to"); writer.Write(destTypeScala); } } else { Core.Write(writer, expression.Expression); writer.Write(".asInstanceOf["); writer.Write(destTypeScala); writer.Write("]"); } }
public static void Go(ScalaWriter writer, TryStatementSyntax tryStatement) { writer.WriteLine("try"); Core.Write(writer, tryStatement.Block); var catches = tryStatement.Catches.Where(o => Program.DoNotWrite.ContainsKey(o) == false).ToList(); if (catches.Count > 0) { writer.WriteLine("catch"); writer.WriteOpenBrace(); foreach (var catchClause in catches) { writer.WriteIndent(); //In C#, the base exception type is Exception, but on the JVM it is Throwable. Normally, JVM programs should not catch throwable, so we map the C# Exception type to the JVM Exception type by default. We attempted to change Exception to map to Throwable but ran into issues with things getting caught that shouldn't, such as Scala's "BreakControl" that's used on break statements. //if C# code really wants to catch all throwables, catch Exception and name the variable "allThrowables". This is a signal to CSScala that all throwables should be caught. However, use it with care, as it can cause complications. if (catchClause.Declaration == null) { writer.Write("case __ex: java.lang.Exception => "); } else { writer.Write("case "); writer.Write(string.IsNullOrWhiteSpace(catchClause.Declaration.Identifier.ValueText) ? "__ex" : WriteIdentifierName.TransformIdentifier(catchClause.Declaration.Identifier.ValueText)); writer.Write(": "); if (catchClause.Declaration.Identifier.ValueText == "allThrowables") { writer.Write("java.lang.Throwable"); } else { writer.Write(TypeProcessor.ConvertType(catchClause.Declaration.Type)); } writer.Write(" =>\r\n"); } writer.Indent++; foreach (var statement in catchClause.Block.Statements) { Core.Write(writer, statement); } writer.Indent--; } writer.WriteCloseBrace(); } if (tryStatement.Finally != null) { writer.WriteLine("finally"); Core.Write(writer, tryStatement.Finally.Block); } }
public static void Go(ScalaWriter 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(WriteIdentifierName.TransformIdentifier(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(declaration.Declaration.Type)); } else { Core.Write(writer, variable.Initializer.As <EqualsValueClauseSyntax>().Value); } writer.Write(")"); } else { writer.Write(TypeProcessor.ConvertTypeWithColon(declaration.Declaration.Type)); writer.Write(" = "); if (variable.Initializer != null) { Core.Write(writer, variable.Initializer.As <EqualsValueClauseSyntax>().Value); } else { writer.Write(TypeProcessor.DefaultValue(declaration.Declaration.Type)); } } writer.Write(";\r\n"); } }
public static void WriteAnonymousType(AnonymousObjectCreationExpressionSyntax syntax) { var type = Program.GetModel(syntax).GetTypeInfo(syntax).Type.As <INamedTypeSymbol>(); var anonName = TypeName(type); using (var writer = new ScalaWriter("anonymoustypes", StripGeneric(anonName))) { var fields = type.GetMembers().OfType <IPropertySymbol>().OrderBy(o => o.Name).ToList(); writer.WriteLine("package anonymoustypes;"); WriteImports.Go(writer); writer.WriteIndent(); writer.Write("class "); writer.Write(anonName); writer.Write("("); bool first = true; foreach (var field in fields) { if (first) { first = false; } else { writer.Write(", "); } writer.Write("_"); writer.Write(WriteIdentifierName.TransformIdentifier(field.Name)); writer.Write(TypeProcessor.ConvertTypeWithColon(field.Type)); } writer.Write(")\r\n"); writer.WriteOpenBrace(); foreach (var field in fields) { writer.WriteIndent(); writer.Write("final var "); writer.Write(WriteIdentifierName.TransformIdentifier(field.Name)); writer.Write(TypeProcessor.ConvertTypeWithColon(field.Type)); writer.Write(" = _"); writer.Write(WriteIdentifierName.TransformIdentifier(field.Name)); writer.Write(";\r\n"); } writer.WriteCloseBrace(); } }
private static bool IsAmbiguousType(ITypeSymbol type) { switch (TypeProcessor.GenericTypeName(type)) { case "System.UInt16": case "System.UInt32": case "System.UInt64": return(true); default: return(false); } }
private static void WriteGetEnumeratorFunction(ScalaWriter writer, MethodDeclarationSyntax 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; } writer.WriteIndent(); writer.Write("def foreach[U](fn: "); writer.Write(enumerableType); writer.Write(" => U)\r\n"); writer.WriteOpenBrace(); writer.WriteIndent(); Core.Write(writer, member.Expression); writer.Write(".foreach(fn);\r\n"); writer.WriteCloseBrace(); }
public static bool NeedsClassTag(INamedTypeSymbol symbol, string templateID) { //For types, unlike methods, this requires that they're specified in Translations.xml. TODO: Determine these programmatically. //var symbol = Program.GetModel(typeSyntax).GetDeclaredSymbol(typeSyntax); var trans = NeedsClassTagTranslation.Get(TypeProcessor.GenericTypeName(symbol)); if (trans == null || trans.TypesHashSet == null) { return(false); } else { return(trans.TypesHashSet.Contains(templateID)); } }
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()) + "]"); var ret = "Anon_" + string.Join("__", fields .OrderBy(o => o.Name) .Select(o => o.Name + "_" + TypeProcessor.ConvertType(o.Type).Replace('.', '_').Replace("[", "_").Replace("]", "_"))) + genericSuffix; return(ret); }
private static void WriteThreadStatic(ScalaWriter writer, VariableDeclaratorSyntax declaration, FieldDeclarationSyntax field) { /*val __Init = new ThreadLocal[String]() * { override def initialValue():String = ""initval""; }; * def Init:String = __Init.get(); * def Init_=(value:String) = __Init.set(value);*/ var type = TypeProcessor.ConvertType(field.Declaration.Type); writer.WriteIndent(); writer.Write("final val __"); writer.Write(declaration.Identifier.ValueText); writer.Write(" = new ThreadLocal["); writer.Write(type); writer.Write("]()"); if (declaration.Initializer != null) { writer.Write("\r\n"); writer.WriteIndent(); writer.Write("{ override def initialValue():"); writer.Write(type); writer.Write(" = "); Core.Write(writer, declaration.Initializer.Value); writer.Write("; }"); } writer.Write(";\r\n"); writer.WriteIndent(); writer.Write("def "); writer.Write(declaration.Identifier.ValueText); writer.Write(":"); writer.Write(type); writer.Write(" = __"); writer.Write(declaration.Identifier.ValueText); writer.Write(".get();\r\n"); writer.WriteIndent(); writer.Write("def "); writer.Write(declaration.Identifier.ValueText); writer.Write("_=(value:"); writer.Write(type); writer.Write(") = __"); writer.Write(declaration.Identifier.ValueText); writer.Write(".set(value);\r\n"); }
public static void Go(ScalaWriter writer, ArrayCreationExpressionSyntax array) { if (array.Type.RankSpecifiers.Count > 1 || array.Type.RankSpecifiers.Single().Sizes.Count > 1) { throw new Exception("Multi-dimensional arrays are not supported " + Utility.Descriptor(array)); } var rankExpression = array.Type.RankSpecifiers.Single().Sizes.Single(); if (rankExpression is OmittedArraySizeExpressionSyntax) { writer.Write("Array["); writer.Write(TypeProcessor.ConvertType(array.Type.ElementType)); writer.Write("]("); bool first = true; foreach (var expression in array.Initializer.Expressions) { if (first) { first = false; } else { writer.Write(", "); } Core.Write(writer, expression); } writer.Write(")"); } else { if (array.Initializer != null) { throw new Exception("Initalizers along with array sizes are not supported - please use a size or an initializer " + Utility.Descriptor(array)); } writer.Write("new Array["); writer.Write(TypeProcessor.ConvertType(array.Type.ElementType)); writer.Write("]("); Core.Write(writer, array.Type.RankSpecifiers.Single().Sizes.Single()); writer.Write(")"); } }
public static void Go(ScalaWriter 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("def 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(WriteIdentifierName.TransformIdentifier(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(); }
private static HashSet <string> TryGetBCLClassTags(IMethodSymbol method) { var methodStr = TypeProcessor.GenericTypeName(method.ContainingType) + "." + method.Name; var trans = NeedsClassTagTranslation.Get(methodStr); if (trans == null) { return(null); } if (trans.TypesHashSet != null) { return(trans.TypesHashSet); } else { return(method.TypeParameters.ToArray().Select(o => o.ToString()).ToHashSet(true)); } }
public static void Go(ScalaWriter writer, GenericNameSyntax name) { writer.Write(WriteIdentifierName.TransformIdentifier(name.Identifier.ValueText)); writer.Write("["); bool first = true; foreach (var gen in name.TypeArgumentList.Arguments) { if (first) { first = false; } else { writer.Write(", "); } writer.Write(TypeProcessor.ConvertType(gen)); } writer.Write("]"); }
private static string TransformTypeConstraint(TypeParameterConstraintSyntax constraint) { if (constraint is TypeConstraintSyntax) { return(" <% " + TypeProcessor.ConvertType(constraint.As <TypeConstraintSyntax>().Type)); } else if (constraint is ClassOrStructConstraintSyntax) { if (constraint.As <ClassOrStructConstraintSyntax>().ClassOrStructKeyword.Kind() == SyntaxKind.ClassKeyword) { return(" >: Null"); } else { throw new Exception("struct type constraint not supported " + Utility.Descriptor(constraint)); } } else { throw new Exception(constraint.GetType().Name); } }
public static void Go(ScalaWriter writer, PropertyDeclarationSyntax property) { Action <AccessorDeclarationSyntax, bool> writeRegion = (region, get) => { writer.WriteIndent(); if (property.Modifiers.Any(SyntaxKind.OverrideKeyword)) { writer.Write("override "); } if (property.Modifiers.Any(SyntaxKind.PrivateKeyword)) { writer.Write("private "); } writer.Write("def "); writer.Write(WriteIdentifierName.TransformIdentifier(property.Identifier.ValueText)); if (get) { writer.Write(TypeProcessor.ConvertTypeWithColon(property.Type)); } else { writer.Write("_=(value"); writer.Write(TypeProcessor.ConvertTypeWithColon(property.Type)); writer.Write(")"); } if (property.Modifiers.Any(SyntaxKind.AbstractKeyword) || region.Body == null) { writer.Write(";\r\n"); } else { writer.Write(" =\r\n"); Core.WriteBlock(writer, region.Body.As <BlockSyntax>()); } }; 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 (getter != null && setter != null && setter.Body == null && getter.Body == null) { //Both get and set are null, which means this is an automatic property. For our purposes, this is the equivilant of a field WriteField.Go(writer, property.Modifiers, WriteIdentifierName.TransformIdentifier(property.Identifier.ValueText), property.Type); } else { if (getter != null) { writeRegion(getter, true); } else if (setter != null) { //Scala does not allow having a setter without a getter. Write out a getter. writer.Write("def "); writer.Write(WriteIdentifierName.TransformIdentifier(property.Identifier.ValueText)); writer.Write(TypeProcessor.ConvertTypeWithColon(property.Type)); writer.Write(" =\r\n"); writer.WriteOpenBrace(); writer.WriteLine("throw new Exception(\"No getter defined\");"); writer.WriteCloseBrace(); } if (setter != null) { writeRegion(setter, false); } } }
public static bool IsGenericType(this INamedTypeSymbol symbolOpt) { return(symbolOpt != null && symbolOpt.IsGenericType && TypeProcessor.TypeArguments(symbolOpt).Any()); }
public static void Go(ScalaWriter writer, ForStatementSyntax forStatement) { var info = new LoopInfo(forStatement); writer.WriteLine("{ //for"); writer.Indent++; info.WritePreLoop(writer); if (forStatement.Declaration != null) { foreach (var variable in forStatement.Declaration.Variables) { writer.WriteIndent(); writer.Write("var "); writer.Write(WriteIdentifierName.TransformIdentifier(variable.Identifier.ValueText)); writer.Write(TypeProcessor.ConvertTypeWithColon(forStatement.Declaration.Type)); if (variable.Initializer != null) { writer.Write(" = "); Core.Write(writer, variable.Initializer.Value); } writer.Write(";\r\n"); } } foreach (var init in forStatement.Initializers) { writer.WriteIndent(); Core.Write(writer, init); writer.Write(";\r\n"); } writer.WriteIndent(); writer.Write("while ("); if (forStatement.Condition == null) { writer.Write("true"); } else { Core.Write(writer, forStatement.Condition); } writer.Write(")\r\n"); writer.WriteOpenBrace(); info.WriteLoopOpening(writer); Core.WriteStatementAsBlock(writer, forStatement.Statement, false); info.WriteLoopClosing(writer); foreach (var iterator in forStatement.Incrementors) { writer.WriteIndent(); Core.Write(writer, iterator); writer.Write(";\r\n"); } writer.WriteCloseBrace(); info.WritePostLoop(writer); writer.Indent--; writer.WriteLine("} //end for"); }
private static void Go(ScalaWriter writer, IEnumerable <ParameterSyntax> parameters, SyntaxNode body, TypeInfo type) { var methodSymbol = type.ConvertedType.As <INamedTypeSymbol>().DelegateInvokeMethod.As <IMethodSymbol>(); writer.Write("("); for (int pi = 0; pi < parameters.Count(); pi++) { var parameter = parameters.ElementAt(pi); if (pi > 0) { writer.Write(", "); } writer.Write(WriteIdentifierName.TransformIdentifier(parameter.Identifier.ValueText)); if (parameter.Type != null) { writer.Write(TypeProcessor.ConvertTypeWithColon(parameter.Type)); } else { writer.Write(TypeProcessor.ConvertTypeWithColon(methodSymbol.Parameters[pi].Type)); } } writer.Write(") => "); bool returnsVoid = methodSymbol.ReturnType.ToString() == "void"; if (body is BlockSyntax) { writer.Write("\r\n"); writer.WriteOpenBrace(); var statements = body.As <BlockSyntax>().Statements; var lastStatement = statements.LastOrDefault() as ReturnStatementSyntax; var returnStatements = FindReturnStatements(body); if (returnStatements.Count > 0 && (lastStatement == null || returnStatements.Except(lastStatement).Any())) { //Lambda has branching returns. We must use a breakable block since scala can't return from a lambda like C# can TypeState.Instance.InLambdaBreakable++; writer.WriteLine("val __lambdabreak = new Breaks;"); if (!returnsVoid) { writer.WriteIndent(); writer.Write("var __lambdareturn:"); writer.Write(TypeProcessor.ConvertType(methodSymbol.ReturnType)); writer.Write(" = "); writer.Write(TypeProcessor.DefaultValue(methodSymbol.ReturnType)); writer.Write(";\r\n"); } writer.WriteLine("__lambdabreak.breakable"); writer.WriteOpenBrace(); foreach (var statement in statements) { if (statement == lastStatement && !returnsVoid) { //Manually write it so we avoid the final break that WriteReturnStatement does writer.WriteIndent(); writer.Write("__lambdareturn = "); Core.Write(writer, lastStatement.Expression); writer.Write(";\r\n"); } else { Core.Write(writer, statement); } } TriviaProcessor.ProcessTrivias(writer, body.DescendantTrivia()); writer.WriteCloseBrace(); if (!returnsVoid) { writer.WriteLine("__lambdareturn;"); } TypeState.Instance.InLambdaBreakable--; } else { foreach (var statement in statements) { if (statement == lastStatement) { writer.WriteIndent(); Core.Write(writer, lastStatement.Expression); writer.Write(";\r\n"); } else { Core.Write(writer, statement); } } } writer.Indent--; writer.WriteIndent(); writer.Write("}"); } else { writer.Write(" { "); Core.Write(writer, body); writer.Write("; }"); } if (!returnsVoid) { writer.Write(TypeProcessor.ConvertTypeWithColon(methodSymbol.ReturnType)); } }
public static void Go(ScalaWriter writer, ForEachStatementSyntax foreachStatement) { var info = new LoopInfo(foreachStatement); var types = Program.GetModel(foreachStatement).GetTypeInfo(foreachStatement.Expression); var typeStr = TypeProcessor.GenericTypeName(types.Type); if (types.Type is IArrayTypeSymbol) { //It's faster to "while" through arrays than "for" through them writer.WriteOpenBrace(); info.WritePreLoop(writer); writer.WriteLine("var __foreachindex:Int = 0;"); writer.WriteIndent(); writer.Write("val __foreacharray = "); Core.Write(writer, foreachStatement.Expression); writer.Write(";\r\n"); writer.WriteLine("while (__foreachindex < __foreacharray.length)"); writer.WriteOpenBrace(); writer.WriteIndent(); writer.Write("val "); writer.Write(WriteIdentifierName.TransformIdentifier(foreachStatement.Identifier.ValueText)); writer.Write(" = __foreacharray(__foreachindex);\r\n"); info.WriteLoopOpening(writer); Core.WriteStatementAsBlock(writer, foreachStatement.Statement, false); info.WriteLoopClosing(writer); writer.WriteLine("__foreachindex += 1;"); writer.WriteCloseBrace(); info.WritePostLoop(writer); writer.WriteCloseBrace(); } else if (typeStr == "System.Collections.Generic.List<>" //|| typeStr == "System.Collections.Generic.Dictionary<,>" || typeStr == "System.Collections.Generic.Dictionary<,>.KeyCollection" || typeStr == "System.Collections.Generic.Dictionary<,>.ValueCollection") { //It's faster to "while" over a list's iterator than to "for" through it writer.WriteOpenBrace(); info.WritePreLoop(writer); writer.WriteIndent(); writer.Write("val __foreachiterator = "); Core.Write(writer, foreachStatement.Expression); writer.Write(".iterator();\r\n"); writer.WriteLine("while (__foreachiterator.hasNext())"); writer.WriteOpenBrace(); writer.WriteIndent(); writer.Write("val "); writer.Write(WriteIdentifierName.TransformIdentifier(foreachStatement.Identifier.ValueText)); writer.Write(" = __foreachiterator.next();\r\n"); info.WriteLoopOpening(writer); Core.WriteStatementAsBlock(writer, foreachStatement.Statement, false); info.WriteLoopClosing(writer); writer.WriteCloseBrace(); info.WritePostLoop(writer); writer.WriteCloseBrace(); } else { info.WritePreLoop(writer); writer.WriteIndent(); writer.Write("for ("); writer.Write(WriteIdentifierName.TransformIdentifier(foreachStatement.Identifier.ValueText)); writer.Write(" <- "); Core.Write(writer, foreachStatement.Expression); writer.Write(")\r\n"); writer.WriteOpenBrace(); info.WriteLoopOpening(writer); Core.WriteStatementAsBlock(writer, foreachStatement.Statement, false); info.WriteLoopClosing(writer); writer.WriteCloseBrace(); info.WritePostLoop(writer); } }
public static void Go(ScalaWriter 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) { if (memberName == "MaxValue" || memberName == "MinValue" || memberName == "NaN") { var predefined = expression.Expression.ToString(); if (predefined.StartsWith("u")) { //Scala does not have unsigned types. Forward these to CsScala writer.Write("System.CsScala."); writer.Write(predefined); writer.Write(memberName); } else { writer.Write(predefined[0].ToString().ToUpper()); writer.Write(predefined.Substring(1)); writer.Write("."); writer.Write(memberName); } } else { var field = System.Type.GetType(typeStr).GetField(memberName); if (field == null) { throw new Exception("Cannot use " + memberName + " as a field. If you're passing a function, wrap a closure around it. " + Utility.Descriptor(expression)); } var val = field.GetValue(null); if (val is string) { writer.Write("\"" + val + "\""); } else { writer.Write(val.ToString()); } } } else if (type.OriginalDefinition is INamedTypeSymbol && type.OriginalDefinition.As <INamedTypeSymbol>().SpecialType == SpecialType.System_Nullable_T) { switch (memberName) { case "HasValue": writer.Write("("); WriteMember(writer, expression.Expression); writer.Write(" != null)"); break; case "Value": var nullableType = TypeProcessor.ConvertType(type.As <INamedTypeSymbol>().TypeArguments.Single()); WriteMember(writer, expression.Expression); if (TypeProcessor.IsPrimitiveType(nullableType)) { writer.Write("."); writer.Write(nullableType[0].ToString().ToLower()); writer.Write(nullableType.Substring(1)); writer.Write("Value()"); } break; default: throw new Exception("Need handler for Nullable." + memberName + " " + Utility.Descriptor(expression)); } } else { var translate = PropertyTranslation.Get(typeStr, memberName); if (translate != null && translate.ExtensionMethod != null) { writer.Write(translate.ExtensionMethod); writer.Write("("); if (!(model.GetSymbolInfo(expression.Expression).Symbol is INamedTypeSymbol)) { Core.Write(writer, expression.Expression); } writer.Write(")"); return; } if (translate != null) { memberName = translate.ReplaceWith; } else { memberName = WriteIdentifierName.TransformIdentifier(memberName); } 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("]"); } } }
public static void Go(ScalaWriter writer, ObjectCreationExpressionSyntax expression) { var model = Program.GetModel(expression); var type = model.GetTypeInfo(expression).Type; if (expression.Initializer != null) { throw new Exception("Object initializers are not supported " + 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("System.CsScala.NewString("); bool first = true; foreach (var param in expression.ArgumentList.Arguments) { if (first) { first = false; } else { writer.Write(", "); } Core.Write(writer, param.Expression); } writer.Write(")"); } else if (type.OriginalDefinition is INamedTypeSymbol && type.OriginalDefinition.As <INamedTypeSymbol>().SpecialType == SpecialType.System_Nullable_T) { //new'ing up a Nullable<T> has special sematics in C#. If we're calling this with no parameters, just use null. Otherwise just use the parameter. if (expression.ArgumentList.Arguments.Count == 0) { writer.Write("null"); } else { Core.Write(writer, expression.ArgumentList.Arguments.Single().Expression); } } else { var methodSymbol = model.GetSymbolInfo(expression).Symbol.As <IMethodSymbol>(); var translateOpt = MethodTranslation.Get(methodSymbol); if (translateOpt != null && translateOpt.ExtensionNamespace != null) { writer.Write(translateOpt.ExtensionNamespace); writer.Write("."); writer.Write(translateOpt.ReplaceWith); } else { writer.Write("new "); writer.Write(TypeProcessor.ConvertType(expression.Type)); } writer.Write("("); if (expression.ArgumentList != null) { bool first = true; foreach (var param in TranslateParameters(translateOpt, expression.ArgumentList.Arguments, expression)) { if (first) { first = false; } else { writer.Write(", "); } param.Write(writer); } } writer.Write(")"); } }
public static void Go(ScalaWriter writer, TypeOfExpressionSyntax expression) { writer.Write("new System.Type(classOf["); writer.Write(TypeProcessor.ConvertType(expression.Type)); writer.Write("])"); }
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(")"); }
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(); } }
private static void Go(ScalaWriter writer, ExpressionSyntax left, SyntaxToken operatorToken, ExpressionSyntax right) { if (operatorToken.Kind() == SyntaxKind.AsKeyword) { writer.Write("CsScala.As["); writer.Write(TypeProcessor.ConvertType(right)); writer.Write("]("); Core.Write(writer, left); writer.Write(")"); } else if (operatorToken.Kind() == SyntaxKind.IsKeyword) { Core.Write(writer, left); writer.Write(".isInstanceOf["); writer.Write(TypeProcessor.ConvertType(right)); writer.Write("]"); } else if (operatorToken.Kind() == SyntaxKind.QuestionQuestionToken) { writer.Write("CsScala.Coalesce("); Core.Write(writer, left); writer.Write(", "); Core.Write(writer, right); writer.Write(")"); } else { if (left is ElementAccessExpressionSyntax && IsAssignmentToken(operatorToken.Kind())) { var subExpr = left.As <ElementAccessExpressionSyntax>(); var typeStr = TypeProcessor.GenericTypeName(Program.GetModel(left).GetTypeInfo(subExpr.Expression).Type); var trans = ElementAccessTranslation.Get(typeStr); if (trans != null) { Core.Write(writer, subExpr.Expression); writer.Write("."); if (operatorToken.Kind() == SyntaxKind.EqualsToken) { writer.Write(trans.ReplaceAssign); } else { throw new Exception(operatorToken.Kind() + " is not supported on " + typeStr + " " + Utility.Descriptor(left.Parent)); } writer.Write("("); foreach (var arg in subExpr.ArgumentList.Arguments) { Core.Write(writer, arg.Expression); writer.Write(", "); } Core.Write(writer, right); writer.Write(")"); return; } } Action <ExpressionSyntax> write = e => { var model = Program.GetModel(left); var type = model.GetTypeInfo(e); //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()); 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.Name == "Nullable" && type.Type.ContainingNamespace.FullName() == "System" && type.Type.As <INamedTypeSymbol>().TypeArguments.Single().TypeKind == TypeKind.Enum)) { var enumType = type.Type.As <INamedTypeSymbol>().TypeArguments.Single(); writer.Write(enumType.ContainingNamespace.FullNameWithDot()); writer.Write(WriteType.TypeName(enumType.As <INamedTypeSymbol>())); writer.Write(".ToString("); Core.Write(writer, e); writer.Write(")"); } else if (operatorToken.Kind() == SyntaxKind.PlusToken && IsException(type.Type)) //Check for exceptions being converted to strings by string concatenation { writer.Write("System.CsScala.ExceptionToString("); Core.Write(writer, e); writer.Write(")"); } else if (operatorToken.Kind() == SyntaxKind.PlusToken && type.Type.SpecialType == SpecialType.System_Byte && !Utility.IsNumeric(type.ConvertedType)) { //bytes are signed in the JVM, so we need to take care when converting them to strings. Exclude numeric types, since Core.Writer will convert these to ints writer.Write("System.CsScala.ByteToString("); Core.Write(writer, e); writer.Write(")"); } else if (operatorToken.Kind() == SyntaxKind.PlusToken && !(e is BinaryExpressionSyntax) && type.Type.SpecialType == SpecialType.System_String && CouldBeNullString(model, e)) { //In .net, concatenating a null string does not alter the output. However, in the JVM, it produces the "null" string. To counter this, we must check non-const strings. writer.Write("System.CsScala.NullCheck("); Core.Write(writer, e); writer.Write(")"); } else if (operatorToken.Kind() == SyntaxKind.PlusToken && !(e is BinaryExpressionSyntax) && type.Type is INamedTypeSymbol && type.Type.As <INamedTypeSymbol>().ConstructedFrom.SpecialType == SpecialType.System_Nullable_T) { //Concatening a nullable type in .net just produces an empty string if it's null. In scala it produces "null" or a null reference exception -- we want neither. writer.Write("System.CsScala.NullCheck("); Core.Write(writer, e); writer.Write(")"); } else if (operatorToken.Kind() == SyntaxKind.PlusToken && !(e is BinaryExpressionSyntax) && type.Type.SpecialType == SpecialType.System_Boolean) { writer.Write("System.CsScala.BooleanToString("); Core.Write(writer, e); writer.Write(")"); } else { Core.Write(writer, e); } }; write(left); writer.Write(" "); writer.Write(operatorToken.ToString()); writer.Write(" "); write(right); } }
public static bool IsConst(SyntaxTokenList modifiers, EqualsValueClauseSyntax initializerOpt, TypeSyntax type) { var t = TypeProcessor.ConvertType(type); return(modifiers.Any(SyntaxKind.ConstKeyword)); }
public static void Go() { var partials = TypeState.Instance.Partials; var first = partials.First(); using (var writer = new ScalaWriter(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; var package = first.Symbol.ContainingNamespace.FullName(); if (package.Length > 0) { writer.WriteLine("package " + package + @";"); } WriteImports.Go(writer); if (first.Syntax is EnumDeclarationSyntax) { WriteEnum.Go(writer, TypeState.Instance.Partials.Select(o => o.Syntax).Cast <EnumDeclarationSyntax>().SelectMany(o => o.Members).Where(o => !Program.DoNotWrite.ContainsKey(o))); return; } TypeState.Instance.AllMembers = partials.Select(o => o.Syntax).Cast <TypeDeclarationSyntax>().SelectMany(o => o.Members).Where(o => !Program.DoNotWrite.ContainsKey(o)).ToList(); var allMembersToWrite = TypeState.Instance.AllMembers .Where(member => !(member is TypeDeclarationSyntax) && !(member is EnumDeclarationSyntax) && !(member is DelegateDeclarationSyntax)) .ToList(); var instanceCtors = TypeState.Instance.AllMembers.OfType <ConstructorDeclarationSyntax>() .Where(o => !o.Modifiers.Any(SyntaxKind.StaticKeyword)) .ToList(); 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)); } var ctorOpt = instanceCtors.SingleOrDefault(); foreach (var staticMembers in new[] { true, false }) { var membersToWrite = allMembersToWrite.Where(o => IsStatic(o) == staticMembers).ToList(); if (membersToWrite.Count == 0 && (staticMembers || partials.Any(o => o.Syntax.Modifiers.Any(SyntaxKind.StaticKeyword)))) { continue; } if (staticMembers) { writer.Write("object "); } else if (first.Syntax.Kind() == SyntaxKind.InterfaceDeclaration) { writer.Write("trait "); } else { if (partials.Any(o => o.Syntax.Modifiers.Any(SyntaxKind.AbstractKeyword))) { writer.Write("abstract "); } writer.Write("class "); } writer.Write(TypeState.Instance.TypeName); if (!staticMembers && 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 => TypeParameter(o)))); writer.Write("]"); } //Write constructor arguments if (ctorOpt != null && ctorOpt.ParameterList.Parameters.Count > 0) { writer.Write("("); var firstParameter = true; foreach (var parameter in ctorOpt.ParameterList.Parameters) { if (firstParameter) { firstParameter = false; } else { writer.Write(", "); } writer.Write(WriteIdentifierName.TransformIdentifier(parameter.Identifier.ValueText)); writer.Write(TypeProcessor.ConvertTypeWithColon(parameter.Type)); if (parameter.Default != null) { writer.Write(" = "); Core.Write(writer, parameter.Default.Value); } } writer.Write(")"); } bool firstBase = true; foreach (var baseType in bases.OrderBy(o => o.TypeKind == TypeKind.Interface ? 1 : 0)) { if (firstBase) { writer.Write(" extends "); } else { writer.Write(" with "); } writer.Write(TypeProcessor.ConvertType(baseType)); if (firstBase && ctorOpt != null && ctorOpt.Initializer != null && ctorOpt.Initializer.ArgumentList.Arguments.Count > 0) { writer.Write("("); bool firstArg = true; foreach (var init in ctorOpt.Initializer.ArgumentList.Arguments) { if (firstArg) { firstArg = false; } else { writer.Write(", "); } Core.Write(writer, init.Expression); } writer.Write(")"); } firstBase = false; } } writer.Write("\r\n"); writer.WriteOpenBrace(); var fields = membersToWrite.OfType <FieldDeclarationSyntax>().ToList(); var nonFields = membersToWrite.Except(fields); fields = SortFields(fields); foreach (var member in fields) { Core.Write(writer, member); } foreach (var member in nonFields) { Core.Write(writer, member); } if (!staticMembers && ctorOpt != null && ctorOpt.Body != null && ctorOpt.Body.As <BlockSyntax>().Statements.Count > 0) { writer.WriteLine(); Core.WriteBlock(writer, ctorOpt.Body.As <BlockSyntax>(), true); //render braces so local ctor variables don't bleed out into fields } writer.WriteCloseBrace(); } } }