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) foreach (string r in csDir)
doFile(r, ".cs", translateFile, cfg.Exclude); // translate it 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) foreach (KeyValuePair<string, ClassDescriptorSerialized> entry in partialTypes)
emitPartialType(entry.Key, entry.Value); emitPartialType(entry.Key, entry.Value);
@ -537,8 +537,8 @@ namespace Twiglet.CS2J.Translator
outputMaker.Cfg = cfg; outputMaker.Cfg = cfg;
outputMaker.EmittedCommentTokenIdx = saveEmittedCommentTokenIdx; outputMaker.EmittedCommentTokenIdx = saveEmittedCommentTokenIdx;
outputMaker.IsPartial = javaMaker.CUMap[typeName].IsPartial; bool isPartial = javaMaker.CUMap[typeName].IsPartial;
if (outputMaker.IsPartial) if (isPartial)
{ {
if (!partialTypes.ContainsKey(typeName)) if (!partialTypes.ContainsKey(typeName))
{ {
@ -550,7 +550,7 @@ namespace Twiglet.CS2J.Translator
outputMaker.IsLast = i == (javaMaker.CUKeys.Count - 1); outputMaker.IsLast = i == (javaMaker.CUKeys.Count - 1);
if (!outputMaker.IsPartial) if (!isPartial)
{ {
if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", javaFName); if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", javaFName);
StreamWriter javaW = new StreamWriter(javaFName); StreamWriter javaW = new StreamWriter(javaFName);
@ -574,25 +574,17 @@ namespace Twiglet.CS2J.Translator
public static void emitPartialType(string name, ClassDescriptorSerialized serTy) public static void emitPartialType(string name, ClassDescriptorSerialized serTy)
{ {
JavaPrettyPrint outputMaker = new JavaPrettyPrint(null);
// Pretty print as text outputMaker.Filename = serTy.FileName;
Dictionary<string,object> args = new Dictionary<string,object>(); outputMaker.TraceDestination = Console.Error;
args["now"] = DateTime.Now; outputMaker.TemplateLib = templates;
args["includeDate"] = cfg.TranslatorAddTimeStamp; outputMaker.Cfg = cfg;
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;
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); if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", serTy.FileName);
StreamWriter javaW = new StreamWriter(serTy.FileName); StreamWriter javaW = new StreamWriter(serTy.FileName);
javaW.Write(limit(st.ToString())); javaW.Write(limit(pkgST.ToString()));
javaW.Close(); javaW.Close();
} }
} }

View File

@ -46,37 +46,16 @@ import_list(nss) ::= <<
import_template(ns) ::= ""import <ns>;"" 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 *********** // ******* 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""> <comments; separator=""\n"">
<modifiers(modifiers)>class <name> <typeparams> <extends> <imps> <modifiers><if(type)><type><else>class<endif> <name> <typeparams> <extends> <imps>
{
<body>
}
>>
iface(modifiers, comments, attributes, name, typeparams, imps, body) ::= <<
<comments; separator=""\n"">
<modifiers(modifiers)>interface <name> <typeparams> <imps>
{ {
<body> <body>
<partial_types>
} }
<end_comments; separator=""\n"">
>> >>
class_body(entries) ::= << class_body(entries) ::= <<
@ -89,7 +68,7 @@ class_member(comments, member) ::= <<
>> >>
constructor(modifiers, name, params, exceptions, body, bodyIsSemi) ::= << 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> <else>
<body> <body>
<endif> <endif>
@ -97,7 +76,7 @@ constructor(modifiers, name, params, exceptions, body, bodyIsSemi) ::= <<
>> >>
static_constructor(modifiers, body, bodyIsSemi) ::= << static_constructor(modifiers, body, bodyIsSemi) ::= <<
<modifiers(modifiers)><if(bodyIsSemi)>; <modifiers><if(bodyIsSemi)>;
<else> <else>
<body> <body>
<endif> <endif>
@ -105,14 +84,14 @@ static_constructor(modifiers, body, bodyIsSemi) ::= <<
>> >>
method(modifiers, typeparams, type, name, params, exceptions, 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> <else>
<body> <body>
<endif> <endif>
<\n> <\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_declarators(varinits) ::= ""<varinits; separator=\"", \"">""
variable_declarator(typename,init) ::= ""<typename><if(init)> = <init><endif>"" 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=\"" & \"">"" type_param_constraint(param, constraints) ::= ""<param> extends <constraints; separator=\"" & \"">""
fixed_parameter(mod,type,name,def) ::= << fixed_parameter(mod,type,name,def) ::= <<
<mod> <type> <name><if(def)> = <def><endif> <mod><type> <name><if(def)> = <def><endif>
>> >>
varargs(type,name) ::= << varargs(type,name) ::= <<
@ -141,7 +120,7 @@ statement(statement) ::= <<
annotation(modifiers, comments, attributes, name, body) ::= << annotation(modifiers, comments, attributes, name, body) ::= <<
<comments; separator=""\n""> <comments; separator=""\n"">
<modifiers(modifiers)>@interface <name> <modifiers>@interface <name>
{ {
<body> <body>
} }
@ -159,7 +138,7 @@ throw(exp) ::= ""throw <exp>;""
enum(modifiers,comments, attributes, name, body) ::= << enum(modifiers,comments, attributes, name, body) ::= <<
<comments; separator=""\n""> <comments; separator=""\n"">
<modifiers(modifiers)>enum <name> <modifiers>enum <name>
{ {
<body> <body>
} }
@ -175,7 +154,9 @@ enum_member(comments, value) ::= <<
type(name, rs, stars, opt) ::= ""<name><rs><stars><opt>"" 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>"" 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) ::= << type_parameter_list(items) ::= <<
\<<items; separator="", "">\> \<<items; separator="", "">\>

View File

@ -258,45 +258,24 @@ namespace Twiglet.CS2J.Translator.Transform
public bool IsPartial {get; set;} public bool IsPartial {get; set;}
} }
public class ClassDescriptor { // This structure holds (serialized) consolidated strings describing
public IToken Token { get;set; } // partial classes and interfaces
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;
}
}
public class ClassDescriptorSerialized { public class ClassDescriptorSerialized {
public String FileName { get;set; } public String FileName { get;set; }
public List<String> Imports { get;set; } public List<String> Imports { get;set; }
public String Package { get;set; } public String Package { get;set; }
public String Type { get;set; }
public String Comments { get;set; } public String Comments { get;set; }
public String Atts { get;set; } public String Atts { get;set; }
public List<String> Mods { get;set; } public List<String> Mods { get;set; }
public String Identifier { get;set; } public String Identifier { get;set; }
public String TypeParameterList { 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 List<String> ClassImplements { get;set; }
public String TypeParameterConstraintsClauses { get;set; }
public String ClassBody { get;set; } public String ClassBody { get;set; }
public String EndComments { get;set; }
public Dictionary<String,ClassDescriptorSerialized> PartialTypes { get;set; }
public ClassDescriptorSerialized(string name) public ClassDescriptorSerialized(string name)
{ {
@ -304,14 +283,16 @@ namespace Twiglet.CS2J.Translator.Transform
Comments = ""; Comments = "";
Imports = new List<String>(); Imports = new List<String>();
Package = ""; Package = "";
Type = "class";
Atts = ""; Atts = "";
Mods = new List<String>(); Mods = new List<String>();
Identifier = name; Identifier = name;
TypeParameterList = ""; TypeParameterList = "";
ClassBase = ""; ClassExtends = new List<String>();
ClassImplements = new List<String>(); ClassImplements = new List<String>();
TypeParameterConstraintsClauses = "";
ClassBody = ""; 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 // A scope to keep track of the current type context
scope TypeContext { scope TypeContext {
string typeName; string typeName;
Dictionary<String,ClassDescriptor> partialTypes;
} }
@namespace { Twiglet.CS2J.Translator.Transform } @namespace { Twiglet.CS2J.Translator.Transform }
@ -56,10 +55,6 @@ scope TypeContext {
public IDictionary<string, CUnit> CUMap { get; set; } public IDictionary<string, CUnit> CUMap { get; set; }
public IList<string> CUKeys { 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) { protected string snaffleComments(int startIndex, int endIndex) {
StringBuilder ret = new StringBuilder(); StringBuilder ret = new StringBuilder();
List<IToken> toks = ((CommonTokenStream)this.GetTreeNodeStream().TokenStream).GetTokens(startIndex,endIndex); List<IToken> toks = ((CommonTokenStream)this.GetTreeNodeStream().TokenStream).GetTokens(startIndex,endIndex);
@ -507,56 +502,56 @@ scope TypeContext {
} }
// Merges part into combined // Merges part into combined
protected void mergePartialTypes(ClassDescriptor combined, ClassDescriptor part) { // protected void mergePartialTypes(ClassDescriptor combined, ClassDescriptor part) {
//
// append comments // // append comments
combined.Comments += part.Comments; // combined.Comments += part.Comments;
//
// union all attributes // // union all attributes
CommonTree attRoot = (CommonTree)adaptor.Nil; // CommonTree attRoot = (CommonTree)adaptor.Nil;
adaptor.AddChild(attRoot, combined.Atts); // adaptor.AddChild(attRoot, combined.Atts);
adaptor.AddChild(attRoot, part.Atts); // adaptor.AddChild(attRoot, part.Atts);
combined.Atts = (CommonTree)adaptor.RulePostProcessing(attRoot); // combined.Atts = (CommonTree)adaptor.RulePostProcessing(attRoot);
//
// merge all modifiers // // merge all modifiers
combined.Mods = mergeModifiers(combined.Mods, part.Mods); // combined.Mods = mergeModifiers(combined.Mods, part.Mods);
//
// type parameter list must be the same on all parts // // type parameter list must be the same on all parts
//
// all parts that have a TypeParameterConstraintsClauses must agree // // all parts that have a TypeParameterConstraintsClauses must agree
if (combined.TypeParameterConstraintsClauses == null) // if (combined.TypeParameterConstraintsClauses == null)
combined.TypeParameterConstraintsClauses = part.TypeParameterConstraintsClauses; // combined.TypeParameterConstraintsClauses = part.TypeParameterConstraintsClauses;
//
// merge all base classes, interfaces // // merge all base classes, interfaces
combined.ClassBase = mergeModifiers(combined.ClassBase, part.ClassBase); // combined.ClassBase = mergeModifiers(combined.ClassBase, part.ClassBase);
//
// union all class_body // // union all class_body
CommonTree bodyRoot = (CommonTree)adaptor.Nil; // CommonTree bodyRoot = (CommonTree)adaptor.Nil;
adaptor.AddChild(bodyRoot, combined.ClassBody); // adaptor.AddChild(bodyRoot, combined.ClassBody);
adaptor.AddChild(bodyRoot, part.ClassBody); // adaptor.AddChild(bodyRoot, part.ClassBody);
combined.ClassBody = (CommonTree)adaptor.RulePostProcessing(bodyRoot); // combined.ClassBody = (CommonTree)adaptor.RulePostProcessing(bodyRoot);
//
// merge partial sub-types // // merge partial sub-types
foreach (string key in combined.PartialTypes.Keys) { // foreach (string key in combined.PartialTypes.Keys) {
if (part.PartialTypes.ContainsKey(key)) { // if (part.PartialTypes.ContainsKey(key)) {
mergePartialTypes(combined.PartialTypes[key], part.PartialTypes[key]); // mergePartialTypes(combined.PartialTypes[key], part.PartialTypes[key]);
} // }
} // }
// Add types in part but not combined // // Add types in part but not combined
foreach (string key in part.PartialTypes.Keys) { // foreach (string key in part.PartialTypes.Keys) {
if (!combined.PartialTypes.ContainsKey(key)) { // if (!combined.PartialTypes.ContainsKey(key)) {
combined.PartialTypes[key] = part.PartialTypes[key]; // combined.PartialTypes[key] = part.PartialTypes[key];
} // }
} // }
} // }
protected CommonTree emitPartialTypes(Dictionary<string,ClassDescriptor> partialTypes) { // protected CommonTree emitPartialTypes(Dictionary<string,ClassDescriptor> partialTypes) {
CommonTree root = (CommonTree)adaptor.Nil; // CommonTree root = (CommonTree)adaptor.Nil;
foreach (ClassDescriptor part in partialTypes.Values) { // foreach (ClassDescriptor part in partialTypes.Values) {
root.AddChild((CommonTree)magicClassFromDescriptor(part.Token, part).Tree); // root.AddChild((CommonTree)magicClassFromDescriptor(part.Token, part).Tree);
} // }
return (CommonTree)adaptor.RulePostProcessing(root); // return (CommonTree)adaptor.RulePostProcessing(root);
} // }
protected void mergeCompUnits(CUnit cu, List<string> searchPath, List<string> aliasKeys, List<string> aliasNamespaces) { protected void mergeCompUnits(CUnit cu, List<string> searchPath, List<string> aliasKeys, List<string> aliasNamespaces) {
foreach (string s in searchPath) { foreach (string s in searchPath) {
@ -590,7 +585,6 @@ scope NSContext, TypeContext;
$NSContext::aliasNamespaces = new List<string>(); $NSContext::aliasNamespaces = new List<string>();
$TypeContext::typeName = null; $TypeContext::typeName = null;
$TypeContext::partialTypes = new Dictionary<String,ClassDescriptor>();
} }
: :
namespace_body; namespace_body;
@ -636,7 +630,6 @@ scope TypeContext;
bool isCompUnit = false; bool isCompUnit = false;
CommonTree atts = null; CommonTree atts = null;
CommonTree mods = null; CommonTree mods = null;
$TypeContext::partialTypes = new Dictionary<string, ClassDescriptor>();
} }
@after { @after {
if (isCompUnit) { if (isCompUnit) {
@ -647,21 +640,11 @@ scope TypeContext;
Warning(treeEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + fqn); Warning(treeEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + fqn);
} }
else { 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); 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 namespace_declaration
@ -669,17 +652,19 @@ scope TypeContext;
; ;
// type_declaration is only called at the top level, so each of the types declared // 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) // 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 { @init {
$compUnits = new Dictionary<String,CommonTree>(); $compUnits = new Dictionary<String,CommonTree>();
$isPartial = false;
} }
: :
('partial') => p='partial'! (pc=class_declaration[$atts, $mods, true /* toplevel */, true /* isPartial */] ('partial') => p='partial' { $isPartial = true; }
| ps=struct_declaration[$atts, $mods, true /* toplevel */, true /* isPartial */] (pc=class_declaration[$atts, $mods, $p, true /* toplevel */] { $compUnits.Add($pc.name, $pc.tree); }
| pi=interface_declaration[$atts, $mods] { $compUnits.Add($pi.name, $pi.tree); } ) | ps=struct_declaration[$atts, $mods, $p, true /* toplevel */] { $compUnits.Add($ps.name, $ps.tree); }
| c=class_declaration[$atts, $mods, true /* toplevel */, false /* isPartial */] { $compUnits.Add($c.name, $c.tree); } | pi=interface_declaration[$atts, $mods, $p] { $compUnits.Add($pi.name, $pi.tree); } )
| s=struct_declaration[$atts, $mods, true /* toplevel */, false /* isPartial */] { $compUnits.Add($s.name, $s.tree); } | c=class_declaration[$atts, $mods, null, true /* toplevel */] { $compUnits.Add($c.name, $c.tree); }
| i=interface_declaration[$atts, $mods] { $compUnits.Add($i.name, $i.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); } | e=enum_declaration[$atts, $mods] { $compUnits.Add($e.name, $e.tree); }
| d=delegate_declaration[$atts, $mods, true /* toplevel */] { $compUnits = $d.compUnits; } | 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' '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 */; | '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 class_member_declaration:
@after {
this.prevMemberEndTokenIndex = adaptor.GetTokenStopIndex($class_member_declaration.tree);
}:
a=attributes? a=attributes?
m=modifiers? m=modifiers?
( c='const' ct=type constant_declarators ';' -> ^(FIELD[$c.token, "FIELD"] $a? $m? { addConstModifiers($c.token, $m.modList) } $ct constant_declarators) ( 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 | 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 | 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 | pi=interface_declaration[$a.tree, $m.tree, $p] -> $pi
| pc=class_declaration[$a.tree, $m.tree, false /* toplevel */, true /* isPartial */] -> { $pc.tree != null}? $pc | pc=class_declaration[$a.tree, $m.tree, $p, false /* toplevel */] -> $pc
-> | ps=struct_declaration[$a.tree, $m.tree, $p, false /* toplevel */] -> $ps)
| ps=struct_declaration[$a.tree, $m.tree, false /* toplevel */, true /* isPartial */] -> { ps.tree != null}? $ps | i=interface_declaration[$a.tree, $m.tree, null] -> $i
-> )
| i=interface_declaration[$a.tree, $m.tree] -> $i
| v2=void_type m1=method_declaration[$a.tree, $m.tree, $m.modList, $v2.tree, $v2.text, false /* isPartial */] -> $m1 | 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 | 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 | (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) // common_modifiers// (method_modifiers | field_modifiers)
| cd=class_declaration[$a.tree, $m.tree, false /* toplevel */, false /* isPartial */] -> $cd | cd=class_declaration[$a.tree, $m.tree, null, false /* toplevel */] -> $cd
| sd=struct_declaration[$a.tree, $m.tree, false /* toplevel */, false /* isPartial */] -> $sd | sd=struct_declaration[$a.tree, $m.tree, null, false /* toplevel */] -> $sd
| ed=enum_declaration[$a.tree, $m.tree] -> $ed | ed=enum_declaration[$a.tree, $m.tree] -> $ed
| dd=delegate_declaration[$a.tree, $m.tree, false /* toplevel */] -> { mkFlattenDictionary($dd.tree.Token,$dd.compUnits) } | 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) | co3=conversion_operator_declaration -> ^(CONVERSION_OPERATOR[$co3.start.Token, "CONVERSION"] $a? $m? $co3)
@ -1258,42 +1238,11 @@ attribute_argument_expression:
// Class Section // 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; 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; })? 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 );
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 );
type_parameter_list returns [List<string> names] type_parameter_list returns [List<string> names]
@init { @init {
@ -1311,10 +1260,8 @@ class_base:
//interface_type_list: //interface_type_list:
// ts+=type (',' ts+=type)* -> $ts+; // ts+=type (',' ts+=type)* -> $ts+;
class_body[bool isPartial] returns [IToken endToken]: class_body:
'{' class_member_declarations? e='}' { $endToken = $e.token; } '{' class_member_declarations? '}' ;
-> {!$isPartial}? '{' class_member_declarations? { emitPartialTypes($TypeContext::partialTypes) } '}'
-> '{' class_member_declarations? '}' ;
class_member_declarations: class_member_declarations:
class_member_declaration+ ; 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; scope TypeContext;
: :
c='interface' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } variant_generic_parameter_list? c='interface' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } variant_generic_parameter_list?
interface_base? type_parameter_constraints_clauses? interface_body ';'? 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: interface_base:
c=':' ts+=type (',' ts+=type)* -> ^(EXTENDS[$c.token,"extends"] $ts)*; 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; 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; })? 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 );
if ($isPartial) {
// Strip off braces struct_body [string structName]:
CommonTree newClassBody = dupTree($struct_body.tree); o='{' magicDefaultConstructor[$o.token, structName] class_member_declarations? e='}'
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) } '}'
-> '{' magicDefaultConstructor class_member_declarations? '}' ; -> '{' 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, "}"]) OPEN_BRACE[tok, "{"] {dupTree(invokeMethod)} { dupTree(members) } CLOSE_BRACE[tok, "}"])
; ;
magicClassFromDescriptor[IToken tok, ClassDescriptor klass]: //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, "}"] ); //-> ^(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; 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 } @namespace { Twiglet.CS2J.Translator.Transform }
@header @header
@ -25,9 +30,9 @@ options {
@members @members
{ {
public bool IsPartial { get; set; }
public bool IsLast { get; set; } public bool IsLast { get; set; }
public int EmittedCommentTokenIdx { 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; } public ClassDescriptorSerialized PartialDescriptor { get; set; }
private List<string> collectedComments = null; private List<string> collectedComments = null;
@ -293,20 +298,139 @@ options {
protected string mkString(object s) { protected string mkString(object s) {
return (s == null ? String.Empty : s.ToString()); 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 public compilation_unit
scope TypeContext;
@init{ @init{
initPrecedence(); initPrecedence();
$TypeContext::partialTypes = new Dictionary<string,ClassDescriptorSerialized>();
} }
: :
^(PACKAGE nm=PAYLOAD imports? type_declaration) ^(PACKAGE nm=PAYLOAD imports? type_declaration)
{ {
if (IsLast) collectComments(); if (IsLast) collectComments();
if (IsPartial) { if (PartialDescriptor != null && $TypeContext::partialTypes.Count > 0) {
// Merge into existing descriptor // 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); PartialDescriptor.Package = ($nm.text != null && $nm.text.Length > 0 ? $nm.text : null);
if ($imports.importList != null && $imports.importList.Count > 0) { if ($imports.importList != null && $imports.importList.Count > 0) {
foreach (string m in $imports.importList) { 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)}, package(now = {DateTime.Now}, includeDate = {Cfg.TranslatorAddTimeStamp}, packageName = {($nm.text != null && $nm.text.Length > 0 ? $nm.text : null)},
imports = {$imports.st}, imports = {$imports.st},
@ -955,59 +1089,65 @@ attribute_argument_expression:
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
class_declaration[bool topLevel] class_declaration[bool topLevel]
scope TypeContext;
@init { @init {
List<string> preComments = null; List<string> preComments = null;
String name = "";
bool isPartial = false;
$TypeContext::partialTypes = new Dictionary<string,ClassDescriptorSerialized>();
}: }:
^(c=CLASS PAYLOAD? ^(c=CLASS ('partial' { isPartial = true; })? PAYLOAD?
attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list[$type_parameter_constraints_clauses.tpConstraints]? 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 ) 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) { if (preComments != null) {
foreach (String comment in preComments) { foreach (String comment in preComments) {
PartialDescriptor.Comments += comment ; part.Comments += comment ;
} }
} }
// Union all attributes // Union all attributes
// we don't push through attributes yet part.Atts += mkString($attributes.st);
PartialDescriptor.Atts += mkString($attributes.st);
// Merge modifiers // Merge modifiers
if ($modifiers.modList != null && $modifiers.modList.Count > 0) { if ($modifiers.modList != null && $modifiers.modList.Count > 0) {
foreach (string m in $modifiers.modList) { foreach (string m in $modifiers.modList) {
if (!PartialDescriptor.Mods.Contains(m)) { part.Mods.Add(m);
PartialDescriptor.Mods.Add(m);
}
} }
} }
part.TypeParameterList = mkString($type_parameter_list.st);
if (String.IsNullOrEmpty(PartialDescriptor.TypeParameterList)) { if ($class_extends.extendList != null && $class_extends.extendList.Count > 0) {
PartialDescriptor.TypeParameterList = mkString($type_parameter_list.st); 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) { if ($class_implements.implementList != null && $class_implements.implementList.Count > 0) {
foreach (string m in $class_implements.implementList) { foreach (string m in $class_implements.implementList) {
if (!PartialDescriptor.ClassImplements.Contains(m)) { part.ClassImplements.Add(m);
PartialDescriptor.ClassImplements.Add(m);
}
} }
} }
if (String.IsNullOrEmpty(PartialDescriptor.ClassBase)) { part.ClassBody += mkString($class_body.st);
PartialDescriptor.ClassBase = mkString($class_extends.st); part.PartialTypes = $TypeContext::partialTypes;
}
// Union the class bodies // Place this in our parent's scope
PartialDescriptor.ClassBody += mkString($class_body.st); 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 }, -> 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]: type_parameter_list [Dictionary<string,StringTemplate> tpConstraints]:
(attributes? t+=type_parameter[tpConstraints])+ -> type_parameter_list(items={ $t }); (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 } ; identifier {if (tpConstraints == null || !tpConstraints.TryGetValue($identifier.text, out mySt)) {mySt = $identifier.st;}; } -> { mySt } ;
class_extends: class_extends returns [List<String> extendList]
ts+=class_extend+ -> extends(types = { $ts }) ; @init {
class_extend: $extendList = new List<String>();
^(EXTENDS ts=type) -> { $ts.st } ; }:
(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] class_implements returns [List<String> implementList]
@init { @init {
$implementList = new List<String>(); $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]: class_implement returns [string implement]:
^(IMPLEMENTS ts=type) { $implement = $ts.st.ToString(); } -> { $ts.st }; ^(IMPLEMENTS ts=type) { $implement = $ts.st.ToString(); } -> { $ts.st };
@ -1186,11 +1329,53 @@ parameter_array:
interface_declaration interface_declaration
@init { @init {
List<string> preComments = null; List<string> preComments = null;
String name = "";
bool isPartial = false;
}: }:
^(c=INTERFACE attributes? modifiers? ^(c=INTERFACE ('partial' { isPartial = true; })? attributes? modifiers?
identifier type_parameter_constraints_clauses? variant_generic_parameter_list[$type_parameter_constraints_clauses.tpConstraints]? identifier { name = $identifier.st.ToString(); } type_parameter_constraints_clauses? variant_generic_parameter_list[$type_parameter_constraints_clauses.tpConstraints]?
class_extends? { preComments = CollectedComments; } interface_body ) 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 }) ; imps = { $class_extends.st }, body = { $interface_body.st }) ;
//interface_base: //interface_base:
// ':' interface_type_list ; // ':' interface_type_list ;

View File

@ -2212,7 +2212,7 @@ scope NSContext,SymTab;
$SymTab::symtab = new Dictionary<string, TypeRepTemplate>(); $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? type_parameter_list?
{ $NSContext::currentNS = NSPrefix(ParentNameSpace) + mkGenericTypeAlias($identifier.thetext, $type_parameter_list.tyParams); if (CompUnitName == null) CompUnitName = $NSContext::currentNS; } { $NSContext::currentNS = NSPrefix(ParentNameSpace) + mkGenericTypeAlias($identifier.thetext, $type_parameter_list.tyParams); if (CompUnitName == null) CompUnitName = $NSContext::currentNS; }
class_implements? class_implements?
@ -2251,7 +2251,7 @@ scope NSContext,SymTab;
} }
class_body magicAnnotation[$modifiers.tree, $identifier.tree, null, $c.token]) 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 -> {$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] type_parameter_list returns [List<string> tyParams]
@init { @init {
@ -2467,7 +2467,7 @@ parameter_array:
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
interface_declaration: 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 ) ; class_extends? interface_body ) ;
interface_modifiers: interface_modifiers:
modifier+ ; modifier+ ;