1
0
mirror of https://github.com/twiglet/cs2j.git synced 2025-01-18 13:15:17 +01:00

Support for Partial Types.

Reworked earlier attempt that tried to collect them after JavaMaker phase. Realised it is better to go all the way through to generating strings because we need the original token stream to do that and partial types can be splity across different files.

Its actually simpler this way.
This commit is contained in:
Kevin Glynn 2011-06-10 13:27:40 +02:00
parent 930db5d588
commit d855f757ae
6 changed files with 343 additions and 290 deletions

View File

@ -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<string, ClassDescriptorSerialized> 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<string,object> args = new Dictionary<string,object>();
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();
}
}

View File

@ -46,37 +46,16 @@ import_list(nss) ::= <<
import_template(ns) ::= ""import <ns>;""
// ****** output partial type ******
partial_type(now, includeDate, packageName, imports, modifiers, comments, attributes, name, typeparams, extends, imps, body) ::= <<
<itsmine(now=now,includeDate=includeDate)>
<if(packageName)>package <packageName>;<endif>
<comments; separator=""\n"">
<import_list(imports)>
<modifiers(modifiers)>class <name> <typeparams> <extends><if(imps)> implements <imps; separator="",""><endif>
{
<body>
}
>>
// ******* CLASSES ***********
class(modifiers, comments, attributes, name, typeparams, extends, imps, body) ::= <<
class(modifiers, comments, attributes, type, name, typeparams, extends, imps, body, partial_types, end_comments) ::= <<
<comments; separator=""\n"">
<modifiers(modifiers)>class <name> <typeparams> <extends> <imps>
{
<body>
}
>>
iface(modifiers, comments, attributes, name, typeparams, imps, body) ::= <<
<comments; separator=""\n"">
<modifiers(modifiers)>interface <name> <typeparams> <imps>
<modifiers><if(type)><type><else>class<endif> <name> <typeparams> <extends> <imps>
{
<body>
<partial_types>
}
<end_comments; separator=""\n"">
>>
class_body(entries) ::= <<
@ -89,7 +68,7 @@ class_member(comments, member) ::= <<
>>
constructor(modifiers, name, params, exceptions, body, bodyIsSemi) ::= <<
<modifiers(modifiers)><name>(<params; separator="", "">)<if(exceptions)> throws <exceptions; separator="", ""><endif> <if(bodyIsSemi)>;
<modifiers><name>(<params; separator="", "">)<if(exceptions)> throws <exceptions; separator="", ""><endif> <if(bodyIsSemi)>;
<else>
<body>
<endif>
@ -97,7 +76,7 @@ constructor(modifiers, name, params, exceptions, body, bodyIsSemi) ::= <<
>>
static_constructor(modifiers, body, bodyIsSemi) ::= <<
<modifiers(modifiers)><if(bodyIsSemi)>;
<modifiers><if(bodyIsSemi)>;
<else>
<body>
<endif>
@ -105,14 +84,14 @@ static_constructor(modifiers, body, bodyIsSemi) ::= <<
>>
method(modifiers, typeparams, type, name, params, exceptions, body, bodyIsSemi) ::= <<
<modifiers(modifiers)><typeparams> <type> <name>(<params; separator="", "">)<if(exceptions)> throws <exceptions; separator="", ""><endif> <if(bodyIsSemi)>;
<modifiers><typeparams><type> <name>(<params>)<if(exceptions)> throws <exceptions; separator="", ""><endif> <if(bodyIsSemi)>;
<else>
<body>
<endif>
<\n>
>>
field(modifiers, type, field, comments, init) ::= ""<comments><modifiers(modifiers)><type> <field>;""
field(modifiers, type, field, comments, init) ::= ""<comments><modifiers><type> <field>;""
variable_declarators(varinits) ::= ""<varinits; separator=\"", \"">""
variable_declarator(typename,init) ::= ""<typename><if(init)> = <init><endif>""
@ -122,7 +101,7 @@ primary_expression_start_parts(start,follows) ::= ""<start><follows>""
type_param_constraint(param, constraints) ::= ""<param> extends <constraints; separator=\"" & \"">""
fixed_parameter(mod,type,name,def) ::= <<
<mod> <type> <name><if(def)> = <def><endif>
<mod><type> <name><if(def)> = <def><endif>
>>
varargs(type,name) ::= <<
@ -141,7 +120,7 @@ statement(statement) ::= <<
annotation(modifiers, comments, attributes, name, body) ::= <<
<comments; separator=""\n"">
<modifiers(modifiers)>@interface <name>
<modifiers>@interface <name>
{
<body>
}
@ -159,7 +138,7 @@ throw(exp) ::= ""throw <exp>;""
enum(modifiers,comments, attributes, name, body) ::= <<
<comments; separator=""\n"">
<modifiers(modifiers)>enum <name>
<modifiers>enum <name>
{
<body>
}
@ -175,7 +154,9 @@ enum_member(comments, value) ::= <<
type(name, rs, stars, opt) ::= ""<name><rs><stars><opt>""
namespace_or_type(type1, type2, types) ::= ""<type1><if(type2)>::<type2><endif><if(types)>.<types; separator=\"".\""><endif>""
modifiers(mods) ::= ""<if(mods)><mods; separator=\"" \""> <endif>""
modifiers(mods) ::= <<
<if(mods)><mods; separator="" ""> <endif>
>>
type_parameter_list(items) ::= <<
\<<items; separator="", "">\>

