diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs index ddce2aa..9b39f20 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs @@ -209,7 +209,7 @@ namespace Twiglet.CS2J.Translator foreach (string r in csDir) doFile(r, ".cs", translateFile, cfg.Exclude); // translate it - if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out collected partial types"); + if (cfg.DebugLevel >= 1 && partialTypes.Count > 0) Console.Out.WriteLine("Writing out collected partial types"); foreach (KeyValuePair entry in partialTypes) emitPartialType(entry.Key, entry.Value); @@ -537,8 +537,8 @@ namespace Twiglet.CS2J.Translator outputMaker.Cfg = cfg; outputMaker.EmittedCommentTokenIdx = saveEmittedCommentTokenIdx; - outputMaker.IsPartial = javaMaker.CUMap[typeName].IsPartial; - if (outputMaker.IsPartial) + bool isPartial = javaMaker.CUMap[typeName].IsPartial; + if (isPartial) { if (!partialTypes.ContainsKey(typeName)) { @@ -550,7 +550,7 @@ namespace Twiglet.CS2J.Translator outputMaker.IsLast = i == (javaMaker.CUKeys.Count - 1); - if (!outputMaker.IsPartial) + if (!isPartial) { if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", javaFName); StreamWriter javaW = new StreamWriter(javaFName); @@ -574,25 +574,17 @@ namespace Twiglet.CS2J.Translator public static void emitPartialType(string name, ClassDescriptorSerialized serTy) { - - // Pretty print as text - Dictionary args = new Dictionary(); - args["now"] = DateTime.Now; - args["includeDate"] = cfg.TranslatorAddTimeStamp; - args["packageName"] = serTy.Package; - args["imports"] = serTy.Imports; - args["modifiers"] = serTy.Mods; - args["name"] = serTy.Identifier; - args["extends"] = serTy.ClassBase; - args["imps"] = serTy.ClassImplements; - args["body"] = serTy.ClassBody; + JavaPrettyPrint outputMaker = new JavaPrettyPrint(null); + outputMaker.Filename = serTy.FileName; + outputMaker.TraceDestination = Console.Error; + outputMaker.TemplateLib = templates; + outputMaker.Cfg = cfg; - StringTemplate st = templates.GetInstanceOf("partial_type", args); + StringTemplate pkgST = outputMaker.emitPackage(serTy); -// new STAttrMap().Add("now", DateTime.Now).Add("includeDate", Cfg.TranslatorAddTimeStamp).Add("packageName", (((nm != null) ? nm.Text : null) != null && ((nm != null) ? nm.Text : null).Length > 0 ? ((nm != null) ? nm.Text : null) : null)).Add("imports", ((imports1 != null) ? imports1.ST : null)).Add("type", ((type_declaration2 != null) ? type_declaration2.ST : null)).Add("endComments", CollectedComments )); if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", serTy.FileName); StreamWriter javaW = new StreamWriter(serTy.FileName); - javaW.Write(limit(st.ToString())); + javaW.Write(limit(pkgST.ToString())); javaW.Close(); } } diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs index 3c8f1f9..ac33952 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs @@ -46,37 +46,16 @@ import_list(nss) ::= << import_template(ns) ::= ""import ;"" -// ****** output partial type ****** -partial_type(now, includeDate, packageName, imports, modifiers, comments, attributes, name, typeparams, extends, imps, body) ::= << - -package ; - - - - -class implements -{ - -} - ->> - // ******* CLASSES *********** -class(modifiers, comments, attributes, name, typeparams, extends, imps, body) ::= << +class(modifiers, comments, attributes, type, name, typeparams, extends, imps, body, partial_types, end_comments) ::= << -class -{ - -} ->> - -iface(modifiers, comments, attributes, name, typeparams, imps, body) ::= << - -interface +class { + } + >> class_body(entries) ::= << @@ -89,7 +68,7 @@ class_member(comments, member) ::= << >> constructor(modifiers, name, params, exceptions, body, bodyIsSemi) ::= << -() throws ; +() throws ; @@ -97,7 +76,7 @@ constructor(modifiers, name, params, exceptions, body, bodyIsSemi) ::= << >> static_constructor(modifiers, body, bodyIsSemi) ::= << -; +; @@ -105,14 +84,14 @@ static_constructor(modifiers, body, bodyIsSemi) ::= << >> method(modifiers, typeparams, type, name, params, exceptions, body, bodyIsSemi) ::= << - () throws ; + () throws ; <\n> >> -field(modifiers, type, field, comments, init) ::= "" ;"" +field(modifiers, type, field, comments, init) ::= "" ;"" variable_declarators(varinits) ::= """" variable_declarator(typename,init) ::= "" = "" @@ -122,7 +101,7 @@ primary_expression_start_parts(start,follows) ::= """" type_param_constraint(param, constraints) ::= "" extends "" fixed_parameter(mod,type,name,def) ::= << - = + = >> varargs(type,name) ::= << @@ -141,7 +120,7 @@ statement(statement) ::= << annotation(modifiers, comments, attributes, name, body) ::= << -@interface +@interface { } @@ -159,7 +138,7 @@ throw(exp) ::= ""throw ;"" enum(modifiers,comments, attributes, name, body) ::= << -enum +enum { } @@ -175,7 +154,9 @@ enum_member(comments, value) ::= << type(name, rs, stars, opt) ::= """" namespace_or_type(type1, type2, types) ::= ""::."" -modifiers(mods) ::= "" "" +modifiers(mods) ::= << + +>> type_parameter_list(items) ::= << \<\> diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/CommonWalker.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/CommonWalker.cs index 2015e43..a2f2cf6 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/CommonWalker.cs +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/CommonWalker.cs @@ -258,45 +258,24 @@ namespace Twiglet.CS2J.Translator.Transform public bool IsPartial {get; set;} } - public class ClassDescriptor { - public IToken Token { get;set; } - public String Comments { get;set; } - public CommonTree Atts { get;set; } - public CommonTree Mods { get;set; } - public CommonTree Identifier { get;set; } - public CommonTree TypeParameterList { get;set; } - public CommonTree ClassBase { get;set; } - public CommonTree TypeParameterConstraintsClauses { get;set; } - public CommonTree ClassBody { get;set; } - public Dictionary PartialTypes { get;set; } - - public ClassDescriptor(IToken inToken, String inComments, CommonTree inAtts, CommonTree inMods, CommonTree inIdentifier, CommonTree inTypeParameterList, CommonTree inClassBase, CommonTree inTypeParameterConstraintsClauses, CommonTree inClassBody, Dictionary inPartialTypes) { - Token = inToken; - Comments = inComments; - Atts = inAtts; - Mods = inMods; - Identifier = inIdentifier; - TypeParameterList = inTypeParameterList; - ClassBase = inClassBase; - TypeParameterConstraintsClauses = inTypeParameterConstraintsClauses; - ClassBody = inClassBody; - PartialTypes = inPartialTypes; - } - } - + // This structure holds (serialized) consolidated strings describing + // partial classes and interfaces public class ClassDescriptorSerialized { public String FileName { get;set; } public List Imports { get;set; } public String Package { get;set; } + public String Type { get;set; } public String Comments { get;set; } public String Atts { get;set; } public List Mods { get;set; } public String Identifier { get;set; } public String TypeParameterList { get;set; } - public String ClassBase { get;set; } + public List ClassExtends { get;set; } // Can have multiple extends in an interface public List ClassImplements { get;set; } - public String TypeParameterConstraintsClauses { get;set; } public String ClassBody { get;set; } + public String EndComments { get;set; } + + public Dictionary PartialTypes { get;set; } public ClassDescriptorSerialized(string name) { @@ -304,14 +283,16 @@ namespace Twiglet.CS2J.Translator.Transform Comments = ""; Imports = new List(); Package = ""; + Type = "class"; Atts = ""; Mods = new List(); Identifier = name; TypeParameterList = ""; - ClassBase = ""; + ClassExtends = new List(); ClassImplements = new List(); - TypeParameterConstraintsClauses = ""; ClassBody = ""; + EndComments = ""; + PartialTypes = new Dictionary(); } } diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g index b49aa3a..0750809 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g @@ -33,7 +33,6 @@ scope NSContext { // A scope to keep track of the current type context scope TypeContext { string typeName; - Dictionary partialTypes; } @namespace { Twiglet.CS2J.Translator.Transform } @@ -56,10 +55,6 @@ scope TypeContext { public IDictionary CUMap { get; set; } public IList CUKeys { get; set; } - // we keep track of the end position of the previous class / struct member - // so that we can collect comments for a partial type definition - private int prevMemberEndTokenIndex = -1; - protected string snaffleComments(int startIndex, int endIndex) { StringBuilder ret = new StringBuilder(); List toks = ((CommonTokenStream)this.GetTreeNodeStream().TokenStream).GetTokens(startIndex,endIndex); @@ -507,56 +502,56 @@ scope TypeContext { } // Merges part into combined - protected void mergePartialTypes(ClassDescriptor combined, ClassDescriptor part) { - - // append comments - combined.Comments += part.Comments; - - // union all attributes - CommonTree attRoot = (CommonTree)adaptor.Nil; - adaptor.AddChild(attRoot, combined.Atts); - adaptor.AddChild(attRoot, part.Atts); - combined.Atts = (CommonTree)adaptor.RulePostProcessing(attRoot); - - // merge all modifiers - combined.Mods = mergeModifiers(combined.Mods, part.Mods); - - // type parameter list must be the same on all parts - - // all parts that have a TypeParameterConstraintsClauses must agree - if (combined.TypeParameterConstraintsClauses == null) - combined.TypeParameterConstraintsClauses = part.TypeParameterConstraintsClauses; - - // merge all base classes, interfaces - combined.ClassBase = mergeModifiers(combined.ClassBase, part.ClassBase); - - // union all class_body - CommonTree bodyRoot = (CommonTree)adaptor.Nil; - adaptor.AddChild(bodyRoot, combined.ClassBody); - adaptor.AddChild(bodyRoot, part.ClassBody); - combined.ClassBody = (CommonTree)adaptor.RulePostProcessing(bodyRoot); - - // merge partial sub-types - foreach (string key in combined.PartialTypes.Keys) { - if (part.PartialTypes.ContainsKey(key)) { - mergePartialTypes(combined.PartialTypes[key], part.PartialTypes[key]); - } - } - // Add types in part but not combined - foreach (string key in part.PartialTypes.Keys) { - if (!combined.PartialTypes.ContainsKey(key)) { - combined.PartialTypes[key] = part.PartialTypes[key]; - } - } - } - - protected CommonTree emitPartialTypes(Dictionary partialTypes) { - CommonTree root = (CommonTree)adaptor.Nil; - foreach (ClassDescriptor part in partialTypes.Values) { - root.AddChild((CommonTree)magicClassFromDescriptor(part.Token, part).Tree); - } - return (CommonTree)adaptor.RulePostProcessing(root); - } +// protected void mergePartialTypes(ClassDescriptor combined, ClassDescriptor part) { +// +// // append comments +// combined.Comments += part.Comments; +// +// // union all attributes +// CommonTree attRoot = (CommonTree)adaptor.Nil; +// adaptor.AddChild(attRoot, combined.Atts); +// adaptor.AddChild(attRoot, part.Atts); +// combined.Atts = (CommonTree)adaptor.RulePostProcessing(attRoot); +// +// // merge all modifiers +// combined.Mods = mergeModifiers(combined.Mods, part.Mods); +// +// // type parameter list must be the same on all parts +// +// // all parts that have a TypeParameterConstraintsClauses must agree +// if (combined.TypeParameterConstraintsClauses == null) +// combined.TypeParameterConstraintsClauses = part.TypeParameterConstraintsClauses; +// +// // merge all base classes, interfaces +// combined.ClassBase = mergeModifiers(combined.ClassBase, part.ClassBase); +// +// // union all class_body +// CommonTree bodyRoot = (CommonTree)adaptor.Nil; +// adaptor.AddChild(bodyRoot, combined.ClassBody); +// adaptor.AddChild(bodyRoot, part.ClassBody); +// combined.ClassBody = (CommonTree)adaptor.RulePostProcessing(bodyRoot); +// +// // merge partial sub-types +// foreach (string key in combined.PartialTypes.Keys) { +// if (part.PartialTypes.ContainsKey(key)) { +// mergePartialTypes(combined.PartialTypes[key], part.PartialTypes[key]); +// } +// } +// // Add types in part but not combined +// foreach (string key in part.PartialTypes.Keys) { +// if (!combined.PartialTypes.ContainsKey(key)) { +// combined.PartialTypes[key] = part.PartialTypes[key]; +// } +// } +// } + +// protected CommonTree emitPartialTypes(Dictionary partialTypes) { +// CommonTree root = (CommonTree)adaptor.Nil; +// foreach (ClassDescriptor part in partialTypes.Values) { +// root.AddChild((CommonTree)magicClassFromDescriptor(part.Token, part).Tree); +// } +// return (CommonTree)adaptor.RulePostProcessing(root); +// } protected void mergeCompUnits(CUnit cu, List searchPath, List aliasKeys, List aliasNamespaces) { foreach (string s in searchPath) { @@ -590,7 +585,6 @@ scope NSContext, TypeContext; $NSContext::aliasNamespaces = new List(); $TypeContext::typeName = null; - $TypeContext::partialTypes = new Dictionary(); } : namespace_body; @@ -636,7 +630,6 @@ scope TypeContext; bool isCompUnit = false; CommonTree atts = null; CommonTree mods = null; - $TypeContext::partialTypes = new Dictionary(); } @after { if (isCompUnit) { @@ -647,21 +640,11 @@ scope TypeContext; Warning(treeEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + fqn); } else { - CUMap.Add(fqn, new CUnit(mkPackage(treeEntry.Value.Token, treeEntry.Value, ns),CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces)); + CUMap.Add(fqn, new CUnit(mkPackage(treeEntry.Value.Token, treeEntry.Value, ns),CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces, $ty.isPartial)); CUKeys.Add(fqn); } } } - foreach (KeyValuePair partialEntry in $TypeContext::partialTypes) { - string fqn = ns+(String.IsNullOrEmpty(ns) ? "" : ".")+partialEntry.Key; - if (CUKeys.Contains(fqn)) { - Warning(partialEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + fqn); - } - else { - CUMap.Add(fqn, new CUnit(mkPackage(partialEntry.Value.Token, (CommonTree)magicClassFromDescriptor(partialEntry.Value.Token, partialEntry.Value).Tree, ns), CollectSearchPath, CollectAliasKeys, CollectAliasNamespaces, true)); - CUKeys.Add(fqn); - } - } } }: namespace_declaration @@ -669,17 +652,19 @@ scope TypeContext; ; // type_declaration is only called at the top level, so each of the types declared // here will become a Java compilation unit (and go to its own file) -type_declaration[CommonTree atts, CommonTree mods] returns [Dictionary compUnits] +type_declaration[CommonTree atts, CommonTree mods] returns [Dictionary compUnits, bool isPartial] @init { $compUnits = new Dictionary(); + $isPartial = false; } : - ('partial') => p='partial'! (pc=class_declaration[$atts, $mods, true /* toplevel */, true /* isPartial */] - | ps=struct_declaration[$atts, $mods, true /* toplevel */, true /* isPartial */] - | pi=interface_declaration[$atts, $mods] { $compUnits.Add($pi.name, $pi.tree); } ) - | c=class_declaration[$atts, $mods, true /* toplevel */, false /* isPartial */] { $compUnits.Add($c.name, $c.tree); } - | s=struct_declaration[$atts, $mods, true /* toplevel */, false /* isPartial */] { $compUnits.Add($s.name, $s.tree); } - | i=interface_declaration[$atts, $mods] { $compUnits.Add($i.name, $i.tree); } + ('partial') => p='partial' { $isPartial = true; } + (pc=class_declaration[$atts, $mods, $p, true /* toplevel */] { $compUnits.Add($pc.name, $pc.tree); } + | ps=struct_declaration[$atts, $mods, $p, true /* toplevel */] { $compUnits.Add($ps.name, $ps.tree); } + | pi=interface_declaration[$atts, $mods, $p] { $compUnits.Add($pi.name, $pi.tree); } ) + | c=class_declaration[$atts, $mods, null, true /* toplevel */] { $compUnits.Add($c.name, $c.tree); } + | s=struct_declaration[$atts, $mods, null, true /* toplevel */] { $compUnits.Add($s.name, $s.tree); } + | i=interface_declaration[$atts, $mods, null] { $compUnits.Add($i.name, $i.tree); } | e=enum_declaration[$atts, $mods] { $compUnits.Add($e.name, $e.tree); } | d=delegate_declaration[$atts, $mods, true /* toplevel */] { $compUnits = $d.compUnits; } ; @@ -698,22 +683,17 @@ modifier: 'new' -> /* No new in Java*/ | 'public' | 'protected' | 'private' | 'internal' -> /* translate to package-private */| 'unsafe' -> | 'abstract' | 'sealed' -> FINAL["final"] | 'static' | 'readonly' -> /* no equivalent in C# (this is like a const that can be initialized separately in the constructor) */ | 'volatile' | e='extern' { Warning($e.line, "[UNSUPPORTED] 'extern' modifier"); } | 'virtual' -> | 'override' -> /* not in Java, maybe convert to override annotation */; -class_member_declaration -@after { - this.prevMemberEndTokenIndex = adaptor.GetTokenStopIndex($class_member_declaration.tree); -}: +class_member_declaration: a=attributes? m=modifiers? ( c='const' ct=type constant_declarators ';' -> ^(FIELD[$c.token, "FIELD"] $a? $m? { addConstModifiers($c.token, $m.modList) } $ct constant_declarators) | ev=event_declaration[$a.tree, $m.tree] -> $ev | p='partial' (v1=void_type m3=method_declaration[$a.tree, $m.tree, $m.modList, $v1.tree, $v1.text, true /* isPartial */] -> { $m3.tree != null}? $m3 -> - | pi=interface_declaration[$a.tree, $m.tree] -> $pi - | pc=class_declaration[$a.tree, $m.tree, false /* toplevel */, true /* isPartial */] -> { $pc.tree != null}? $pc - -> - | ps=struct_declaration[$a.tree, $m.tree, false /* toplevel */, true /* isPartial */] -> { ps.tree != null}? $ps - -> ) - | i=interface_declaration[$a.tree, $m.tree] -> $i + | pi=interface_declaration[$a.tree, $m.tree, $p] -> $pi + | pc=class_declaration[$a.tree, $m.tree, $p, false /* toplevel */] -> $pc + | ps=struct_declaration[$a.tree, $m.tree, $p, false /* toplevel */] -> $ps) + | i=interface_declaration[$a.tree, $m.tree, null] -> $i | v2=void_type m1=method_declaration[$a.tree, $m.tree, $m.modList, $v2.tree, $v2.text, false /* isPartial */] -> $m1 | t=type ( (member_name type_parameter_list? '(') => m2=method_declaration[$a.tree, $m.tree, $m.modList, $t.tree, $t.text, false /* isPartial */] -> $m2 | (member_name '{') => pd=property_declaration[$a.tree, $m.tree, $t.tree] -> $pd @@ -724,8 +704,8 @@ class_member_declaration ) // common_modifiers// (method_modifiers | field_modifiers) - | cd=class_declaration[$a.tree, $m.tree, false /* toplevel */, false /* isPartial */] -> $cd - | sd=struct_declaration[$a.tree, $m.tree, false /* toplevel */, false /* isPartial */] -> $sd + | cd=class_declaration[$a.tree, $m.tree, null, false /* toplevel */] -> $cd + | sd=struct_declaration[$a.tree, $m.tree, null, false /* toplevel */] -> $sd | ed=enum_declaration[$a.tree, $m.tree] -> $ed | dd=delegate_declaration[$a.tree, $m.tree, false /* toplevel */] -> { mkFlattenDictionary($dd.tree.Token,$dd.compUnits) } | co3=conversion_operator_declaration -> ^(CONVERSION_OPERATOR[$co3.start.Token, "CONVERSION"] $a? $m? $co3) @@ -1258,42 +1238,11 @@ attribute_argument_expression: // Class Section /////////////////////////////////////////////////////// -class_declaration[CommonTree atts, CommonTree mods, bool toplevel, bool isPartial] returns [string name] +class_declaration[CommonTree atts, CommonTree mods, CommonTree partial, bool toplevel] returns [string name] scope TypeContext; -@init{ - $TypeContext::partialTypes = new Dictionary(); - int prevMemberEndIndex = this.prevMemberEndTokenIndex; - IToken endToken = null; -} : - c='class' identifier { $TypeContext::typeName = $identifier.thetext; } type_parameter_list? { $name = mkGenericTypeAlias($identifier.thetext, $type_parameter_list.names); } class_base? type_parameter_constraints_clauses? class_body[$isPartial] { endToken = $class_body.endToken; } (s=';' { endToken = $s.token; })? - { - if ($isPartial) { - - // Strip off braces - CommonTree newClassBody = dupTree($class_body.tree); - int bodyChildren = adaptor.GetChildCount(newClassBody); - if (bodyChildren >= 2 && ((CommonTree)adaptor.GetChild(newClassBody, 0)).Type == OPEN_BRACE && ((CommonTree)adaptor.GetChild(newClassBody, bodyChildren - 1)).Type == CLOSE_BRACE) { - adaptor.DeleteChild(newClassBody, bodyChildren - 1); - adaptor.DeleteChild(newClassBody, 0); - newClassBody = (CommonTree)adaptor.RulePostProcessing(newClassBody); - } - if (!toplevel) { - $mods = addModifier($mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")); - } - ClassDescriptor klass = new ClassDescriptor($c.token, snaffleComments(prevMemberEndIndex, $c.token.TokenIndex), $atts, $mods, $identifier.tree, $type_parameter_list.tree, $class_base.tree, $type_parameter_constraints_clauses.tree, newClassBody, $TypeContext::partialTypes); - // add to parent's context - Dictionary parentPartialTypes = ((TypeContext_scope)$TypeContext.ToArray()[1]).partialTypes; - if (parentPartialTypes.ContainsKey($identifier.thetext)) { - mergePartialTypes(parentPartialTypes[$identifier.thetext], klass); - } - else { - parentPartialTypes[$identifier.thetext] = klass; - } - } - } - -> {$isPartial}? - -> ^(CLASS[$c.Token] { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")) } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? class_body ); + c='class' identifier { $TypeContext::typeName = $identifier.thetext; } type_parameter_list? { $name = mkGenericTypeAlias($identifier.thetext, $type_parameter_list.names); } class_base? type_parameter_constraints_clauses? class_body ';'? + -> ^(CLASS[$c.token, "class"] { dupTree($partial) } { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")) } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? class_body ); type_parameter_list returns [List names] @init { @@ -1311,10 +1260,8 @@ class_base: //interface_type_list: // ts+=type (',' ts+=type)* -> $ts+; -class_body[bool isPartial] returns [IToken endToken]: - '{' class_member_declarations? e='}' { $endToken = $e.token; } - -> {!$isPartial}? '{' class_member_declarations? { emitPartialTypes($TypeContext::partialTypes) } '}' - -> '{' class_member_declarations? '}' ; +class_body: + '{' class_member_declarations? '}' ; class_member_declarations: class_member_declaration+ ; @@ -1664,12 +1611,12 @@ parameter_array: ; /////////////////////////////////////////////////////// -interface_declaration[CommonTree atts, CommonTree mods] returns [string name] +interface_declaration[CommonTree atts, CommonTree mods, CommonTree partial] returns [string name] scope TypeContext; : c='interface' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } variant_generic_parameter_list? interface_base? type_parameter_constraints_clauses? interface_body ';'? - -> ^(INTERFACE[$c.Token, "interface"] { dupTree($atts) } { dupTree($mods) } identifier type_parameter_constraints_clauses? variant_generic_parameter_list? interface_base? interface_body ); + -> ^(INTERFACE[$c.token, "interface"] { dupTree($partial) } { dupTree($atts) } { dupTree($mods) } identifier type_parameter_constraints_clauses? variant_generic_parameter_list? interface_base? interface_body ); interface_base: c=':' ts+=type (',' ts+=type)* -> ^(EXTENDS[$c.token,"extends"] $ts)*; @@ -1713,47 +1660,14 @@ interface_accessor_declaration [CommonTree atts, CommonTree mods, CommonTree typ ; /////////////////////////////////////////////////////// -struct_declaration[CommonTree atts, CommonTree mods, bool toplevel, bool isPartial] returns [string name] +struct_declaration[CommonTree atts, CommonTree mods, CommonTree partial, bool toplevel] returns [string name] scope TypeContext; -@init { - $TypeContext::partialTypes = new Dictionary(); - IToken endToken = null; -} : - c='struct' identifier { $TypeContext::typeName = $identifier.thetext; } type_parameter_list? { $name = mkGenericTypeAlias($identifier.thetext, $type_parameter_list.names); } class_base? type_parameter_constraints_clauses? struct_body[$isPartial, $identifier.thetext] { endToken = $struct_body.endToken; } (s=';' { endToken = $s.token; })? - { - if ($isPartial) { + c='struct' identifier { $TypeContext::typeName = $identifier.thetext; } type_parameter_list? { $name = mkGenericTypeAlias($identifier.thetext, $type_parameter_list.names); } class_base? type_parameter_constraints_clauses? struct_body[$identifier.thetext] ';'? + -> ^(CLASS[$c.token, "class"] { dupTree($partial) } { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")) } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? struct_body ); - // Strip off braces - CommonTree newClassBody = dupTree($struct_body.tree); - int bodyChildren = adaptor.GetChildCount(newClassBody); - if (bodyChildren >= 2 && ((CommonTree)adaptor.GetChild(newClassBody, 0)).Type == OPEN_BRACE && ((CommonTree)adaptor.GetChild(newClassBody, bodyChildren - 1)).Type == CLOSE_BRACE) { - adaptor.DeleteChild(newClassBody, bodyChildren - 1); - adaptor.DeleteChild(newClassBody, 0); - newClassBody = (CommonTree)adaptor.RulePostProcessing(newClassBody); - } - if (!toplevel) { - $mods = addModifier($mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")); - } - - ClassDescriptor klass = new ClassDescriptor($c.token, snaffleComments(this.prevMemberEndTokenIndex, $c.token.TokenIndex), $atts, $mods, $identifier.tree, $type_parameter_list.tree, $class_base.tree, $type_parameter_constraints_clauses.tree, newClassBody, $TypeContext::partialTypes); - - // add to parent's context - Dictionary parentPartialTypes = ((TypeContext_scope)$TypeContext.ToArray()[1]).partialTypes; - if (!parentPartialTypes.ContainsKey($identifier.thetext)) { - mergePartialTypes(parentPartialTypes[$identifier.thetext], klass); - } - else { - parentPartialTypes[$identifier.thetext] = klass; - } - } - } - -> {$isPartial}? - -> ^(CLASS[$c.Token, "class"] { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")) } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? struct_body ); - -struct_body [bool isPartial, string structName] returns [IToken endToken]: - o='{' magicDefaultConstructor[$o.token, structName] class_member_declarations? e='}' { $endToken = $e.token; } - -> {$isPartial}? '{' magicDefaultConstructor class_member_declarations? { emitPartialTypes($TypeContext::partialTypes) } '}' +struct_body [string structName]: + o='{' magicDefaultConstructor[$o.token, structName] class_member_declarations? e='}' -> '{' magicDefaultConstructor class_member_declarations? '}' ; @@ -2352,5 +2266,5 @@ magicMultiDelClass[IToken tok, CommonTree atts, CommonTree mods, string classNam OPEN_BRACE[tok, "{"] {dupTree(invokeMethod)} { dupTree(members) } CLOSE_BRACE[tok, "}"]) ; -magicClassFromDescriptor[IToken tok, ClassDescriptor klass]: --> ^(CLASS[tok] PAYLOAD[tok, klass.Comments] { dupTree(klass.Atts) } { dupTree(klass.Mods) } { dupTree(klass.Identifier) } { dupTree(klass.TypeParameterConstraintsClauses) } { dupTree(klass.TypeParameterList) } { dupTree(klass.ClassBase) } OPEN_BRACE[tok, "{"] { dupTree(klass.ClassBody) } { emitPartialTypes(klass.PartialTypes) } CLOSE_BRACE[tok, "}"] ); +//magicClassFromDescriptor[IToken tok, ClassDescriptor klass]: +//-> ^(CLASS[tok] PAYLOAD[tok, klass.Comments] { dupTree(klass.Atts) } { dupTree(klass.Mods) } { dupTree(klass.Identifier) } { dupTree(klass.TypeParameterConstraintsClauses) } { dupTree(klass.TypeParameterList) } { dupTree(klass.ClassBase) } OPEN_BRACE[tok, "{"] { dupTree(klass.ClassBody) } { emitPartialTypes(klass.PartialTypes) } CLOSE_BRACE[tok, "}"] ); diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g index 4fcaffd..3fbef49 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g @@ -12,6 +12,11 @@ options { output=template; } +// We don't emit partial types as soon as we generate them, we merge them unti we know we hve seen all parts +scope TypeContext { + Dictionary partialTypes; +} + @namespace { Twiglet.CS2J.Translator.Transform } @header @@ -25,9 +30,9 @@ options { @members { - public bool IsPartial { get; set; } public bool IsLast { get; set; } public int EmittedCommentTokenIdx { get; set; } + // If top level is partial then this will contain the components so that we can mere with other parts down the line public ClassDescriptorSerialized PartialDescriptor { get; set; } private List collectedComments = null; @@ -293,20 +298,139 @@ options { protected string mkString(object s) { return (s == null ? String.Empty : s.ToString()); } + + protected void mergeParts(ClassDescriptorSerialized master, ClassDescriptorSerialized part) { + // Merge into existing descriptor + if (!String.IsNullOrEmpty(part.Comments)) { + master.Comments += "\n" + part.Comments; + } + if (!String.IsNullOrEmpty(part.EndComments)) { + master.EndComments += "\n" + part.EndComments; + } + + // So that we can set "class" as default an doverride it when we see its an interface + master.Type = part.Type; + + // Union all attributes + // we don't push through attributes yet + master.Atts += part.Atts; + + // Merge modifiers + foreach (string m in part.Mods) { + if (!master.Mods.Contains(m)) { + master.Mods.Add(m); + } + } + + if (String.IsNullOrEmpty(master.TypeParameterList)) { + master.TypeParameterList = part.TypeParameterList; + } + + foreach (string m in part.ClassExtends) { + if (!master.ClassExtends.Contains(m)) { + master.ClassExtends.Add(m); + } + } + + foreach (string m in part.ClassImplements) { + if (!master.ClassImplements.Contains(m)) { + master.ClassImplements.Add(m); + } + } + + // Union the class bodies + if (!String.IsNullOrEmpty(part.ClassBody)) { + master.ClassBody += "\n" + part.ClassBody; + } + + foreach (KeyValuePair d in part.PartialTypes) { + if (master.PartialTypes.ContainsKey(d.Key)) { + mergeParts(master.PartialTypes[d.Key], part.PartialTypes[d.Key]); + } + else { + master.PartialTypes[d.Key] = part.PartialTypes[d.Key]; + } + } + + } + + public StringTemplate emitPackage(ClassDescriptorSerialized part) + { + + // Pretty print as text + StringTemplate pkgST = %package(); + %{pkgST}.now = DateTime.Now; + %{pkgST}.includeDate = Cfg.TranslatorAddTimeStamp; + %{pkgST}.packageName = part.Package; + StringTemplate impST = %import_list(); + %{impST}.nss = part.Imports; + %{pkgST}.imports = impST; + %{pkgST}.type = emitPartialType(part); + %{pkgST}.endComments = part.EndComments; + + return pkgST; + } + + public StringTemplate emitPartialType(ClassDescriptorSerialized part) + { + + // Pretty print as text + StringTemplate modST = %modifiers(); + %{modST}.mods = part.Mods; + StringTemplate serTy = %class(); + %{serTy}.comments = part.Comments; + %{serTy}.modifiers = modST; + %{serTy}.type = part.Type; + %{serTy}.name = part.Identifier; + %{serTy}.typeparams = part.TypeParameterList; + StringTemplate extTy = %extends(); + %{extTy}.types = part.ClassExtends; + %{serTy}.extends = extTy; + StringTemplate impsTy = %imps(); + %{impsTy}.types = part.ClassImplements; + %{serTy}.imps = impsTy; + %{serTy}.body = part.ClassBody; + %{serTy}.partial_types = emitParts(part.PartialTypes); + %{serTy}.end_comments = part.EndComments; + return serTy; + } + + protected StringTemplate emitParts(Dictionary partialTypes) + { + + // Pretty print as text + List serParts = new List(); + foreach (ClassDescriptorSerialized part in partialTypes.Values) { + StringTemplate partST = emitPartialType(part); + serParts.Add(partST); + } + StringTemplate allParts = %seplist(); + %{allParts}.items = serParts; + %{allParts}.sep = "\n"; + + return allParts; + } } public compilation_unit +scope TypeContext; @init{ initPrecedence(); + $TypeContext::partialTypes = new Dictionary(); } : ^(PACKAGE nm=PAYLOAD imports? type_declaration) { if (IsLast) collectComments(); - if (IsPartial) { - // Merge into existing descriptor + if (PartialDescriptor != null && $TypeContext::partialTypes.Count > 0) { + // Merge into existing descriptor (must only be one) + foreach (ClassDescriptorSerialized part in $TypeContext::partialTypes.Values) { + mergeParts(PartialDescriptor, part); + } + + // If this is the first time we have seen thsi we must ensure Package name is there PartialDescriptor.Package = ($nm.text != null && $nm.text.Length > 0 ? $nm.text : null); if ($imports.importList != null && $imports.importList.Count > 0) { foreach (string m in $imports.importList) { @@ -315,8 +439,18 @@ public compilation_unit } } } + if (IsLast) { + List endComments = CollectedComments; + if (endComments != null) { + foreach (string comment in endComments) { + PartialDescriptor.EndComments += comment; + } + } + } + } } + -> { PartialDescriptor != null}? // output is all collected in PartialDescriptor -> package(now = {DateTime.Now}, includeDate = {Cfg.TranslatorAddTimeStamp}, packageName = {($nm.text != null && $nm.text.Length > 0 ? $nm.text : null)}, imports = {$imports.st}, @@ -955,59 +1089,65 @@ attribute_argument_expression: /////////////////////////////////////////////////////// class_declaration[bool topLevel] +scope TypeContext; @init { List preComments = null; + String name = ""; + bool isPartial = false; + $TypeContext::partialTypes = new Dictionary(); }: - ^(c=CLASS PAYLOAD? - attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list[$type_parameter_constraints_clauses.tpConstraints]? + ^(c=CLASS ('partial' { isPartial = true; })? PAYLOAD? + attributes? modifiers? identifier { name = $identifier.st.ToString(); } type_parameter_constraints_clauses? type_parameter_list[$type_parameter_constraints_clauses.tpConstraints]? class_extends? class_implements? { preComments = CollectedComments; preComments.Add($PAYLOAD.text); } class_body ) { - if (IsPartial && topLevel) { - // Merge into existing descriptor + + if (isPartial) { + // build a serialized descriptor and merge it + ClassDescriptorSerialized part = new ClassDescriptorSerialized(name); + if (preComments != null) { foreach (String comment in preComments) { - PartialDescriptor.Comments += comment ; + part.Comments += comment ; } } // Union all attributes - // we don't push through attributes yet - PartialDescriptor.Atts += mkString($attributes.st); - + part.Atts += mkString($attributes.st); // Merge modifiers if ($modifiers.modList != null && $modifiers.modList.Count > 0) { foreach (string m in $modifiers.modList) { - if (!PartialDescriptor.Mods.Contains(m)) { - PartialDescriptor.Mods.Add(m); - } + part.Mods.Add(m); } } + part.TypeParameterList = mkString($type_parameter_list.st); - if (String.IsNullOrEmpty(PartialDescriptor.TypeParameterList)) { - PartialDescriptor.TypeParameterList = mkString($type_parameter_list.st); + if ($class_extends.extendList != null && $class_extends.extendList.Count > 0) { + foreach (string m in $class_extends.extendList) { + part.ClassExtends.Add(m); + } } - - if (String.IsNullOrEmpty(PartialDescriptor.TypeParameterConstraintsClauses)) { - PartialDescriptor.TypeParameterConstraintsClauses = mkString($type_parameter_constraints_clauses.st); - } - + if ($class_implements.implementList != null && $class_implements.implementList.Count > 0) { foreach (string m in $class_implements.implementList) { - if (!PartialDescriptor.ClassImplements.Contains(m)) { - PartialDescriptor.ClassImplements.Add(m); - } + part.ClassImplements.Add(m); } } - if (String.IsNullOrEmpty(PartialDescriptor.ClassBase)) { - PartialDescriptor.ClassBase = mkString($class_extends.st); - } + part.ClassBody += mkString($class_body.st); + part.PartialTypes = $TypeContext::partialTypes; - // Union the class bodies - PartialDescriptor.ClassBody += mkString($class_body.st); + // Place this in our parent's scope + Dictionary parentPartialTypes = ((TypeContext_scope)$TypeContext.ToArray()[1]).partialTypes; + if (!parentPartialTypes.ContainsKey(name)) { + parentPartialTypes[name] = part; + } + else { + mergeParts(parentPartialTypes[name], part); + } } } + -> {isPartial}? -> class(modifiers = { $modifiers.st }, name={ $identifier.st }, typeparams= {$type_parameter_list.st}, comments = { preComments }, - extends = { $class_extends.st }, imps = { $class_implements.st }, body={$class_body.st}) ; + extends = { $class_extends.st }, imps = { $class_implements.st }, body={$class_body.st}, partial_types = { emitParts($TypeContext::partialTypes) }) ; type_parameter_list [Dictionary tpConstraints]: (attributes? t+=type_parameter[tpConstraints])+ -> type_parameter_list(items={ $t }); @@ -1018,15 +1158,18 @@ type_parameter [Dictionary tpConstraints] }: identifier {if (tpConstraints == null || !tpConstraints.TryGetValue($identifier.text, out mySt)) {mySt = $identifier.st;}; } -> { mySt } ; -class_extends: - ts+=class_extend+ -> extends(types = { $ts }) ; -class_extend: - ^(EXTENDS ts=type) -> { $ts.st } ; +class_extends returns [List extendList] +@init { + $extendList = new List(); +}: + (class_extend { $extendList.Add($class_extend.extend); })+ -> extends(types = { $extendList }) ; +class_extend returns [string extend]: + ^(EXTENDS ts=type { $extend = $ts.st.ToString(); }) -> { $ts.st } ; class_implements returns [List implementList] @init { $implementList = new List(); }: - (class_implement {$implementList.Add($class_implement.st.ToString()); })+ -> imps(types = { $implementList }) ; + (class_implement {$implementList.Add($class_implement.implement); })+ -> imps(types = { $implementList }) ; class_implement returns [string implement]: ^(IMPLEMENTS ts=type) { $implement = $ts.st.ToString(); } -> { $ts.st }; @@ -1186,11 +1329,53 @@ parameter_array: interface_declaration @init { List preComments = null; + String name = ""; + bool isPartial = false; }: - ^(c=INTERFACE attributes? modifiers? - identifier type_parameter_constraints_clauses? variant_generic_parameter_list[$type_parameter_constraints_clauses.tpConstraints]? + ^(c=INTERFACE ('partial' { isPartial = true; })? attributes? modifiers? + identifier { name = $identifier.st.ToString(); } type_parameter_constraints_clauses? variant_generic_parameter_list[$type_parameter_constraints_clauses.tpConstraints]? class_extends? { preComments = CollectedComments; } interface_body ) - -> iface(modifiers = { $modifiers.st }, name={ $identifier.st }, typeparams={$variant_generic_parameter_list.st} ,comments = { preComments }, + { + + if (isPartial) { + // build a serialized descriptor and merge it + ClassDescriptorSerialized part = new ClassDescriptorSerialized(name); + + if (preComments != null) { + foreach (String comment in preComments) { + part.Comments += comment ; + } + } + part.Type = "interface"; + // Union all attributes + part.Atts += mkString($attributes.st); + // Merge modifiers + if ($modifiers.modList != null && $modifiers.modList.Count > 0) { + foreach (string m in $modifiers.modList) { + part.Mods.Add(m); + } + } + part.TypeParameterList = mkString($variant_generic_parameter_list.st); + + if ($class_extends.extendList != null && $class_extends.extendList.Count > 0) { + foreach (string m in $class_extends.extendList) { + part.ClassExtends.Add(m); + } + } + + part.ClassBody += mkString($interface_body.st); + + // Place this in our parent's scope (We don't declare a TypeContext scope because interfaces don't have nested types) + if (!$TypeContext::partialTypes.ContainsKey(name)) { + $TypeContext::partialTypes[name] = part; + } + else { + mergeParts($TypeContext::partialTypes[name], part); + } + } + } + -> {isPartial}? + -> class(type={ "interface" }, modifiers = { $modifiers.st }, name={ $identifier.st }, typeparams={$variant_generic_parameter_list.st} ,comments = { preComments }, imps = { $class_extends.st }, body = { $interface_body.st }) ; //interface_base: // ':' interface_type_list ; diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g index f55770f..d383354 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g @@ -2212,7 +2212,7 @@ scope NSContext,SymTab; $SymTab::symtab = new Dictionary(); } : - ^(c=CLASS PAYLOAD? attributes? modifiers? identifier type_parameter_constraints_clauses? + ^(c=CLASS 'partial'? PAYLOAD? attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list? { $NSContext::currentNS = NSPrefix(ParentNameSpace) + mkGenericTypeAlias($identifier.thetext, $type_parameter_list.tyParams); if (CompUnitName == null) CompUnitName = $NSContext::currentNS; } class_implements? @@ -2251,7 +2251,7 @@ scope NSContext,SymTab; } class_body magicAnnotation[$modifiers.tree, $identifier.tree, null, $c.token]) -> {$class_implements.hasExtends && $class_implements.extendDotNetType.IsA(AppEnv.Search("System.Attribute", new UnknownRepTemplate("System.Attribute")), AppEnv)}? magicAnnotation - -> ^($c PAYLOAD? attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list? class_implements? class_body); + -> ^($c 'partial'? PAYLOAD? attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list? class_implements? class_body); type_parameter_list returns [List tyParams] @init { @@ -2467,7 +2467,7 @@ parameter_array: /////////////////////////////////////////////////////// interface_declaration: - ^(INTERFACE attributes? modifiers? identifier type_parameter_constraints_clauses? variant_generic_parameter_list? + ^(INTERFACE 'partial'? attributes? modifiers? identifier type_parameter_constraints_clauses? variant_generic_parameter_list? class_extends? interface_body ) ; interface_modifiers: modifier+ ;