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

implement top level partial types

This commit is contained in:
Kevin Glynn 2011-06-07 17:11:29 +02:00
parent 24ea1b1fc3
commit 0b8e05d0a6
6 changed files with 522 additions and 104 deletions

View File

@ -45,6 +45,8 @@ namespace Twiglet.CS2J.Translator
public delegate void FileProcessor(string fName);
private static Dictionary<string, ClassDescriptorSerialized> partialTypes = new Dictionary<string, ClassDescriptorSerialized>();
private static void showVersion()
{
Console.Out.WriteLine(Path.GetFileNameWithoutExtension(System.Environment.GetCommandLineArgs()[0]) + ": " + VERSION);
@ -207,6 +209,10 @@ 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");
foreach (KeyValuePair<string, ClassDescriptorSerialized> entry in partialTypes)
emitPartialType(entry.Key, entry.Value);
if (cfg.DumpEnums)
{
enumXmlWriter.WriteEndElement();
@ -531,12 +537,31 @@ namespace Twiglet.CS2J.Translator
outputMaker.Cfg = cfg;
outputMaker.EmittedCommentTokenIdx = saveEmittedCommentTokenIdx;
outputMaker.IsPartial = javaMaker.CUMap[typeName].IsPartial;
if (outputMaker.IsPartial)
{
if (!partialTypes.ContainsKey(typeName))
{
partialTypes[typeName] = new ClassDescriptorSerialized(claName);
partialTypes[typeName].FileName = javaFName;
}
outputMaker.PartialDescriptor = partialTypes[typeName];
}
outputMaker.IsLast = i == (javaMaker.CUKeys.Count - 1);
if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", javaFName);
StreamWriter javaW = new StreamWriter(javaFName);
javaW.Write(limit(outputMaker.compilation_unit().ToString()));
javaW.Close();
if (!outputMaker.IsPartial)
{
if (cfg.DebugLevel >= 1) Console.Out.WriteLine("Writing out {0}", javaFName);
StreamWriter javaW = new StreamWriter(javaFName);
javaW.Write(limit(outputMaker.compilation_unit().ToString()));
javaW.Close();
}
else
{
// fill out partialTypes[typeName]
outputMaker.compilation_unit();
}
saveEmittedCommentTokenIdx = outputMaker.EmittedCommentTokenIdx;
}
}
@ -546,5 +571,29 @@ namespace Twiglet.CS2J.Translator
System.Console.Out.WriteLine("");
System.Console.Out.WriteLine("");
}
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;
StringTemplate st = templates.GetInstanceOf("partial_type", args);
// 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.Close();
}
}
}

View File

@ -40,8 +40,27 @@ package(now, includeDate, packageName, imports, comments, modifiers, type, endCo
<endComments; separator=""\n"">
>>
import_list(nss) ::= <<
<nss:{x | import <x>;}; separator=""\n"">
>>
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) ::= <<
@ -347,3 +366,4 @@ verbatim_string(payload) ::= <<
}
}
}

View File

@ -234,12 +234,19 @@ namespace Twiglet.CS2J.Translator.Transform
// Wraps a compilation unit with its imports search path
public class CUnit {
public CUnit(CommonTree inTree, List<string> inSearchPath, List<string> inAliasKeys, List<string> inAliasValues) {
public CUnit(CommonTree inTree, List<string> inSearchPath, List<string> inAliasKeys, List<string> inAliasValues)
: this(inTree, inSearchPath, inAliasKeys, inAliasValues, false)
{
}
public CUnit(CommonTree inTree, List<string> inSearchPath, List<string> inAliasKeys, List<string> inAliasValues, bool inIsPartial) {
Tree = inTree;
SearchPath = inSearchPath;
NameSpaceAliasKeys = inAliasKeys;
NameSpaceAliasValues = inAliasValues;
IsPartial = inIsPartial;
}
public CommonTree Tree {get; set;}
// namespaces in scope
@ -248,6 +255,64 @@ namespace Twiglet.CS2J.Translator.Transform
// aliases for namespaces
public List<string> NameSpaceAliasKeys {get; set;}
public List<string> NameSpaceAliasValues {get; set;}
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;
}
}
public class ClassDescriptorSerialized {
public String FileName { get;set; }
public List<String> Imports { get;set; }
public String Package { 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> ClassImplements { get;set; }
public String TypeParameterConstraintsClauses { get;set; }
public String ClassBody { get;set; }
public ClassDescriptorSerialized(string name)
{
FileName = "";
Comments = "";
Imports = new List<String>();
Package = "";
Atts = "";
Mods = new List<String>();
Identifier = name;
TypeParameterList = "";
ClassBase = "";
ClassImplements = new List<String>();
TypeParameterConstraintsClauses = "";
ClassBody = "";
}
}
}