View File

@ -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<String, ClassDescriptor> PartialTypes { get;set; }
public ClassDescriptor(IToken inToken, String inComments, CommonTree inAtts, CommonTree inMods, CommonTree inIdentifier, CommonTree inTypeParameterList, CommonTree inClassBase, CommonTree inTypeParameterConstraintsClauses, CommonTree inClassBody, Dictionary<String, ClassDescriptor> 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<String> 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<String> Mods { get;set; }
public String Identifier { get;set; }
public String TypeParameterList { get;set; }
public String ClassBase { get;set; }
public List<String> ClassExtends { get;set; } // Can have multiple extends in an interface
public List<String> ClassImplements { get;set; }
public String TypeParameterConstraintsClauses { get;set; }
public String ClassBody { get;set; }
public String EndComments { get;set; }
public Dictionary<String,ClassDescriptorSerialized> PartialTypes { get;set; }
public ClassDescriptorSerialized(string name)
{
@ -304,14 +283,16 @@ namespace Twiglet.CS2J.Translator.Transform
Comments = "";
Imports = new List<String>();
Package = "";
Type = "class";
Atts = "";
Mods = new List<String>();
Identifier = name;
TypeParameterList = "";
ClassBase = "";
ClassExtends = new List<String>();
ClassImplements = new List<String>();
TypeParameterConstraintsClauses = "";
ClassBody = "";
EndComments = "";
PartialTypes = new Dictionary<String,ClassDescriptorSerialized>();
}
}

View File

@ -33,7 +33,6 @@ scope NSContext {
// A scope to keep track of the current type context
scope TypeContext {
string typeName;
Dictionary<String,ClassDescriptor> partialTypes;
}
@namespace { Twiglet.CS2J.Translator.Transform }
@ -56,10 +55,6 @@ scope TypeContext {
public IDictionary<string, CUnit> CUMap { get; set; }
public IList<string> 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<IToken> 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<string,ClassDescriptor> 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<string,ClassDescriptor> 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<string> searchPath, List<string> aliasKeys, List<string> aliasNamespaces) {
foreach (string s in searchPath) {
@ -590,7 +585,6 @@ scope NSContext, TypeContext;
$NSContext::aliasNamespaces = new List<string>();
$TypeContext::typeName = null;
$TypeContext::partialTypes = new Dictionary<String,ClassDescriptor>();
}
:
namespace_body;
@ -636,7 +630,6 @@ scope TypeContext;
bool isCompUnit = false;
CommonTree atts = null;
CommonTree mods = null;
$TypeContext::partialTypes = new Dictionary<string, ClassDescriptor>();
}
@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<String, ClassDescriptor> 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<String,CommonTree> compUnits]
type_declaration[CommonTree atts, CommonTree mods] returns [Dictionary<String,CommonTree> compUnits, bool isPartial]
@init {
$compUnits = new Dictionary<String,CommonTree>();
$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<String,ClassDescriptor>();
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<String,ClassDescriptor> 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<string> 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<String,ClassDescriptor>();
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<String,ClassDescriptor> 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, "}"] );

View File

@ -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<string,ClassDescriptorSerialized> 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<string> 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<String,ClassDescriptorSerialized> 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<string, ClassDescriptorSerialized> partialTypes)
{
// Pretty print as text
List<StringTemplate> serParts = new List<StringTemplate>();
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<string,ClassDescriptorSerialized>();
}
:
^(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<string> 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<string> preComments = null;
String name = "";
bool isPartial = false;
$TypeContext::partialTypes = new Dictionary<string,ClassDescriptorSerialized>();
}:
^(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<string,ClassDescriptorSerialized> 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<string,StringTemplate> tpConstraints]:
(attributes? t+=type_parameter[tpConstraints])+ -> type_parameter_list(items={ $t });
@ -1018,15 +1158,18 @@ type_parameter [Dictionary<string,StringTemplate> 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<String> extendList]
@init {
$extendList = new List<String>();
}:
(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<String> implementList]
@init {
$implementList = new List<String>();
}:
(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<string> 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 ;

View File

@ -2212,7 +2212,7 @@ scope NSContext,SymTab;
$SymTab::symtab = new Dictionary<string, TypeRepTemplate>();
}
:
^(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<string> 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+ ;