View File

@ -33,6 +33,7 @@ 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 }
@ -42,6 +43,7 @@ scope TypeContext {
using System;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
}
@members
@ -49,11 +51,29 @@ scope TypeContext {
// Since a CS file may comtain multiple top level types (and so generate multiple Java
// files) we build a map from type name to AST for each top level type
// We also build a lit of type names so that we can maintain the order (so comments
// We also build a list of type names so that we can maintain the order (so comments
// at the end of the file will get included when we emit the java for the last type)
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);
if (toks != null) {
foreach (IToken tok in toks) {
if (tok.Channel == TokenChannels.Hidden) {
ret.Append(new Regex("(\\n|\\r)+").Replace(tok.Text, Environment.NewLine).Trim());
// Hide from Pretty Printer
tok.Channel = TokenChannels.Hidden - 1;
}
}
}
return ret.ToString();
}
protected string ParentNameSpace {
get {
return ((NSContext_scope)$NSContext.ToArray()[1]).currentNS;
@ -140,7 +160,7 @@ scope TypeContext {
// null, or
// a single token, or
// a list of tokens (^(NIL ......))
protected CommonTree addModifier(IToken tok, CommonTree mods, CommonTree modToAdd) {
protected CommonTree addModifier(CommonTree mods, CommonTree modToAdd) {
CommonTree root = (CommonTree)adaptor.Nil;
@ -149,7 +169,7 @@ scope TypeContext {
if (mods != null) {
// Is root node the one we are looking for?
if (!mods.IsNil) {
if (adaptor.GetType(mods) == adaptor.GetType(modToAdd)) {
if (adaptor.GetType(mods) == adaptor.GetType(modToAdd) && adaptor.GetText(mods) == adaptor.GetText(modToAdd)) {
modSeen = true;
}
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(mods));
@ -157,7 +177,7 @@ scope TypeContext {
else {
for (int i = 0; i < adaptor.GetChildCount(mods); i++) {
CommonTree child = (CommonTree)adaptor.GetChild(mods,i);
if (adaptor.GetType(child) == adaptor.GetType(modToAdd)) {
if (adaptor.GetType(child) == adaptor.GetType(modToAdd) && adaptor.GetText(child) == adaptor.GetText(modToAdd)) {
modSeen = true;
}
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(child));
@ -172,6 +192,24 @@ scope TypeContext {
return root;
}
// add all modifiers in modToAdd tree
protected CommonTree mergeModifiers(CommonTree mods, CommonTree modToAdd) {
if (modToAdd == null)
return mods;
if (!modToAdd.IsNil) {
return addModifier(mods, modToAdd);
}
CommonTree ret = mods;
for (int i = 0; i < adaptor.GetChildCount(modToAdd); i++) {
ret = addModifier(mods, (CommonTree)adaptor.GetChild(modToAdd, i));
}
return ret;
}
// mods is a list of modifiers. removes is a list of token types, we remove all modifiers appearing in removes
protected CommonTree mkRemoveMods(CommonTree mods, int[] removes) {
@ -467,6 +505,73 @@ scope TypeContext {
}
return ret.ToString();
}
// 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 mergeCompUnits(CUnit cu, List<string> searchPath, List<string> aliasKeys, List<string> aliasNamespaces) {
foreach (string s in searchPath) {
if (!cu.SearchPath.Contains(s)) {
cu.SearchPath.Add(s);
}
for (int i = 0; i < aliasKeys.Count; i++) {
// TODO: ?? Assume alias -> namespace mapping is the same in all files ....
if (!cu.NameSpaceAliasKeys.Contains(aliasKeys[i])) {
cu.NameSpaceAliasKeys.Add(aliasKeys[i]);
cu.NameSpaceAliasValues.Add(aliasNamespaces[i]);
}
}
}
}
}
@ -477,12 +582,15 @@ scope TypeContext {
///////////////////////////////////////////////////////
public compilation_unit
scope NSContext;
scope NSContext, TypeContext;
@init {
$NSContext::currentNS = "";
$NSContext::namespaces = new List<string>();
$NSContext::aliasKeys = new List<string>();
$NSContext::aliasNamespaces = new List<string>();
$TypeContext::typeName = null;
$TypeContext::partialTypes = new Dictionary<String,ClassDescriptor>();
}
:
namespace_body;
@ -523,24 +631,37 @@ using_namespace_directive:
namespace_member_declarations:
namespace_member_declaration+ ;
namespace_member_declaration
scope TypeContext;
@init { string ns = $NSContext::currentNS;
bool isCompUnit = false;
CommonTree atts = null;
CommonTree mods = null;
$TypeContext::partialTypes = new Dictionary<string, ClassDescriptor>();
}
@after {
if (isCompUnit) {
foreach (KeyValuePair<String, CommonTree> treeEntry in $ty.compUnits) {
if (treeEntry.Value != null) {
if (CUKeys.Contains(ns+"."+treeEntry.Key)) {
{ Warning(treeEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + ns+"."+treeEntry.Key); }
string fqn = ns+(String.IsNullOrEmpty(ns) ? "" : ".")+treeEntry.Key;
if (CUKeys.Contains(fqn)) {
Warning(treeEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + fqn);
}
else {
CUMap.Add(ns+"."+treeEntry.Key, new CUnit(mkPackage(treeEntry.Value.Token, treeEntry.Value, ns),CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces));
CUKeys.Add(ns+"."+treeEntry.Key);
CUMap.Add(fqn, new CUnit(mkPackage(treeEntry.Value.Token, treeEntry.Value, ns),CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces));
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
@ -553,12 +674,11 @@ type_declaration[CommonTree atts, CommonTree mods] returns [Dictionary<String,Co
$compUnits = new Dictionary<String,CommonTree>();
}
:
('partial') => p='partial'! { Warning($p.line, "[UNSUPPORTED] 'partial' definition"); }
(pc=class_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($pc.name, $pc.tree); }
| ps=struct_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($ps.name, $ps.tree); }
('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 */] { $compUnits.Add($c.name, $c.tree); }
| s=struct_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($s.name, $s.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); }
| e=enum_declaration[$atts, $mods] { $compUnits.Add($e.name, $e.tree); }
| d=delegate_declaration[$atts, $mods, true /* toplevel */] { $compUnits = $d.compUnits; }
@ -578,18 +698,24 @@ 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:
class_member_declaration
@after {
this.prevMemberEndTokenIndex = adaptor.GetTokenStopIndex($class_member_declaration.tree);
}:
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' { Warning($p.line, "[UNSUPPORTED] 'partial' definition"); } (v1=void_type m3=method_declaration[$a.tree, $m.tree, $m.modList, $v1.tree, $v1.text] -> $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
| pc=class_declaration[$a.tree, $m.tree, false /* toplevel */] -> $pc
| ps=struct_declaration[$a.tree, $m.tree, false /* toplevel */] -> $ps)
| 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
| v2=void_type m1=method_declaration[$a.tree, $m.tree, $m.modList, $v2.tree, $v2.text] -> $m1
| t=type ( (member_name type_parameter_list? '(') => m2=method_declaration[$a.tree, $m.tree, $m.modList, $t.tree, $t.text] -> $m2
| 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
| (type_name '.' 'this') => tn=type_name '.' ix1=indexer_declaration[$a.tree, $m.tree, $t.tree, $tn.tree] -> $ix1
| ix2=indexer_declaration[$a.tree, $m.tree, $t.tree, null] -> $ix2 //this
@ -598,8 +724,8 @@ class_member_declaration:
)
// common_modifiers// (method_modifiers | field_modifiers)
| cd=class_declaration[$a.tree, $m.tree, false /* toplevel */] -> $cd
| sd=struct_declaration[$a.tree, $m.tree, false /* toplevel */] -> $sd
| cd=class_declaration[$a.tree, $m.tree, false /* toplevel */, false /* isPartial */] -> $cd
| sd=struct_declaration[$a.tree, $m.tree, false /* toplevel */, false /* isPartial */] -> $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)
@ -923,9 +1049,9 @@ pointer_type:
///////////////////////////////////////////////////////
// Statement Section
///////////////////////////////////////////////////////
block:
';'
| '{' statement_list? '}';
block returns [bool isEmpty]:
';' { $isEmpty = true; }
| '{' statement_list? '}' { $isEmpty = false; };
statement_list:
statement[/* isStatementListCtxt */ true]+ ;
@ -1132,11 +1258,42 @@ attribute_argument_expression:
// Class Section
///////////////////////////////////////////////////////
class_declaration[CommonTree atts, CommonTree mods, bool toplevel] returns [string name]
class_declaration[CommonTree atts, CommonTree mods, bool toplevel, bool isPartial] 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.text; } type_parameter_list? { $name = mkGenericTypeAlias($identifier.text, $type_parameter_list.names); } class_base? type_parameter_constraints_clauses? class_body ';'?
-> ^(CLASS[$c.Token] { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($c.token, $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[$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 );
type_parameter_list returns [List<string> names]
@init {
@ -1145,7 +1302,7 @@ type_parameter_list returns [List<string> names]
'<'! attributes? t1=type_parameter { names.Add($t1.name); } ( ','! attributes? tn=type_parameter { names.Add($tn.name); })* '>'! ;
type_parameter returns [string name]:
identifier { $name = $identifier.text; } ;
identifier { $name = $identifier.thetext; } ;
class_base:
// just put all types in a single list. In NetMaker we will extract the base class if necessary
@ -1154,8 +1311,10 @@ class_base:
//interface_type_list:
// ts+=type (',' ts+=type)* -> $ts+;
class_body:
'{' class_member_declarations? '}' ;
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_member_declarations:
class_member_declaration+ ;
@ -1178,7 +1337,7 @@ variable_declarator:
type_name ('=' variable_initializer)? ; // eg. event EventHandler IInterface.VariableName = Foo;
///////////////////////////////////////////////////////
method_declaration [CommonTree atts, CommonTree mods, List<string> modList, CommonTree type, string typeText]
method_declaration [CommonTree atts, CommonTree mods, List<string> modList, CommonTree type, string typeText, bool isPartial]
@init {
bool isToString = false;
bool isEquals = false;
@ -1247,14 +1406,17 @@ method_declaration [CommonTree atts, CommonTree mods, List<string> modList, Comm
}
exceptions = IsJavaish ? $throw_exceptions.tree : $b.exceptionList;
}
-> $mainMethod?
-> {!($isPartial && $b.isEmpty)}?
$mainMethod?
^(METHOD { dupTree($atts) } { dupTree($mods) } { dupTree($type) }
magicIdentifier type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? $b { exceptions });
magicIdentifier type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? $b { exceptions })
->
;
method_body [bool smotherExceptions] returns [CommonTree exceptionList]:
method_body [bool smotherExceptions] returns [CommonTree exceptionList, bool isEmpty]:
{smotherExceptions}? b=block nb=magicSmotherExceptions[dupTree($b.tree) ]
-> $nb
| b=block el=magicThrowsException[true,$b.tree.Token] { $exceptionList=$el.tree; }
| b=block el=magicThrowsException[true,$b.tree.Token] { $exceptionList=$el.tree; $isEmpty = $b.isEmpty; }
-> $b
;
@ -1328,7 +1490,7 @@ remove_accessor_declaration:
enum_declaration[CommonTree atts, CommonTree mods] returns [string name]
scope TypeContext;
:
e='enum' identifier { $name = $identifier.text; $TypeContext::typeName = $identifier.text; } enum_base? enum_body ';'?
e='enum' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } enum_base? enum_body ';'?
-> ^(ENUM[$e.token, "ENUM"] { dupTree($atts) } { dupTree($mods) } identifier enum_base? enum_body);
enum_base:
':' integral_type ;
@ -1404,7 +1566,7 @@ scope TypeContext;
$compUnits.Add(delName, dupTree($delegate_declaration.tree));
}
:
d='delegate' return_type identifier { delName = $identifier.text; $TypeContext::typeName = $identifier.text; } variant_generic_parameter_list? {ifTree = mkType($d.token, $identifier.tree, $variant_generic_parameter_list.tyargs); }
d='delegate' return_type identifier { delName = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } variant_generic_parameter_list? {ifTree = mkType($d.token, $identifier.tree, $variant_generic_parameter_list.tyargs); }
'(' formal_parameter_list? ')' type_parameter_constraints_clauses? ';'
magicDelegateInterface[$d.token, $return_type.tree, $identifier.tree, $formal_parameter_list.tree, $variant_generic_parameter_list.tyargs]
magicMultiInvokerMethod[$d.token, $return_type.tree, $return_type.thetext == "Void" || $return_type.thetext == "System.Void", ifTree, $formal_parameter_list.tree, mkArgsFromParams($d.token, $formal_parameter_list.tree), $variant_generic_parameter_list.tyargs]
@ -1415,14 +1577,14 @@ scope TypeContext;
AddToImports("java.util.ArrayList");
AddToImports("CS2JNet.JavaSupport.util.ListSupport");
}
magicMultiDelClass[$d.token, $atts, toplevel ? dupTree($mods) : addModifier($d.token, $mods, (CommonTree)adaptor.Create(STATIC, $d.token, "static")), multiDelName, ifTree, $type_parameter_constraints_clauses.tree, $variant_generic_parameter_list.tree, $magicMultiInvokerMethod.tree, delClassMemberNodes]
magicMultiDelClass[$d.token, $atts, toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $d.token, "static")), multiDelName, ifTree, $type_parameter_constraints_clauses.tree, $variant_generic_parameter_list.tree, $magicMultiInvokerMethod.tree, delClassMemberNodes]
{
$compUnits.Add(multiDelName, $magicMultiDelClass.tree);
}
->
// ^(DELEGATE[$d.token, "DELEGATE"] { dupTree($atts) } { dupTree($mods) } return_type identifier type_parameter_constraints_clauses? variant_generic_parameter_list?
// '(' formal_parameter_list? ')' );
^(INTERFACE[$d.token, "interface"] { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($d.token, $mods, (CommonTree)adaptor.Create(STATIC, $d.token, "static")) } identifier { dupTree($type_parameter_constraints_clauses.tree) } { dupTree($variant_generic_parameter_list.tree) } magicDelegateInterface)
^(INTERFACE[$d.token, "interface"] { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, $d.token, "static")) } identifier { dupTree($type_parameter_constraints_clauses.tree) } { dupTree($variant_generic_parameter_list.tree) } magicDelegateInterface)
;
delegate_modifiers:
modifier+ ;
@ -1505,7 +1667,7 @@ parameter_array:
interface_declaration[CommonTree atts, CommonTree mods] returns [string name]
scope TypeContext;
:
c='interface' identifier { $name = $identifier.text; $TypeContext::typeName = $identifier.text; } 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[$c.Token, "interface"] { dupTree($atts) } { dupTree($mods) } identifier type_parameter_constraints_clauses? variant_generic_parameter_list? interface_base? interface_body );
@ -1551,14 +1713,48 @@ interface_accessor_declaration [CommonTree atts, CommonTree mods, CommonTree typ
;
///////////////////////////////////////////////////////
struct_declaration[CommonTree atts, CommonTree mods, bool toplevel] returns [string name]
struct_declaration[CommonTree atts, CommonTree mods, bool toplevel, bool isPartial] returns [string name]
scope TypeContext;
@init {
$TypeContext::partialTypes = new Dictionary<String,ClassDescriptor>();
IToken endToken = null;
}
:
c='struct' identifier { $TypeContext::typeName = $identifier.text; } type_parameter_list? { $name = mkGenericTypeAlias($identifier.text, $type_parameter_list.names); } class_base? type_parameter_constraints_clauses? struct_body[$identifier.text] ';'?
-> ^(CLASS[$c.Token, "class"] { dupTree($atts) } { toplevel ? dupTree($mods) : addModifier($c.token, $mods, (CommonTree)adaptor.Create(STATIC, $c.token, "static")) } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? struct_body );
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) {
struct_body [string structName]:
o='{' magicDefaultConstructor[$o.token, structName] class_member_declarations? '}' ;
// 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) } '}'
-> '{' magicDefaultConstructor class_member_declarations? '}' ;
///////////////////////////////////////////////////////
@ -1702,7 +1898,7 @@ local_variable_declarators returns [List<string> variableNames]
}:
i1=local_variable_declarator { $variableNames.Add($i1.variableName); } (',' ip=local_variable_declarator { $variableNames.Add($ip.variableName); })* ;
local_variable_declarator returns [string variableName]:
identifier { $variableName = $identifier.text; } ('=' local_variable_initializer)? ;
identifier { $variableName = $identifier.thetext; } ('=' local_variable_initializer)? ;
local_variable_initializer:
expression
| array_initializer
@ -1867,10 +2063,11 @@ predefined_type returns [string thetext]
| 'ushort' { $thetext = "System.UInt16"; }
;
identifier
identifier returns [string thetext]
@after {
string fixedId = fixBrokenId($identifier.tree.Token.Text);
$identifier.tree.Token.Text = fixedId;
$thetext = $identifier.tree.Token.Text;
}:
IDENTIFIER | also_keyword;
@ -2155,3 +2352,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, "}"] );

View File

@ -25,9 +25,11 @@ options {
@members
{
public bool IsPartial { get; set; }
public bool IsLast { get; set; }
public int EmittedCommentTokenIdx { get; set; }
public ClassDescriptorSerialized PartialDescriptor { get; set; }
private List<string> collectedComments = null;
List<string> CollectedComments {
get {
@ -288,7 +290,9 @@ options {
return ret;
}
protected string mkString(object s) {
return (s == null ? String.Empty : s.ToString());
}
}
@ -297,14 +301,30 @@ public compilation_unit
initPrecedence();
}
:
^(PACKAGE nm=PAYLOAD imports? type_declaration { if (IsLast) collectComments(); }) ->
^(PACKAGE nm=PAYLOAD imports? type_declaration)
{
if (IsLast) collectComments();
if (IsPartial) {
// Merge into existing descriptor
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) {
if (!PartialDescriptor.Imports.Contains(m)) {
PartialDescriptor.Imports.Add(m);
}
}
}
}
}
->
package(now = {DateTime.Now}, includeDate = {Cfg.TranslatorAddTimeStamp}, packageName = {($nm.text != null && $nm.text.Length > 0 ? $nm.text : null)},
imports = {$imports.st},
type = {$type_declaration.st},
endComments = { CollectedComments });
type_declaration:
class_declaration -> { $class_declaration.st }
class_declaration[true] -> { $class_declaration.st }
| interface_declaration -> { $interface_declaration.st }
| enum_declaration -> { $enum_declaration.st }
| annotation_declaration -> { $annotation_declaration.st }
@ -315,21 +335,36 @@ qualified_identifier:
namespace_name
: namespace_or_type_name ;
modifiers:
ms+=modifier+ -> modifiers(mods={$ms});
modifier
modifiers returns [List<string> modList]
@init {
string thetext = null;
}
:
(m='new' | m='public' | m='protected' | m='private' | m='abstract' | m='sealed' | m='static'
| m='readonly' | m='volatile' | m='extern' { thetext = "/* [UNSUPPORTED] 'extern' modifier not supported */"; } | m='virtual' | m='override' | m=FINAL)
-> string(payload={ (thetext == null ? $m.text : thetext) });
$modList = new List<string>();
}:
(modifier { $modList.Add($modifier.thetext); })+ -> modifiers(mods={$modList});
imports:
imps+=importns+ -> seplist(items = { $imps }, sep= { "\n" });
importns:
IMPORT PAYLOAD -> import_template(ns = { $PAYLOAD.text });
modifier returns [string thetext]
:
(m='new' { $thetext = "new"; }
| m='public' { $thetext = "public"; }
| m='protected' { $thetext = "protected"; }
| m='private' { $thetext = "private"; }
| m='abstract' { $thetext = "abstract"; }
| m='sealed' { $thetext = "sealed"; }
| m='static' { $thetext = "static"; }
| m='readonly' { $thetext = "readonly"; }
| m='volatile' { $thetext = "volatile"; }
| m='extern' { $thetext = "/* [UNSUPPORTED] 'extern' modifier not supported */"; }
| m='virtual' { $thetext = "virtual"; }
| m='override' { $thetext = "override"; }
| m=FINAL{ $thetext = "final"; })
-> string(payload= { $thetext });
imports returns [List<string> importList]
@init {
$importList = new List<string>();
}:
(importns { $importList.Add($importns.thetext); })+ -> import_list(nss = { $importList });
importns returns [string thetext]:
IMPORT PAYLOAD { $thetext = $PAYLOAD.text; } -> import_template(ns = { $PAYLOAD.text });
class_member_declaration returns [List<string> preComments]:
^(CONST attributes? modifiers? type { $preComments = CollectedComments; } constant_declarators)
@ -338,7 +373,7 @@ class_member_declaration returns [List<string> preComments]:
{ $preComments = CollectedComments; } method_body exception*)
-> method(modifiers={$modifiers.st}, type={$type.st}, name={ $member_name.st }, typeparams = { $type_parameter_list.st }, params={ $formal_parameter_list.st }, exceptions = { $exception.st }, bodyIsSemi = { $method_body.isSemi }, body={ $method_body.st })
| interface_declaration -> { $interface_declaration.st }
| class_declaration -> { $class_declaration.st }
| class_declaration[false] -> { $class_declaration.st }
| ^(FIELD attributes? modifiers? type { $preComments = CollectedComments; } field_declaration) -> field(modifiers={$modifiers.st}, type={$type.st}, field={$field_declaration.st})
| ^(OPERATOR attributes? modifiers? type { $preComments = CollectedComments; } operator_declaration)
| enum_declaration -> { $enum_declaration.st }
@ -884,9 +919,9 @@ global_attribute_target_specifier:
global_attribute_target:
'assembly' | 'module' ;
attributes:
attribute_sections ;
attribute_sections -> { $attribute_sections.st } ;
attribute_sections:
attribute_section+ ;
ass+=attribute_section+ ;
attribute_section:
^(ATTRIBUTE attribute_target_specifier? attribute_list) ;
attribute_target_specifier:
@ -919,13 +954,58 @@ attribute_argument_expression:
// Class Section
///////////////////////////////////////////////////////
class_declaration
class_declaration[bool topLevel]
@init {
List<string> preComments = null;
}:
^(c=CLASS
^(c=CLASS PAYLOAD?
attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list[$type_parameter_constraints_clauses.tpConstraints]?
class_extends? class_implements? { preComments = CollectedComments; } class_body )
class_extends? class_implements? { preComments = CollectedComments; preComments.Add($PAYLOAD.text); } class_body )
{
if (IsPartial && topLevel) {
// Merge into existing descriptor
if (preComments != null) {
foreach (String comment in preComments) {
PartialDescriptor.Comments += comment ;
}
}
// Union all attributes
// we don't push through attributes yet
PartialDescriptor.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);
}
}
}
if (String.IsNullOrEmpty(PartialDescriptor.TypeParameterList)) {
PartialDescriptor.TypeParameterList = mkString($type_parameter_list.st);
}
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);
}
}
}
if (String.IsNullOrEmpty(PartialDescriptor.ClassBase)) {
PartialDescriptor.ClassBase = mkString($class_extends.st);
}
// Union the class bodies
PartialDescriptor.ClassBody += mkString($class_body.st);
}
}
-> 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}) ;
@ -942,10 +1022,13 @@ class_extends:
ts+=class_extend+ -> extends(types = { $ts }) ;
class_extend:
^(EXTENDS ts=type) -> { $ts.st } ;
class_implements:
ts+=class_implement+ -> imps(types = { $ts }) ;
class_implement:
^(IMPLEMENTS ts=type) -> { $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 returns [string implement]:
^(IMPLEMENTS ts=type) { $implement = $ts.st.ToString(); } -> { $ts.st };
interface_type_list:
ts+=type (',' ts+=type)* -> commalist(items={ $ts });

View File

@ -2212,7 +2212,7 @@ scope NSContext,SymTab;
$SymTab::symtab = new Dictionary<string, TypeRepTemplate>();
}
:
^(c=CLASS attributes? modifiers? identifier type_parameter_constraints_clauses?
^(c=CLASS 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 attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list? class_implements? class_body);
-> ^($c PAYLOAD? attributes? modifiers? identifier type_parameter_constraints_clauses? type_parameter_list? class_implements? class_body);
type_parameter_list returns [List<string> tyParams]
@init {
@ -2265,20 +2265,27 @@ type_parameter returns [string thetext]:
class_extends:
class_extend+ ;
class_extend:
^(EXTENDS type) ;
^(EXTENDS type);
// If first implements type is a class then convert to extends
class_implements returns [bool hasExtends, TypeRepTemplate extendDotNetType]:
class_implement_or_extend { $hasExtends = $class_implement_or_extend.hasExtends; $extendDotNetType = $class_implement_or_extend.extendDotNetType; }
class_implement* ;
class_implement_or_extend returns [bool hasExtends, TypeRepTemplate extendDotNetType]
class_implements returns [bool hasExtends, TypeRepTemplate extendDotNetType]
@init {
$hasExtends = false;
CommonTree extends = null;
}:
^(i=IMPLEMENTS t=type
{ if ($t.dotNetType is ClassRepTemplate) {
$hasExtends = true;
(class_implement_or_extend[extends == null] { if ($class_implement_or_extend.extends != null) {
extends = $class_implement_or_extend.extends;
$hasExtends = true;
$extendDotNetType = $class_implement_or_extend.extendDotNetType;
}})+
-> { extends } class_implement_or_extend*;
class_implement_or_extend[bool lookingForBase] returns [CommonTree extends, TypeRepTemplate extendDotNetType]
@init {
$extends = null;
}:
^(i=IMPLEMENTS t=type magicExtends[$lookingForBase && $t.dotNetType is ClassRepTemplate, $i.token, $t.tree]
{ if ($lookingForBase && $t.dotNetType is ClassRepTemplate) {
$extends = $magicExtends.tree;
$extendDotNetType = $t.dotNetType;
}
if($t.dotNetType.IsA(ICollectionType,AppEnv)) $NSContext::IsICollection = true;
@ -2287,19 +2294,9 @@ class_implement_or_extend returns [bool hasExtends, TypeRepTemplate extendDotNet
$NSContext::GenericICollectionTyVar = $t.dotNetType.TypeParams[0];
}
} )
-> { $t.dotNetType is ClassRepTemplate }? ^(EXTENDS[$i.token, "extends"] type)
-> { $lookingForBase && $t.dotNetType is ClassRepTemplate }?
-> ^($i $t);
class_implement:
^(IMPLEMENTS t=type
{
if($t.dotNetType.IsA(ICollectionType,AppEnv)) $NSContext::IsICollection = true;
if($t.dotNetType.IsA(GenericICollectionType,AppEnv) && $t.dotNetType.TypeParams.Length > 0) {
$NSContext::IsGenericICollection = true;
$NSContext::GenericICollectionTyVar = $t.dotNetType.TypeParams[0];
}
}) ;
class_body
@init {
CommonTree collectorNodes = null;
@ -3295,3 +3292,8 @@ magicTypeFromTemplate[bool isOn, IToken tok, TypeRepTemplate dotNetType]:
-> { $isOn }? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, $dotNetType.mkFormattedTypeName(false, "<",">")])
->
;
magicExtends[bool isOn, IToken tok, CommonTree type]:
-> { $isOn }? ^(EXTENDS[tok, "extends"] { dupTree($type) })
->
;