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

2460 lines
107 KiB
Plaintext

/*
Copyright 2010,2011 Kevin Glynn (kevin.glynn@twigletsoftware.com)
*/
// JavaMaker.g
//
// Convert C# parse tree to a Java parse tree
//
tree grammar JavaMaker;
options {
tokenVocab=cs;
ASTLabelType=CommonTree;
language=CSharp2;
superClass='Twiglet.CS2J.Translator.Transform.SyntaxFragments';
output=AST;
}
// A scope to keep track of the namespaces available at any point in the program
scope NSContext {
int filler;
string currentNS;
// namespaces in scope
List<string> namespaces;
// Alias map: these two lists are actually a map from alias to namespace
// so aliases[i] -> namespaces[i]
List<string> aliasKeys;
List<string> aliasNamespaces;
}
// A scope to keep track of the current type context
scope TypeContext {
string typeName;
}
@namespace { Twiglet.CS2J.Translator.Transform }
@header
{
using System;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
}
@members
{
// 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 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; }
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;
}
}
protected List<string> CollectSearchPath {
get {
List<string> ret = new List<string>();
Object[] nsCtxtArr = $NSContext.ToArray();
for (int i = nsCtxtArr.Length - 1; i >= 0; i--) {
foreach (string v in ((NSContext_scope)nsCtxtArr[i]).namespaces) {
ret.Add(v);
}
}
return ret;
}
}
protected List<string> CollectAliasKeys {
get {
List<string> ret = new List<string>();
Object[] nsCtxtArr = $NSContext.ToArray();
for (int i = nsCtxtArr.Length - 1; i >= 0; i--) {
foreach (string v in ((NSContext_scope)nsCtxtArr[i]).aliasKeys) {
ret.Add(v);
}
}
return ret;
}
}
protected List<string> CollectAliasNamespaces {
get {
List<string> ret = new List<string>();
Object[] nsCtxtArr = $NSContext.ToArray();
for (int i = nsCtxtArr.Length - 1; i >= 0; i--) {
foreach (string v in ((NSContext_scope)nsCtxtArr[i]).aliasNamespaces) {
ret.Add(v);
}
}
return ret;
}
}
// TREE CONSTRUCTION
protected CommonTree mkPayloadList(List<string> payloads) {
CommonTree root = (CommonTree)adaptor.Nil;
foreach (string p in payloads) {
adaptor.AddChild(root, (CommonTree)adaptor.Create(PAYLOAD, p));
}
return root;
}
protected CommonTree mangleModifiersForType(CommonTree modifiers) {
if (modifiers == null || modifiers.Children == null)
return modifiers;
CommonTree stripped = (CommonTree)modifiers.DupNode();
for (int i = 0; i < modifiers.Children.Count; i++) {
if (((CommonTree)modifiers.Children[i]).Token.Text != "static") {
adaptor.AddChild(stripped, modifiers.Children[i]);
}
}
return stripped;
}
protected CommonTree addConstModifiers(IToken tok, List<string> filter) {
CommonTree root = (CommonTree)adaptor.Nil;
if (filter == null || !filter.Contains("static") )
{
adaptor.AddChild(root, (CommonTree)adaptor.Create(STATIC, tok, "static"));
}
if (filter == null || !filter.Contains("final"))
{
adaptor.AddChild(root, (CommonTree)adaptor.Create(FINAL, tok, "final"));
}
root = (CommonTree)adaptor.RulePostProcessing(root);
return root;
}
// We expect mods to be
// null, or
// a single token, or
// a list of tokens (^(NIL ......))
protected CommonTree addModifier(CommonTree mods, CommonTree modToAdd) {
CommonTree root = (CommonTree)adaptor.Nil;
bool modSeen = false;
if (mods != null) {
// Is root node the one we are looking for?
if (!mods.IsNil) {
if (adaptor.GetType(mods) == adaptor.GetType(modToAdd) && adaptor.GetText(mods) == adaptor.GetText(modToAdd)) {
modSeen = true;
}
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(mods));
}
else {
for (int i = 0; i < adaptor.GetChildCount(mods); i++) {
CommonTree child = (CommonTree)adaptor.GetChild(mods,i);
if (adaptor.GetType(child) == adaptor.GetType(modToAdd) && adaptor.GetText(child) == adaptor.GetText(modToAdd)) {
modSeen = true;
}
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(child));
}
}
}
if (!modSeen) {
adaptor.AddChild(root, modToAdd);
}
root = (CommonTree)adaptor.RulePostProcessing(root);
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) {
CommonTree root = (CommonTree)adaptor.Nil;
if (mods != null) {
// Is root node the one we are looking for?
if (!mods.IsNil) {
if (Array.IndexOf(removes,adaptor.GetType(mods)) < 0) {
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(mods));
}
}
else {
for (int i = 0; i < adaptor.GetChildCount(mods); i++) {
CommonTree child = (CommonTree)adaptor.GetChild(mods,i);
if (Array.IndexOf(removes,adaptor.GetType(child)) < 0) {
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(child));
}
}
}
}
root = (CommonTree)adaptor.RulePostProcessing(root);
return root;
}
// mods is a list of modifiers. contains is a list of token types, return true if mods has a member of contains
protected bool containsMods(CommonTree mods, int[] contains) {
bool ret = false;
if (mods != null) {
// Is root node the one we are looking for?
if (!mods.IsNil) {
if (Array.IndexOf(contains,adaptor.GetType(mods)) >= 0) {
ret = true;
}
}
else {
for (int i = 0; i < adaptor.GetChildCount(mods); i++) {
CommonTree child = (CommonTree)adaptor.GetChild(mods,i);
if (Array.IndexOf(contains,adaptor.GetType(child)) >= 0) {
ret = true;
break;
}
}
}
}
return ret;
}
// Add modToAdd to mods.
protected CommonTree mkAddMod(CommonTree mods, CommonTree modToAdd) {
CommonTree root = (CommonTree)adaptor.Nil;
if (mods == null) {
root = modToAdd;
}
else {
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(modToAdd));
adaptor.AddChild(root, (CommonTree)adaptor.DupTree(mods));
}
root = (CommonTree)adaptor.RulePostProcessing(root);
return root;
}
protected CommonTree mkPrivateMod(CommonTree mods, IToken tok) {
return mkAddMod(mkRemoveMods(mods, new int[] {PUBLIC, PROTECTED, INTERNAL, PRIVATE}), (CommonTree)adaptor.Create(PRIVATE, tok, "private"));
}
// embedded statement is ";", or, "{" ... "}", or a single statement. In the latter case we wrap with braces
protected CommonTree embeddedStatementToBlock(IToken tok, CommonTree embedStat) {
if ((!embedStat.IsNil && adaptor.GetType(embedStat) == SEMI) ||
(embedStat.IsNil && adaptor.GetChildCount(embedStat) >= 1 && adaptor.GetType(embedStat) == SEMI)) {
// Do Nothing, already a block
return embedStat;
}
CommonTree root = (CommonTree)adaptor.Nil;
adaptor.AddChild(root, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{"));
adaptor.AddChild(root, dupTree(embedStat));
adaptor.AddChild(root, (CommonTree)adaptor.Create(CLOSE_BRACE, tok, "}"));
root = (CommonTree)adaptor.RulePostProcessing(root);
return root;
}
protected CommonTree mkGenericArgs(IToken tok, List<string> tyVars) {
if (tyVars == null || tyVars.Count == 0) {
return null;
}
CommonTree root = (CommonTree)adaptor.Nil;
adaptor.AddChild(root, (CommonTree)adaptor.Create(LTHAN, tok, "<"));
bool isFirst = true;
foreach (string v in tyVars) {
if (!isFirst) {
adaptor.AddChild(root, (CommonTree)adaptor.Create(COMMA, tok, ","));
}
isFirst = false;
CommonTree ty = (CommonTree)adaptor.Nil;
ty = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), ty);
adaptor.AddChild(ty, (CommonTree)adaptor.Create(IDENTIFIER, tok, v));
adaptor.AddChild(root, ty);
}
adaptor.AddChild(root, (CommonTree)adaptor.Create(GT, tok, ">"));
return root;
}
protected CommonTree mkPackage(IToken tok, CommonTree tree, String nameSpace) {
CommonTree root = (CommonTree)adaptor.Nil;
root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(PACKAGE, tok, "package"), root);
adaptor.AddChild(root, (CommonTree)adaptor.Create(PAYLOAD, tok, nameSpace));
adaptor.AddChild(root, dupTree(tree));
return root;
}
protected CommonTree mkFlattenDictionary(IToken tok, Dictionary<string,CommonTree> treeDict) {
CommonTree root = (CommonTree)adaptor.Nil;
foreach (CommonTree tree in treeDict.Values) {
if (tree != null) {
adaptor.AddChild(root, dupTree(tree));
}
}
root = (CommonTree)adaptor.RulePostProcessing(root);
return root;
}
protected CommonTree mkArgsFromParams(IToken tok, CommonTree pars) {
CommonTree root = (CommonTree)adaptor.Nil;
if (adaptor.GetChildCount(pars) > 0) {
root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(ARGS, tok, "ARGS"), root);
// strip all TYPES and Attributes (there may be parameter modifiers like ref, out ...
for (int i = 0; i < adaptor.GetChildCount(pars); i++) {
if (((CommonTree)adaptor.GetChild(pars, i)).Token.Type != TYPE && ((CommonTree)adaptor.GetChild(pars, i)).Token.Type != ATTRIBUTE) {
adaptor.AddChild(root, dupTree((CommonTree)adaptor.GetChild(pars, i)));
}
}
}
root = (CommonTree)adaptor.RulePostProcessing(root);
return root;
}
protected CommonTree mkType(IToken tok, CommonTree id, List<String> tyVars) {
CommonTree root = (CommonTree)adaptor.Nil;
root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), root);
adaptor.AddChild(root, dupTree(id));
if (tyVars != null && tyVars.Count > 0) {
adaptor.AddChild(root, mkGenericArgs(tok, tyVars));
}
return root;
}
protected string mkTypeString(string tyName, List<String> tyargs) {
StringBuilder ty = new StringBuilder();
ty.Append(tyName);
ty.Append(mkTypeArgString(tyargs));
return ty.ToString();
}
protected string mkTypeArgString(List<String> tyargs) {
StringBuilder ty = new StringBuilder();
if (tyargs != null && tyargs.Count > 0) {
ty.Append("<");
bool isFirst = true;
foreach (String v in tyargs) {
if (!isFirst) {
ty.Append(",");
}
isFirst = false;
ty.Append(v);
}
ty.Append(">");
}
return ty.ToString();
}
// for ["conn", "conn1", "conn2"] generate:
//
// if (conn != null)
// Disposable.mkDisposable(conn).Dispose();
//
//
// if (conn2 != null)
// Disposable.mkDisposable(conn2).Dispose();
//
//
// if (conn3 != null)
// Disposable.mkDisposable(conn3).Dispose();
// used in the finally block of the using translation
protected CommonTree addDisposeVars(IToken tok, List<string> vars, string disposeMethod) {
CommonTree root = (CommonTree)adaptor.Nil;
foreach (string var in vars) {
CommonTree root_1 = (CommonTree)adaptor.Nil;
root_1 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(IF, tok, "if"), root_1);
CommonTree root_2 = (CommonTree)adaptor.Nil;
root_2 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(NOT_EQUAL, tok, "!="), root_2);
adaptor.AddChild(root_2, (CommonTree)adaptor.Create(IDENTIFIER, tok, var));
adaptor.AddChild(root_2, (CommonTree)adaptor.Create(NULL, tok, "null"));
adaptor.AddChild(root_1, root_2);
adaptor.AddChild(root_1, (CommonTree)adaptor.Create(SEP, "SEP"));
// Disposable.mkDisposable(var).Dispose()
root_2 = (CommonTree)adaptor.Nil;
root_2 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(APPLY, tok, "APPLY"), root_2);
// Disposable.mkDisposable(var).Dispose
CommonTree root_3 = (CommonTree)adaptor.Nil;
root_3 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(DOT, tok, "."), root_3);
// Disposable.mkDisposable(var)
CommonTree root_4 = (CommonTree)adaptor.Nil;
root_4 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(APPLY, tok, "APPLY"), root_4);
// Disposable.mkDisposable
CommonTree root_5 = (CommonTree)adaptor.Nil;
root_5 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(DOT, tok, "."), root_5);
adaptor.AddChild(root_5, (CommonTree)adaptor.Create(IDENTIFIER, tok, "Disposable"));
adaptor.AddChild(root_5, (CommonTree)adaptor.Create(IDENTIFIER, tok, "mkDisposable"));
CommonTree root_6 = (CommonTree)adaptor.Nil;
root_6 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(ARGS, tok, "ARGS"), root_6);
adaptor.AddChild(root_6, (CommonTree)adaptor.Create(IDENTIFIER, tok, var));
adaptor.AddChild(root_4, root_5);
adaptor.AddChild(root_4, root_6);
adaptor.AddChild(root_3, root_4);
adaptor.AddChild(root_3, (CommonTree)adaptor.Create(IDENTIFIER, tok, disposeMethod));
adaptor.AddChild(root_2, root_3);
adaptor.AddChild(root_1, root_2);
adaptor.AddChild(root_1, (CommonTree)adaptor.Create(SEMI, tok, ";"));
adaptor.AddChild(root, root_1);
}
return (CommonTree)adaptor.RulePostProcessing(root);
}
// TODO: Read reserved words from a file so that they can be extended by customer
private readonly static string[] javaReserved = new string[] { "int", "protected", "package" };
protected string fixBrokenId(string id)
{
// Console.WriteLine(id);
foreach (string k in javaReserved)
{
if (k == id)
{
return "__" + id;
}
}
return id;
}
// Map of C# built in types to Java equivalents
Dictionary<string, string> predefined_type_map = new Dictionary<string, string>()
{
{"bool", "boolean"},
{"decimal", "double"},
{"object", "Object"},
{"string", "String"}
};
Dictionary<string, string> predefined_unsigned_type_map = new Dictionary<string, string>()
{
{"uint", "int"},
{"ulong", "long"},
{"ushort", "short"}
};
Dictionary<string, string> predefined_embiggen_unsigned_type_map = new Dictionary<string, string>()
{
{"byte", "short"},
{"ushort", "int"},
{"uint", "long"},
{"ulong", "long"}
};
protected CommonTree mkHole() {
return mkHole(null);
}
protected CommonTree mkHole(IToken tok) {
return (CommonTree)adaptor.Create(KGHOLE, tok, "KGHOLE");
}
// counter to ensure that the catch vars we introduce are unique
protected int dummyCatchVarCtr = 0;
protected int newVarCtr = 0;
protected CommonTree dupTree(CommonTree t) {
return (CommonTree)adaptor.DupTree(t);
}
protected string mkTypeOrGenericString(string type, List<string> generic_arguments) {
StringBuilder ret = new StringBuilder();
ret.Append(type);
if (generic_arguments != null && generic_arguments.Count > 0) {
bool first = true;
ret.Append("<");
foreach (string a in generic_arguments) {
if (!first)
ret.Append(",");
ret.Append(a);
first = false;
}
ret.Append(">");
}
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]);
// }
// }
// }
// }
//
}
/********************************************************************************************
Parser section
*********************************************************************************************/
///////////////////////////////////////////////////////
public compilation_unit
scope NSContext, TypeContext;
@init {
$NSContext::currentNS = "";
$NSContext::namespaces = new List<string>();
$NSContext::aliasKeys = new List<string>();
$NSContext::aliasNamespaces = new List<string>();
$TypeContext::typeName = null;
}
:
namespace_body;
namespace_declaration
scope NSContext;
@init {
$NSContext::currentNS = "";
$NSContext::namespaces = new List<string>();
$NSContext::aliasKeys = new List<string>();
$NSContext::aliasNamespaces = new List<string>();
}:
'namespace' qi=qualified_identifier
{
// extend parent namespace
$NSContext::currentNS = this.ParentNameSpace + $qi.thetext;
$NSContext::namespaces.Add($NSContext::currentNS);
}
namespace_block ';'? ;
namespace_block:
'{' namespace_body '}' ;
namespace_body:
extern_alias_directives? using_directives? global_attributes? namespace_member_declarations? ;
extern_alias_directives:
extern_alias_directive+ ;
extern_alias_directive:
e='extern' 'alias' i=identifier ';' { Warning($e.line, "[UNSUPPORTED] External Alias " + $i.text); } ;
using_directives:
using_directive+ ;
using_directive:
(using_alias_directive
| using_namespace_directive) ;
using_alias_directive:
'using' identifier '=' namespace_or_type_name ';'
{$NSContext::aliasKeys.Add($identifier.text);$NSContext::aliasNamespaces.Add($namespace_or_type_name.thetext); } ;
using_namespace_directive:
'using' namespace_name ';' {$NSContext::namespaces.Add($namespace_name.thetext); };
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;
}
@after {
if (isCompUnit) {
foreach (KeyValuePair<String, CommonTree> treeEntry in $ty.compUnits) {
if (treeEntry.Value != null) {
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(fqn, new CUnit(mkPackage(treeEntry.Value.Token, treeEntry.Value, ns),CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces, $ty.isPartial));
CUKeys.Add(fqn);
}
}
}
}
}:
namespace_declaration
| attributes? { atts = dupTree($attributes.tree); } modifiers? { mods = dupTree($modifiers.tree); } ty=type_declaration[atts, mangleModifiersForType(mods)] { isCompUnit = true; }
;
// type_declaration is only called at the top level, so each of the types declared
// here will become a Java compilation unit (and go to its own file)
type_declaration[CommonTree atts, CommonTree mods] returns [Dictionary<String,CommonTree> compUnits, bool isPartial]
@init {
$compUnits = new Dictionary<String,CommonTree>();
$isPartial = false;
}
:
('partial') => p='partial' { $isPartial = true; }
(pc=class_declaration[$atts, $mods, $p, true /* toplevel */] { $compUnits.Add($pc.name, $pc.tree); }
| ps=struct_declaration[$atts, $mods, $p, true /* toplevel */] { $compUnits.Add($ps.name, $ps.tree); }
| pi=interface_declaration[$atts, $mods, $p] { $compUnits.Add($pi.name, $pi.tree); } )
| c=class_declaration[$atts, $mods, null, true /* toplevel */] { $compUnits.Add($c.name, $c.tree); }
| s=struct_declaration[$atts, $mods, null, true /* toplevel */] { $compUnits.Add($s.name, $s.tree); }
| i=interface_declaration[$atts, $mods, null] { $compUnits.Add($i.name, $i.tree); }
| e=enum_declaration[$atts, $mods] { $compUnits.Add($e.name, $e.tree); }
| d=delegate_declaration[$atts, $mods, true /* toplevel */] { $compUnits = $d.compUnits; }
;
// Identifiers
qualified_identifier returns [string thetext]:
i1=identifier { $thetext = $i1.text; } ('.' ip=identifier { $thetext += "." + $ip.text; } )*;
namespace_name returns [string thetext]
: namespace_or_type_name { $thetext = $namespace_or_type_name.thetext; };
modifiers returns [List<string> modList]
@init {
$modList = new List<string>();
}:
(modifier { if ($modifier.tree != null) $modList.Add( $modifier.tree.Text); })+ ;
modifier:
'new' -> /* No new in Java*/ | 'public' | 'protected' | 'private' | i='internal' -> PUBLIC[$i.token, "public"] /* translate to public .... */| 'unsafe' -> | 'abstract' | s='sealed' -> FINAL[$s.token, "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
@init {
List<string> modifierList = new List<string>();
}:
a=attributes?
(m=modifiers { modifierList = $m.modList; })?
( c='const' ct=type constant_declarators ';' -> ^(FIELD[$c.token, "FIELD"] $a? $m? { addConstModifiers($c.token, modifierList) } $ct constant_declarators)
| ev=event_declaration[$a.tree, $m.tree] -> $ev
| p='partial' (v1=void_type m3=method_declaration[$a.tree, $m.tree, modifierList, $v1.tree, $v1.text, true /* isPartial */] -> { $m3.tree != null}? $m3
->
| pi=interface_declaration[$a.tree, $m.tree, $p] -> $pi
| pc=class_declaration[$a.tree, $m.tree, $p, false /* toplevel */] -> $pc
| ps=struct_declaration[$a.tree, $m.tree, $p, false /* toplevel */] -> $ps)
| i=interface_declaration[$a.tree, $m.tree, null] -> $i
| v2=void_type m1=method_declaration[$a.tree, $m.tree, modifierList, $v2.tree, $v2.text, false /* isPartial */] -> $m1
| t=type ( (member_name type_parameter_list? '(') => m2=method_declaration[$a.tree, $m.tree, modifierList, $t.tree, $t.text, false /* isPartial */] -> $m2
| (member_name '{') => pd=property_declaration[$a.tree, $m.tree, modifierList.Contains("abstract"), $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
| field_declaration -> ^(FIELD[$t.start.Token, "FIELD"] $a? $m? $t field_declaration) // qid
| operator_declaration -> ^(OPERATOR[$t.start.Token, "OPERATOR"] $a? $m? $t operator_declaration)
)
// common_modifiers// (method_modifiers | field_modifiers)
| cd=class_declaration[$a.tree, $m.tree, null, false /* toplevel */] -> $cd
| sd=struct_declaration[$a.tree, $m.tree, null, false /* toplevel */] -> $sd
| ed=enum_declaration[$a.tree, $m.tree] -> $ed
| dd=delegate_declaration[$a.tree, $m.tree, false /* toplevel */] -> { mkFlattenDictionary($dd.tree.Token,$dd.compUnits) }
| co3=conversion_operator_declaration -> ^(CONVERSION_OPERATOR[$co3.start.Token, "CONVERSION"] $a? $m? $co3)
| con3=constructor_declaration[$a.tree, $m.tree, modifierList] -> $con3
| de3=destructor_declaration -> $de3
)
;
primary_expression:
('this' brackets[null]) => (t='this' -> $t) (b1=brackets[$primary_expression.tree] -> $b1) (pp1=primary_expression_part[$primary_expression.tree] -> $pp1) *
| ('base' brackets[null]) => (b='base' -> SUPER[$b.token, "super"]) (b2=brackets[$primary_expression.tree] -> $b2) (pp2=primary_expression_part[$primary_expression.tree] -> $pp2) *
| (primary_expression_start -> primary_expression_start) (pp3=primary_expression_part[$primary_expression.tree] -> $pp3 )*
// keving:TODO fixup
| 'new' ( (object_creation_expression ('.'|'->'|'[')) =>
(oc1=object_creation_expression -> $oc1) (pp4=primary_expression_part[ $primary_expression.tree ] -> $pp4 )+ // new Foo(arg, arg).Member
| (object_creation_expression) => oc2=object_creation_expression -> $oc2
// | delegate_creation_expression -> delegate_creation_expression // new FooDelegate (MyFunction)
| anonymous_object_creation_expression -> anonymous_object_creation_expression) // new {int X, string Y}
| sizeof_expression // sizeof (struct)
| checked_expression // checked (...
| unchecked_expression // unchecked {...}
| default_value_expression // default
| anonymous_method_expression // delegate (int foo) {}
;
primary_expression_start:
predefined_type
| (identifier generic_argument_list) => identifier generic_argument_list
| identifier ((c='::'^ identifier { Warning($c.line, "[UNSUPPORTED] external aliases are not yet supported"); })?)!
| 'this'
| b='base' -> SUPER[$b.token, "super"]
| paren_expression
| typeof_expression // typeof(Foo).Name
| literal
;
primary_expression_part [CommonTree lhs]:
access_identifier[$lhs]
| brackets_or_arguments[$lhs]
| p='++' -> ^(POSTINC[$p.token, "++"] { dupTree($lhs) } )
| m='--' -> ^(POSTDEC[$m.token, "--"] { dupTree($lhs) } )
;
access_identifier [CommonTree lhs]:
access_operator type_or_generic -> ^(access_operator { dupTree($lhs) } type_or_generic);
access_operator:
'.' | '->' ;
brackets_or_arguments [CommonTree lhs]:
brackets[$lhs] | arguments[$lhs] ;
brackets [CommonTree lhs]:
'[' expression_list? ']' -> ^(INDEX { dupTree($lhs) } expression_list?);
paren_expression:
'(' expression ')' -> ^(PARENS expression);
arguments [CommonTree lhs]:
'(' argument_list? ')' -> ^(APPLY { dupTree($lhs) } argument_list?);
argument_list:
a1=argument (',' an+=argument)* -> ^(ARGS[$a1.start.Token,"ARGS"] $a1 $an*);
// 4.0
argument:
argument_name argument_value
| argument_value;
argument_name:
identifier ':';
argument_value:
expression
| ref_variable_reference
| 'out' variable_reference ;
ref_variable_reference:
'ref'
(('(' type ')') => '(' type ')' (ref_variable_reference | variable_reference) // SomeFunc(ref (int) ref foo)
// SomeFunc(ref (int) foo)
| variable_reference); // SomeFunc(ref foo)
// lvalue
variable_reference:
expression;
rank_specifiers:
rank_specifier+ ;
// convert dimension separators into additional dimensions, so [,,] -> [] [] []
rank_specifier:
o='[' dim_separators? c=']' -> $o $c dim_separators?;
dim_separators
@init {
CommonTree ret = (CommonTree)adaptor.Nil;
}
@after {
$dim_separators.tree = ret;
}:
(c=',' { adaptor.AddChild(ret, adaptor.Create(OPEN_BRACKET, $c.token, "["));adaptor.AddChild(ret, adaptor.Create(CLOSE_BRACKET, $c.token, "]")); })+ -> ;
delegate_creation_expression:
// 'new'
t1=type_name '(' t2=type_name ')' -> ^(NEW_DELEGATE[$t1.start.Token, "new(delegate)"] ^(TYPE[$t1.start.Token, "TYPE"] $t1) ^(ARGS[$t2.start.Token, "ARGS"] $t2));
anonymous_object_creation_expression:
// 'new'
i=anonymous_object_initializer -> ^(NEW_ANON_OBJECT[$i.tree.Token, "new(anonobj)"] anonymous_object_initializer);
anonymous_object_initializer:
'{' (member_declarator_list ','?)? '}';
member_declarator_list:
member_declarator (',' member_declarator)* ;
member_declarator:
qid ('=' expression)? ;
primary_or_array_creation_expression:
(array_creation_expression) => array_creation_expression
| primary_expression
;
// new Type[2] { }
array_creation_expression
@init {
bool removeDimensions = false;
CommonTree ret = null;
}
@after {
if (ret != null)
$array_creation_expression.tree = (CommonTree)adaptor.RulePostProcessing(ret);
if (removeDimensions) {
if ($array_creation_expression.tree != null &&
adaptor.GetChildCount($array_creation_expression.tree) > 3 &&
adaptor.GetType(adaptor.GetChild($array_creation_expression.tree, 1)) == OPEN_BRACKET) {
// Delete until CLOSE_BRACKET
while (adaptor.GetType(adaptor.GetChild($array_creation_expression.tree, 2)) != CLOSE_BRACKET) {
adaptor.DeleteChild($array_creation_expression.tree, 2);
}
// push open / close bracket into type.
CommonTree type = (CommonTree)adaptor.GetChild($array_creation_expression.tree, 0);
adaptor.AddChild(type, adaptor.DupTree(adaptor.GetChild($array_creation_expression.tree, 1)));
adaptor.AddChild(type, adaptor.DupTree(adaptor.GetChild($array_creation_expression.tree, 2)));
adaptor.DeleteChild($array_creation_expression.tree, 2);
adaptor.DeleteChild($array_creation_expression.tree, 1);
}
}
}:
n=NEW_ARRAY
(type ((o='[' expression_list c=']' -> ^($n type $o expression_list $c)) { ret = (CommonTree)adaptor.RulePostProcessing($array_creation_expression.tree); }
( (rank_specifiers { adaptor.AddChild(ret, $rank_specifiers.tree); })?
(ai1=array_initializer { adaptor.AddChild(ret, $ai1.tree);
removeDimensions = true; /* If an initializer is provided then drop the dimensions */} )? // new int[4]
// | invocation_part*
| ( ((arguments[null] ('['|'.'|'->')) => as1=arguments[ ret ] ip=invocation_part[ $as1.tree ] { ret = $ip.tree; })// new object[2].GetEnumerator()
| ip2=invocation_part[ret] { ret = $ip2.tree; })* as2=arguments[ ret ] { ret = $as2.tree; }
) // new int[4]()
| array_initializer -> ^($n type array_initializer)
)
| (rank_specifier // [,]
(array_initializer // var a = new[] { 1, 10, 100, 1000 }; // int[]
) -> ^($n rank_specifier array_initializer)) { ret = (CommonTree)adaptor.RulePostProcessing($array_creation_expression.tree); }
( // optionally invoke methods/index array
( ((arguments[null] ('['|'.'|'->')) => as3=arguments[ret] ip3=invocation_part[$as3.tree] { ret = $ip3.tree; })// new object[2].GetEnumerator()
| ip4=invocation_part[ret] { ret = $ip4.tree; })* as4=arguments[ret] {ret = $as4.tree; }
)?
) ;
array_initializer:
'{' variable_initializer_list? ','? '}' ;
variable_initializer_list:
variable_initializer (',' variable_initializer)* ;
variable_initializer:
expression | array_initializer ;
sizeof_expression:
'sizeof'^ '('! unmanaged_type ')'!;
checked_expression:
'checked'^ '('! expression ')'! ;
unchecked_expression:
'unchecked'^ '('! expression ')'! ;
default_value_expression:
'default'^ '('! type ')'! ;
anonymous_method_expression:
'delegate'^ explicit_anonymous_function_signature? block;
explicit_anonymous_function_signature:
'(' explicit_anonymous_function_parameter_list? ')'
-> {$explicit_anonymous_function_parameter_list.tree != null}? ^(PARAMS explicit_anonymous_function_parameter_list?)
->
;
explicit_anonymous_function_parameter_list:
explicit_anonymous_function_parameter (','! explicit_anonymous_function_parameter)* ;
explicit_anonymous_function_parameter:
anonymous_function_parameter_modifier? type identifier;
anonymous_function_parameter_modifier:
'ref' | 'out';
///////////////////////////////////////////////////////
object_creation_expression:
// 'new'
type
( '(' argument_list? ')' o1=object_or_collection_initializer? -> ^(NEW[$type.start.Token, "new"] type argument_list? $o1?)
| o2=object_or_collection_initializer -> ^(NEW[$type.start.Token, "new"] type $o2))
;
object_or_collection_initializer:
'{' (object_initializer
| collection_initializer) ;
collection_initializer:
element_initializer_list ','? '}' ;
element_initializer_list:
element_initializer (',' element_initializer)* ;
element_initializer:
non_assignment_expression
| '{' expression_list '}' ;
// object-initializer eg's
// Rectangle r = new Rectangle {
// P1 = new Point { X = 0, Y = 1 },
// P2 = new Point { X = 2, Y = 3 }
// };
// TODO: comma should only follow a member_initializer_list
object_initializer:
member_initializer_list? ','? '}' ;
member_initializer_list:
member_initializer (',' member_initializer)* ;
member_initializer:
identifier '=' initializer_value ;
initializer_value:
expression
| object_or_collection_initializer ;
///////////////////////////////////////////////////////
typeof_expression:
'typeof'^ '('! ((unbound_type_name) => unbound_type_name
| type
| void_type) ')'! ;
// unbound type examples
//foo<bar<X<>>>
//bar::foo<>
//foo1::foo2.foo3<,,>
unbound_type_name: // qualified_identifier v2
// unbound_type_name_start unbound_type_name_part* ;
unbound_type_name_start
(((generic_dimension_specifier '.') => generic_dimension_specifier unbound_type_name_part)
| unbound_type_name_part)*
generic_dimension_specifier
;
unbound_type_name_start:
identifier ('::' identifier)?;
unbound_type_name_part:
'.' identifier;
generic_dimension_specifier:
'<' commas? '>' ;
commas:
','+ ;
///////////////////////////////////////////////////////
// Type Section
///////////////////////////////////////////////////////
type_name returns [string thetext]:
namespace_or_type_name { $thetext = $namespace_or_type_name.thetext; };
namespace_or_type_name returns [string thetext]:
t1=type_or_generic { $thetext=t1.type+formatTyargs($t1.generic_arguments); } ('::'^ tc=type_or_generic { $thetext+="::"+tc.type+formatTyargs($tc.generic_arguments); })? ('.'^ tn=type_or_generic { $thetext+="."+tn.type+formatTyargs($tn.generic_arguments); } )* ;
type_or_generic returns [string type, List<string> generic_arguments]
@init {
$generic_arguments = new List<string>();
}
@after{
$type = $t.text;
}:
(identifier generic_argument_list) => t=identifier ga=generic_argument_list { $generic_arguments = $ga.tyargs; }
| t=identifier ;
// keving: as far as I can see this is (<interfacename>.)?identifier (<tyargs>)? at lease for C# 3.0 and less.
qid returns [string name, List<string> tyargs]: // qualified_identifier v2
(qs=qid_start -> $qs) (qp=qid_part[$qid.tree] -> $qp)* { $name=$qid_start.name; $tyargs = $qid_start.tyargs; }
;
qid_start returns [string name, List<string> tyargs]:
predefined_type { $name = $predefined_type.thetext; }
| (identifier generic_argument_list) => identifier generic_argument_list { $name = $identifier.text; $tyargs = $generic_argument_list.tyargs; }
// | 'this'
// | 'base'
| i1=identifier { $name = $i1.text; } ('::' inext=identifier { $name+="::" + $inext.text; })?
| literal { $name = $literal.text; }
; // 0.ToString() is legal
qid_part[CommonTree lhs]:
access_identifier[ $lhs ] ;
generic_argument_list returns [List<string> tyargs]
@after {
$tyargs = $ta.tyargs;
}
:
'<' ta=type_arguments '>' ;
type_arguments returns [List<string> tyargs]
@init {
$tyargs = new List<string>();
}
:
t1=type_argument { $tyargs.Add($t1.thetext); } (',' tn=type_argument { $tyargs.Add($tn.thetext); })* ;
public type_argument returns [string thetext]:
{this.IsJavaish}?=> javaish_type_argument {$thetext = $javaish_type_argument.thetext; }
| type {$thetext = $type.thetext; }
;
public javaish_type_argument returns [string thetext]:
('?' 'extends')=> '?' 'extends' type {$thetext = "? extends " + $type.thetext; }
| '?' {$thetext = "?"; }
| type {$thetext = $type.thetext; }
;
type returns [string thetext]:
((predefined_type | type_name) rank_specifiers) => (p1=predefined_type { $thetext = $p1.thetext; } | tn1=type_name { $thetext = $tn1.thetext; }) rs=rank_specifiers { $thetext += $rs.text; } ('*' { $thetext += "*"; })* -> ^(TYPE $p1? $tn1? $rs '*'*)
| ((predefined_type | type_name) ('*'+ | '?')) => (p2=predefined_type { $thetext = $p2.thetext; } | tn2=type_name { $thetext = $tn2.thetext; }) (('*' { $thetext += "*"; })+ | o2='?' { $thetext += "?"; }) -> ^(TYPE $p2? $tn2? '*'* $o2?)
| (p3=predefined_type { $thetext = $p3.thetext; } | tn3=type_name { $thetext = $tn3.thetext; }) -> ^(TYPE $p3? $tn3?)
| v='void' { $thetext = "System.Void"; } ('*' { $thetext += "*"; })+ -> ^(TYPE[$v.token, "TYPE"] $v '*'+)
;
non_nullable_type:
(p=predefined_type | t=type_name) rs=rank_specifiers? '*'* -> ^(TYPE["TYPE"] $p? $t? $rs? '*'*)
| v='void' '*'+ -> ^(TYPE[$v.token,"TYPE"] $v '*'+)
;
non_array_type:
type;
array_type:
type;
unmanaged_type:
type;
class_type:
type;
pointer_type:
type;
///////////////////////////////////////////////////////
// Statement Section
///////////////////////////////////////////////////////
block returns [bool isEmpty]:
';' { $isEmpty = true; }
| '{' statement_list? '}' { $isEmpty = false; };
statement_list:
statement[/* isStatementListCtxt */ true]+ ;
///////////////////////////////////////////////////////
// Expression Section
///////////////////////////////////////////////////////
expression:
(unary_expression assignment_operator) => assignment
| non_assignment_expression
;
expression_list:
expression (',' expression)* ;
assignment:
unary_expression assignment_operator expression ;
unary_expression:
//('(' arguments ')' ('[' | '.' | '(')) => primary_or_array_creation_expression
(cast_expression) => cast_expression
| primary_or_array_creation_expression -> primary_or_array_creation_expression
| p='+' unary_expression -> ^(MONOPLUS[$p.token,"+"] unary_expression)
| m='-' unary_expression -> ^(MONOMINUS[$m.token, "-"] unary_expression)
| n='!' unary_expression -> ^(MONONOT[$n.token, "!"] unary_expression)
| t='~' unary_expression -> ^(MONOTWIDDLE[$t.token, "~"] unary_expression)
| pre_increment_expression -> pre_increment_expression
| pre_decrement_expression -> pre_decrement_expression
| pointer_indirection_expression -> pointer_indirection_expression
| addressof_expression -> addressof_expression
;
cast_expression:
// //'(' type ')' unary_expression ;
l='(' type ')' unary_expression -> ^(CAST_EXPR[$l.token, "CAST"] type unary_expression);
assignment_operator:
'=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | r='>' '>=' -> RIGHT_SHIFT_ASSIGN[$r.token, ">>="] ;
pre_increment_expression:
s='++' unary_expression -> ^(PREINC[$s.token, "++"] unary_expression) ;
pre_decrement_expression:
s='--' unary_expression -> ^(PREDEC[$s.token, "--"] unary_expression);
pointer_indirection_expression:
s='*' unary_expression -> ^(MONOSTAR[$s.token, "*"] unary_expression);
addressof_expression:
a='&' unary_expression -> ^(ADDRESSOF[$a.token, "&"] unary_expression);
non_assignment_expression:
//'non ASSIGNment'
(anonymous_function_signature '=>') => lambda_expression
| (query_expression) => query_expression
| conditional_expression
;
///////////////////////////////////////////////////////
// Conditional Expression Section
///////////////////////////////////////////////////////
multiplicative_expression:
(u1=unary_expression -> $u1) ((op='*'|op='/'|op='%') un=unary_expression -> ^($op $multiplicative_expression $un) )* ;
additive_expression:
multiplicative_expression (('+'|'-')^ multiplicative_expression)* ;
// >> check needed (no whitespace)
shift_expression:
(a1=additive_expression -> $a1) ((so='<<' a3=additive_expression -> ^($so $shift_expression $a3))
| (r='>' '>' a2=additive_expression -> ^(RIGHT_SHIFT[$r.token, ">>"] $shift_expression $a2))
)* ;
relational_expression:
(s1=shift_expression -> $s1)
( ((o='<'|o='>'|o='>='|o='<=') s2=shift_expression -> ^($o $relational_expression $s2))
| (i='is' t=non_nullable_type -> ^(INSTANCEOF[$i.Token,"instanceof"] $relational_expression $t)
| i1='as' t1=non_nullable_type -> ^(COND_EXPR[$i1.Token, "?:"]
^(INSTANCEOF[$i1.Token,"instanceof"] { dupTree($s1.tree) } { dupTree($t1.tree) } )
^(CAST_EXPR[$i1.Token, "(cast)"] { dupTree($t1.tree) } { dupTree($s1.tree) })
^(CAST_EXPR[$i1.Token, "(cast)"] { dupTree($t1.tree) } NULL[$i1.Token, "null"])))
)* ;
equality_expression:
relational_expression
(('=='|'!=')^ relational_expression)* ;
and_expression:
equality_expression ('&'^ equality_expression)* ;
exclusive_or_expression:
and_expression ('^'^ and_expression)* ;
inclusive_or_expression:
exclusive_or_expression ('|'^ exclusive_or_expression)* ;
conditional_and_expression:
inclusive_or_expression ('&&'^ inclusive_or_expression)* ;
conditional_or_expression:
conditional_and_expression ('||'^ conditional_and_expression)* ;
null_coalescing_expression:
(e1=conditional_or_expression -> $e1) (qq='??' e2=conditional_or_expression -> ^(COND_EXPR[$qq.token, "?:"]
^(NOT_EQUAL[$qq.token, "!="] { dupTree($null_coalescing_expression.tree) } NULL[$qq.Token, "null"])
{ dupTree($null_coalescing_expression.tree) }
{ dupTree($e2.tree) })
)* ;
conditional_expression:
(ne=null_coalescing_expression -> $ne) (q='?' te=expression ':' ee=expression -> ^(COND_EXPR[$q.token, "?:"] $conditional_expression $te $ee))? ;
// (null_coalescing_expression '?' expression ':') => e1=null_coalescing_expression q='?' e2=expression ':' e3=expression -> ^(COND_EXPR[$q.token, "?:"] $e1 $e2 $e3)
// | null_coalescing_expression ;
///////////////////////////////////////////////////////
// lambda Section
///////////////////////////////////////////////////////
lambda_expression:
anonymous_function_signature '=>' anonymous_function_body;
anonymous_function_signature:
'(' (explicit_anonymous_function_parameter_list -> ^(PARAMS explicit_anonymous_function_parameter_list)
| implicit_anonymous_function_parameter_list -> ^(PARAMS_TYPELESS implicit_anonymous_function_parameter_list))? ')'
| implicit_anonymous_function_parameter_list -> ^(PARAMS_TYPELESS implicit_anonymous_function_parameter_list)
;
implicit_anonymous_function_parameter_list:
implicit_anonymous_function_parameter (','! implicit_anonymous_function_parameter)* ;
implicit_anonymous_function_parameter:
identifier;
anonymous_function_body:
expression
| block ;
///////////////////////////////////////////////////////
// LINQ Section
///////////////////////////////////////////////////////
query_expression:
from_clause query_body ;
query_body:
// match 'into' to closest query_body
query_body_clauses? select_or_group_clause (('into') => query_continuation)? ;
query_continuation:
'into' identifier query_body;
query_body_clauses:
query_body_clause+ ;
query_body_clause:
from_clause
| let_clause
| where_clause
| join_clause
| orderby_clause;
from_clause:
'from' type? identifier 'in' expression ;
join_clause:
'join' type? identifier 'in' expression 'on' expression 'equals' expression ('into' identifier)? ;
let_clause:
'let' identifier '=' expression;
orderby_clause:
'orderby' ordering_list ;
ordering_list:
ordering (',' ordering)* ;
ordering:
expression ordering_direction
;
ordering_direction:
'ascending'
| 'descending' ;
select_or_group_clause:
select_clause
| group_clause ;
select_clause:
'select' expression ;
group_clause:
'group' expression 'by' expression ;
where_clause:
'where' boolean_expression ;
boolean_expression:
expression;
///////////////////////////////////////////////////////
// B.2.13 Attributes
///////////////////////////////////////////////////////
global_attributes:
global_attribute+ ;
global_attribute:
o='[' global_attribute_target_specifier attribute_list ','? ']' -> ^(GLOBAL_ATTRIBUTE[$o.token, "GLOBAL_ATTRIBUTE"] global_attribute_target_specifier? attribute_list) ;
global_attribute_target_specifier:
global_attribute_target ':' ;
global_attribute_target:
'assembly' | 'module' ;
attributes:
attribute_sections ;
attribute_sections:
attribute_section+ ;
attribute_section:
o='[' attribute_target_specifier? attribute_list ','? ']' -> ^(ATTRIBUTE[$o.token, "ATTRIBUTE"] attribute_target_specifier? attribute_list);
attribute_target_specifier:
attribute_target ':' ;
attribute_target:
'field' | 'event' | 'method' | 'param' | 'property' | 'return' | 'type' ;
attribute_list:
attribute (',' attribute)* ;
attribute:
type_name attribute_arguments? ;
// TODO: allows a mix of named/positional arguments in any order
attribute_arguments:
'(' (')' // empty
| (positional_argument ((',' identifier '=') => named_argument
|',' positional_argument)*
) ')'
) ;
positional_argument_list:
a1=positional_argument (',' an+=positional_argument)* -> ^(ARGS[$a1.start.Token,"ARGS"] $a1 $an*);
positional_argument:
attribute_argument_expression ;
named_argument_list:
a1=named_argument (',' an+=named_argument)* -> ^(ARGS[$a1.start.Token,"ARGS"] $a1 $an*);
named_argument:
identifier '=' attribute_argument_expression ;
attribute_argument_expression:
expression ;
///////////////////////////////////////////////////////
// Class Section
///////////////////////////////////////////////////////
class_declaration[CommonTree atts, CommonTree mods, CommonTree partial, bool toplevel] returns [string name]
scope TypeContext;
@init {
CommonTree mangledMods = toplevel ? mkRemoveMods($mods, new int[] {STATIC}) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, "static"));
// If no access modifier then type is internal, which we relax to public
if (toplevel && !containsMods(mangledMods, new int[] {PUBLIC, PRIVATE})) {
mangledMods = addModifier(mangledMods, (CommonTree)adaptor.Create(PUBLIC, "public"));
}
}
:
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) } { mangledMods } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? class_body );
type_parameter_list returns [List<string> names]
@init {
List<string> names = new List<string>();
}:
'<'! attributes? t1=type_parameter { names.Add($t1.name); } ( ','! attributes? tn=type_parameter { names.Add($tn.name); })* '>'! ;
type_parameter returns [string name]:
identifier { $name = $identifier.thetext; } ;
class_base:
// just put all types in a single list. In NetMaker we will extract the base class if necessary
':' ts+=type (',' ts+=type)* -> ^(IMPLEMENTS $ts)*;
//interface_type_list:
// ts+=type (',' ts+=type)* -> $ts+;
class_body:
'{' class_member_declarations? '}' ;
class_member_declarations:
class_member_declaration+ ;
///////////////////////////////////////////////////////
constant_declaration:
'const' type constant_declarators ';' ;
constant_declarators:
constant_declarator (',' constant_declarator)* ;
constant_declarator:
identifier ('=' constant_expression)? ;
constant_expression:
expression;
///////////////////////////////////////////////////////
field_declaration:
variable_declarators ';'! ;
variable_declarators:
variable_declarator (',' variable_declarator)* ;
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, bool isPartial]
@init {
bool isToString = false;
bool isClone = false;
bool isEquals = false;
bool isEqualsArg = false;
CommonTree exceptions = null;
CommonTree optMain = null;
bool isVoid = $typeText == "void";
bool isInt = $typeText == "int" || $typeText == "System.Int32" || $typeText == "Int32";
bool isBool = $typeText == "bool" || $typeText == "System.Boolean" || $typeText == "Boolean";
bool isMain = isVoid || isInt;
bool isMainHasArg = false;
bool isGetHashCode = isInt;
string newMethodName = "";
}:
// TODO: According to the spec the C# Main() method should be static and not public. We aren't checking for lack of public
// we can check the modifiers in modList if we want to enforce that.
member_name { isToString = $member_name.text == "ToString";
isGetHashCode &= $member_name.text == "GetHashCode";
isEquals = $member_name.text == "Equals";
isMain &= $member_name.text == "Main";
isClone = $member_name.text == "Clone";
}
(type_parameter_list { isToString = false; isMain = false; })?
'('
// We are looking for ToString(), and Main(string[] args), where arg is optional.
(formal_parameter_list
{ isToString = false; isGetHashCode = false; isClone = false;
isEqualsArg = $formal_parameter_list.numArgs == 1;
if (isMain) {
isMain = false;
// since we have an argument, must check its an array of String
if ($formal_parameter_list.tree != null && $formal_parameter_list.tree.Children != null && $formal_parameter_list.tree.Children.Count == 2) {
// parameter list children size is 2 (type arg)
CommonTree argTy = (CommonTree)$formal_parameter_list.tree.Children[0];
if (argTy != null && argTy.Children != null && argTy.Children.Count == 3) {
// Looking for Children of "String" "[" "]"
if (argTy.Children[0].Text.ToLower() == "string" &&
argTy.Children[1].Text == "[" &&
argTy.Children[2].Text == "]") {
// Bingo!
isMain = true;
isMainHasArg = true;
}
}
}
}
}
)?
')'
( type_parameter_constraints_clauses { isToString = false; isEquals = false; isMain = false; isClone = false; })?
// Only have throw Exceptions if IsJavaish
throw_exceptions?
b=method_body[isToString || isGetHashCode || (isEquals && isEqualsArg) || isClone]
// build main method if required
argParam=magicMainArgs[isMain && isMainHasArg, $member_name.tree.Token]
mainApply=magicMainApply[isMain, $member_name.tree.Token, (isMain ? $TypeContext::typeName : null), $argParam.tree]
mainCall=magicMainExit[isMain, isInt, $member_name.tree.Token, $mainApply.tree]
mainMethod=magicMainWrapper[isMain, $member_name.tree.Token, $mainCall.tree]
{
newMethodName = $member_name.full_name.Replace(".","___");
if (newMethodName != "Main" && Cfg.TranslatorMakeJavaNamingConventions) {
// Leave Main() as it is because we are going to wrap it with a special main method
newMethodName = toJavaConvention(CSharpEntity.METHOD, newMethodName);
}
}
magicIdentifier[$member_name.tree.Token, newMethodName]
{ if (isToString) {
$magicIdentifier.tree.Token.Text = "toString";
}
if (isGetHashCode) {
$magicIdentifier.tree.Token.Text = "hashCode";
}
if (isEquals && isEqualsArg) {
$magicIdentifier.tree.Token.Text = "equals";
}
if (isClone) {
$magicIdentifier.tree.Token.Text = "clone";
}
exceptions = IsJavaish ? $throw_exceptions.tree : $b.exceptionList;
}
-> {!($isPartial && $b.isEmpty)}?
$mainMethod?
^(METHOD { dupTree($atts) } { dupTree($mods) } { dupTree($type) }
magicIdentifier type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? $b { exceptions })
->
;
method_body [bool smotherExceptions] returns [CommonTree exceptionList, bool isEmpty]:
{smotherExceptions}? b=block nb=magicSmotherExceptions[dupTree($b.tree) ]
-> $nb
| b=block el=magicThrowsException[Cfg.TranslatorBlanketThrow,$b.tree.Token] { $exceptionList=$el.tree; $isEmpty = $b.isEmpty; }
-> $b
;
throw_exceptions:
{IsJavaish}?=> 'throws'! javaException (','! javaException)*
;
javaException:
identifier -> EXCEPTION[$identifier.tree.Token, $identifier.tree.Token.Text]
;
member_name returns [string rawId, string full_name]
@init {
$full_name = "";
}:
(type_or_generic '.' {$full_name += mkTypeOrGenericString($type_or_generic.type, $type_or_generic.generic_arguments) + ".";})*
i=identifier { $rawId = $i.text; $full_name += $i.text; }
// keving [interface_type.identifier] | type_name '.' identifier
;
member_name_orig returns [string name, List<string> tyargs]:
qid { $name = $qid.name; $tyargs = $qid.tyargs; } ; // IInterface<int>.Method logic added.
///////////////////////////////////////////////////////
property_declaration [CommonTree atts, CommonTree mods, bool isAbstract, CommonTree type]
scope { bool emptyGetterSetter; }
@init {
$property_declaration::emptyGetterSetter = false;
CommonTree privateVar = null;
}
:
i=member_name '{' ads=accessor_declarations[atts, mods, isAbstract, type, $i.text, $i.rawId] '}'
v=magicMkPropertyVar[mkPrivateMod($mods, $i.tree.Token), type, "__" + $i.tree.Text] { privateVar = !isAbstract && $property_declaration::emptyGetterSetter ? $v.tree : null; }-> { privateVar } $ads ;
accessor_declarations [CommonTree atts, CommonTree mods, bool isAbstract, CommonTree type, string propName, string rawVarName]:
accessor_declaration[atts, mods, isAbstract, type, propName, rawVarName]+;
accessor_declaration [CommonTree atts, CommonTree mods, bool isAbstract, CommonTree type, string propName, string rawVarName]
@init {
CommonTree propBlock = null;
bool mkBody = false;
}:
la=attributes? lm=accessor_modifier?
(g='get' ((';')=> gbe=semi { $property_declaration::emptyGetterSetter = true; propBlock = $gbe.tree; mkBody = !isAbstract; rawVarName = "__" + rawVarName; }
| gb=block { propBlock = $gb.tree; } ) getm=magicPropGetter[atts, $la.tree, mods, $lm.tree, type, $g.token, propBlock, propName, mkBody, rawVarName] -> $getm
| s='set' ((';')=> sbe=semi { $property_declaration::emptyGetterSetter = true; propBlock = $sbe.tree; mkBody = !isAbstract; rawVarName = "__" + rawVarName; }
| sb=block { propBlock = $sb.tree; } ) setm=magicPropSetter[atts, $la.tree, mods, $lm.tree, type, $s.token, propBlock, propName, mkBody, rawVarName] -> $setm)
;
accessor_modifier:
'protected' 'internal'? | 'private' | 'internal' 'protected'?;
semi:
';' ;
///////////////////////////////////////////////////////
event_declaration[CommonTree atts, CommonTree mods]:
e='event' type
((member_name '{') => member_name '{' event_accessor_declarations '}' -> ^(EVENT[$e.token, "EVENT"] { dupTree(atts) } { dupTree(mods) } type member_name '{' event_accessor_declarations '}')
| variable_declarators ';' -> ^(FIELD[$e.token,"FIELD"] { dupTree(atts) } { dupTree(mods) } type variable_declarators)) // typename=foo;
;
event_modifiers:
modifier+ ;
event_accessor_declarations:
attributes? ((add_accessor_declaration attributes? remove_accessor_declaration)
| (remove_accessor_declaration attributes? add_accessor_declaration)) ;
add_accessor_declaration:
'add' block ;
remove_accessor_declaration:
'remove' block ;
///////////////////////////////////////////////////////
// enum declaration
///////////////////////////////////////////////////////
enum_declaration[CommonTree atts, CommonTree mods] returns [string name]
scope TypeContext;
@init {
CommonTree constType = null;
CommonTree mangledMods = mkRemoveMods($mods, new int[] {STATIC});
// If no access modifier then type is internal, which we relax to public
if (!containsMods(mangledMods, new int[] {PUBLIC, PRIVATE})) {
mangledMods = addModifier(mangledMods, (CommonTree)adaptor.Create(PUBLIC, "public"));
}
}
:
{ Cfg.EnumsAsNumericConsts }? =>
e1='enum' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } magicBoxedType[true,$e1.token,"System.Int32"] { constType = $magicBoxedType.tree; } (enum_base {constType = $enum_base.tree; } )? enum_body_asnumber[constType] ';'?
-> ^(CLASS[$e1.token, "class"] { dupTree($atts) } { mangledMods } identifier enum_body_asnumber)
| e2='enum' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } enum_base? enum_body ';'?
-> ^(ENUM[$e2.token, "ENUM"] { dupTree($atts) } { mangledMods } identifier enum_base? enum_body);
enum_base:
c=':' integral_type -> ^(TYPE[$c.token, "TYPE"] integral_type) ;
enum_body:
'{' (enum_member_declarations ','?)? '}' -> ^(ENUM_BODY enum_member_declarations? ) ;
enum_member_declarations
@init {
SortedList<int,CommonTree> members = new SortedList<int,CommonTree>();
int next = 0;
}
@after{
$enum_member_declarations.tree = (CommonTree)adaptor.Nil;
if (next > 0 && next < MAX_DUMMY_ENUMS) {
int dummyCounter = 0;
for (int i = 0; i < next; i++) {
if (members.ContainsKey(i)) {
adaptor.AddChild($enum_member_declarations.tree, members[i]);
}
else {
adaptor.AddChild($enum_member_declarations.tree, adaptor.Create(IDENTIFIER, $e.start.Token, "__dummyEnum__" + dummyCounter++));
}
}
}
else {
Warning($e.tree.Line, "[UNSUPPORTED] We do not yet generate dummy enum members for enums that need more than " + MAX_DUMMY_ENUMS + " entries.");
foreach (CommonTree en in members.Values) {
adaptor.AddChild($enum_member_declarations.tree, en);
}
}
}
:
e=enum_member_declaration[members,ref next] (',' enum_member_declaration[members, ref next])*
->
;
enum_member_declaration[ SortedList<int,CommonTree> members, ref int next]
@init {
int calcValue = 0;
}:
// Fill in members, a map from enum's value to AST
attributes? identifier { $members[$next] = $identifier.tree; $next++; }
((eq='=' ( ((NUMBER | Hex_number) (','|'}')) =>
{ $members.Remove($next-1); }
(i=NUMBER { calcValue = Int32.Parse($i.text); }
| i=Hex_number { calcValue = Int32.Parse($i.text.Substring(2), NumberStyles.AllowHexSpecifier); } )
{ if (calcValue < 0 || calcValue > Int32.MaxValue) {
Warning($eq.line, "[UNSUPPORTED] enum member's value initialization ignored, only numeric literals in the range 0..MAXINT supported for enum values");
calcValue = $next-1;
}
else if (calcValue < $next-1) {
Warning($eq.line, "[UNSUPPORTED] enum member's value initialization ignored, value has already been assigned and enum values must be unique");
calcValue = $next-1;
}
$members[calcValue] = $identifier.tree; $next = calcValue + 1; }
| expression { Warning($eq.line, "[UNSUPPORTED] enum member's value initialization ignored, only numeric literals supported for enum values"); } ))?)! ;
//enum_modifiers:
// enum_modifier+ ;
//enum_modifier:
// 'new' | 'public' | 'protected' | 'internal' | 'private' ;
integral_type:
'sbyte' | 'byte' | 'short' | 'ushort' | 'int' | 'uint' | 'long' | 'ulong' | 'char' ;
// this escheme translates enums to a class containing numeric constants
enum_body_asnumber [ CommonTree typeTree ]:
'{' (enum_member_declarations_asnumber[typeTree] (','!)?)? '}' ;
enum_member_declarations_asnumber [ CommonTree typeTree ]
@init {
CommonTree prevTree = null;
}:
e1=enum_member_declaration_asnumber[typeTree, prevTree] { prevTree = $e1.thisTree; }
(','! en=enum_member_declaration_asnumber[typeTree, prevTree] { prevTree = $en.thisTree; })*
;
enum_member_declaration_asnumber [ CommonTree typeTree, CommonTree prevTree ] returns [ CommonTree thisTree ]
@init {
CommonTree prev = $prevTree;
}:
attributes? identifier { $thisTree = $identifier.tree; }
(eq='=' expression -> ^(FIELD[$eq.token, "FIELD"] attributes? PUBLIC[$eq.token, "public"] STATIC[$eq.token, "static"] FINAL[$eq.token, "final"] { dupTree(typeTree) } identifier $eq expression)
| magicNumber[$prevTree == null, $identifier.tree.Token, "0"] magicIncrement[$prevTree != null, $identifier.tree.token, $prevTree]
{ prev = $prevTree == null ? $magicNumber.tree : $magicIncrement.tree; } -> ^(FIELD[$identifier.tree.Token, "FIELD"] attributes? PUBLIC[$identifier.tree.Token, "public"] STATIC[$identifier.tree.Token, "static"] FINAL[$identifier.tree.Token, "final"] { dupTree(typeTree) } identifier ASSIGN[$identifier.tree.Token, "="] { dupTree(prev) })) ;
// B.2.12 Delegates
delegate_declaration[CommonTree atts, CommonTree mods, bool toplevel] returns [Dictionary<String, CommonTree> compUnits]
scope TypeContext;
@init {
CommonTree mangledMods = toplevel ? mkRemoveMods($mods, new int[] {STATIC}) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, "static"));
// If no access modifier then type is internal, which we relax to public
if (toplevel && !containsMods(mangledMods, new int[] {PUBLIC, PRIVATE})) {
mangledMods = addModifier(mangledMods, (CommonTree)adaptor.Create(PUBLIC, "public"));
}
$compUnits = new Dictionary<String,CommonTree>();
CommonTree delClassMemberNodes = null;
CommonTree ifTree = null;
String delName = "";
String multiDelName = "";
}
@after {
$compUnits.Add(delName, dupTree($delegate_declaration.tree));
}
:
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]
{
multiDelName = "__Multi" + delName;
delClassMemberNodes = this.parseString("class_member_declarations", this.MultiDelegateMethods(mkTypeString(delName, $variant_generic_parameter_list.tyargs), mkTypeString(multiDelName, $variant_generic_parameter_list.tyargs),mkTypeArgString($variant_generic_parameter_list.tyargs)));
AddToImports("java.util.List");
AddToImports("java.util.LinkedList");
AddToImports("java.util.ArrayList");
AddToImports("CS2JNet.JavaSupport.util.ListSupport");
$NSContext::namespaces.Add("System.Collection"); // System.Collection.Ilist used in multi invoke method
}
magicMultiDelClass[$d.token, $atts, mangledMods, 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) } { mangledMods } identifier { dupTree($type_parameter_constraints_clauses.tree) } { dupTree($variant_generic_parameter_list.tree) } magicDelegateInterface)
;
delegate_modifiers:
modifier+ ;
// 4.0
variant_generic_parameter_list returns [List<string> tyargs]
@init {
$tyargs = new List<string>();
}:
'<'! variant_type_parameters[$tyargs] '>'! ;
variant_type_parameters [List<string> tyargs]:
v1=variant_type_variable_name { tyargs.Add($v1.text); } (',' vn=variant_type_variable_name { tyargs.Add($vn.text); })* -> variant_type_variable_name+ ;
variant_type_variable_name:
attributes? variance_annotation? type_variable_name ;
variance_annotation:
'in' -> IN | 'out' -> OUT;
type_parameter_constraints_clauses:
type_parameter_constraints_clause+ ;
type_parameter_constraints_clause:
'where' type_variable_name ':' type_parameter_constraint_list -> ^(TYPE_PARAM_CONSTRAINT type_variable_name type_parameter_constraint_list?) ;
// class, Circle, new()
type_parameter_constraint_list:
('class' | 'struct') (',' secondary_constraint_list)? (',' constructor_constraint)? -> secondary_constraint_list?
| secondary_constraint_list (',' constructor_constraint)? -> secondary_constraint_list
| constructor_constraint -> ;
//primary_constraint:
// class_type
// | 'class'
// | 'struct' ;
secondary_constraint_list:
secondary_constraint (',' secondary_constraint)* -> secondary_constraint+ ;
secondary_constraint:
type_name ; // | type_variable_name) ;
type_variable_name:
identifier ;
// keving: TOTEST we drop new constraints, but what will happen in Java for this case?
constructor_constraint:
'new' '(' ')' ;
return_type returns [string thetext]:
type {$thetext = $type.thetext; }
| void_type {$thetext = "System.Void"; };
formal_parameter_list returns [int numArgs]
@init {
$numArgs = 0;
}:
formal_parameter {$numArgs++;} (',' formal_parameter {$numArgs++;})* -> ^(PARAMS formal_parameter+);
formal_parameter:
attributes? (fixed_parameter | parameter_array)
| '__arglist'; // __arglist is undocumented, see google
fixed_parameters:
fixed_parameter (',' fixed_parameter)* ;
// 4.0
fixed_parameter:
parameter_modifier? type identifier default_argument? ;
// 4.0
default_argument:
'=' expression;
parameter_modifier:
'ref' | 'out' | 'this' ;
parameter_array:
p='params'^ t=type identifier
{
// type will be an array, need to strip the final [] for java
int numComponents = adaptor.GetChildCount($t.tree);
// sanity check
if (numComponents >= 3 &&
adaptor.GetType(adaptor.GetChild($t.tree, numComponents-2)) == OPEN_BRACKET &&
adaptor.GetType(adaptor.GetChild($t.tree, numComponents-1)) == CLOSE_BRACKET)
{
adaptor.DeleteChild($t.tree, numComponents-1);
adaptor.DeleteChild($t.tree, numComponents-2);
}
else {
Error($p.line, "[SOURCE ERROR] params type must be an array");
}
}
;
///////////////////////////////////////////////////////
interface_declaration[CommonTree atts, CommonTree mods, CommonTree partial] returns [string name]
scope TypeContext;
@init {
CommonTree mangledMods = mkRemoveMods($mods, new int[] {STATIC});
// If no access modifier then type is internal, which we relax to public
if (!containsMods(mangledMods, new int[] {PUBLIC, PRIVATE})) {
mangledMods = addModifier(mangledMods, (CommonTree)adaptor.Create(PUBLIC, "public"));
}
}
:
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($partial) } { dupTree($atts) } { mangledMods } identifier type_parameter_constraints_clauses? variant_generic_parameter_list? interface_base? interface_body );
interface_base:
c=':' ts+=type (',' ts+=type)* -> ^(EXTENDS[$c.token,"extends"] $ts)*;
interface_modifiers:
modifier+ ;
interface_body:
'{' interface_member_declarations? '}' ;
interface_member_declarations:
interface_member_declaration+ ;
interface_member_declaration:
a=attributes? m=modifiers?
(vt=void_type im1=interface_method_declaration[$a.tree, $m.tree, $vt.tree] -> $im1
| ie=interface_event_declaration[$a.tree, $m.tree] -> $ie
| t=type ( (identifier type_parameter_list? '(') => im2=interface_method_declaration[$a.tree, $m.tree, $t.tree] -> $im2
// property will rewrite to one, or two method headers
| (member_name '{') => ip=interface_property_declaration[$a.tree, $m.tree, $t.tree] -> $ip //^(PROPERTY[$t.start.Token, "PROPERTY"] $a? $m? $t interface_property_declaration)
| ii=interface_indexer_declaration[$a.tree, $m.tree, $t.tree] -> $ii)
)
;
interface_property_declaration [CommonTree atts, CommonTree mods, CommonTree type]:
i=identifier '{' iads=interface_accessor_declarations[atts, mods, type, $i.text] '}' -> $iads ;
interface_method_declaration [CommonTree atts, CommonTree mods, CommonTree type]
@init {
string newMethodName = "";
}:
identifier type_parameter_list?
'(' formal_parameter_list? ')' type_parameter_constraints_clauses? s=';' magicThrowsException[Cfg.TranslatorBlanketThrow,$s.token]
{
newMethodName = $identifier.text.Replace(".","___");
if (newMethodName != "Main" && Cfg.TranslatorMakeJavaNamingConventions) {
// Leave Main() as it is because we are going to wrap it with a special main method
newMethodName = toJavaConvention(CSharpEntity.METHOD, newMethodName);
}
}
magicIdentifier[$identifier.tree.Token, newMethodName]
-> ^(METHOD { dupTree($atts) } { dupTree($mods) } { dupTree($type) }
magicIdentifier type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? magicThrowsException?);
interface_event_declaration [CommonTree atts, CommonTree mods]:
//attributes? 'new'?
e='event' type identifier ';' -> ^(EVENT[$e.token, "EVENT"] { dupTree($atts) } { dupTree($mods) } type identifier)
;
interface_indexer_declaration [CommonTree atts, CommonTree mods, CommonTree type]:
// attributes? 'new'? type
'this' '[' formal_parameter_list ']' '{' indexer_accessor_declarations[atts,mods,type,null,$formal_parameter_list.tree] '}' -> indexer_accessor_declarations ;
interface_accessor_declarations [CommonTree atts, CommonTree mods, CommonTree type, string propName]:
interface_accessor_declaration[atts, mods, type, propName]+
;
interface_accessor_declaration [CommonTree atts, CommonTree mods, CommonTree type, string propName]:
la=attributes? (g='get' gbe=semi magicPropGetter[atts, $la.tree, mods, null, type, $g.token, null, propName, false, ""] -> magicPropGetter
| s='set' sbe=semi magicPropSetter[atts, $la.tree, mods, null, type, $s.token, null, propName, false, ""] -> magicPropSetter)
;
///////////////////////////////////////////////////////
struct_declaration[CommonTree atts, CommonTree mods, CommonTree partial, bool toplevel] returns [string name]
scope TypeContext;
@init {
CommonTree mangledMods = toplevel ? mkRemoveMods($mods, new int[] {STATIC}) : addModifier($mods, (CommonTree)adaptor.Create(STATIC, "static"));
// If no access modifier then type is internal, which we relax to public
if (toplevel && !containsMods(mangledMods, new int[] {PUBLIC, PRIVATE})) {
mangledMods = addModifier(mangledMods, (CommonTree)adaptor.Create(PUBLIC, "public"));
}
}
:
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) } { mangledMods } identifier type_parameter_constraints_clauses? type_parameter_list? class_base? struct_body );
struct_body [string structName]:
o='{' magicDefaultConstructor[$o.token, structName] class_member_declarations? e='}'
-> '{' magicDefaultConstructor class_member_declarations? '}' ;
///////////////////////////////////////////////////////
indexer_declaration [CommonTree atts, CommonTree mods, CommonTree type, CommonTree iface]:
'this' '[' formal_parameter_list ']' '{' indexer_accessor_declarations[atts, mods, type, iface, $formal_parameter_list.tree] '}' -> indexer_accessor_declarations ;
//indexer_declarator:
//(type_name '.')?
// 'this' '[' formal_parameter_list ']' ;
indexer_accessor_declarations [CommonTree atts, CommonTree mods, CommonTree type, CommonTree iface, CommonTree idxparams]:
indexer_accessor_declaration[atts, mods, type, iface, idxparams]+;
indexer_accessor_declaration [CommonTree atts, CommonTree mods, CommonTree type, CommonTree iface, CommonTree idxparams]
@init {
CommonTree idxBlock = null;
}:
la=attributes? lm=accessor_modifier?
(g='get' ((';')=> gbe=';' { idxBlock = $gbe.tree; }
| gb=block { idxBlock = $gb.tree; } ) geti=magicIdxGetter[atts, $la.tree, mods, $lm.tree, type, iface, $g.token, idxBlock, idxparams] -> $geti
| s='set' ((';')=> sbe=';' { idxBlock = $sbe.tree; }
| sb=block { idxBlock = $sb.tree; } ) seti=magicIdxSetter[atts, $la.tree, mods, $lm.tree, type, iface, $s.token, idxBlock, idxparams] -> $seti)
;
///////////////////////////////////////////////////////
operator_declaration:
operator_declarator operator_body ;
operator_declarator:
'operator'
(('+' | '-') '(' type identifier (binary_operator_declarator | unary_operator_declarator)
| overloadable_unary_operator '(' type identifier unary_operator_declarator
| overloadable_binary_operator '(' type identifier binary_operator_declarator) ;
unary_operator_declarator:
')' ;
overloadable_unary_operator:
/*'+' | '-' | */ '!' | '~' | '++' | '--' | 'true' | 'false' ;
binary_operator_declarator:
',' type identifier ')' ;
// >> check needed
overloadable_binary_operator:
/*'+' | '-' | */ '*' | '/' | '%' | '&' | '|' | '^' | '<<' | '>' '>' | '==' | '!=' | '>' | '<' | '>=' | '<=' ;
conversion_operator_declaration:
conversion_operator_declarator operator_body ;
conversion_operator_declarator:
('implicit' | 'explicit') 'operator' type '(' type identifier ')' ;
operator_body:
block ;
///////////////////////////////////////////////////////
constructor_declaration[CommonTree atts, CommonTree mods, List<string> modList]:
i=identifier '(' p=formal_parameter_list? s=')' init=constructor_initializer? b=constructor_body[$init.tree] magicThrowsException[Cfg.TranslatorBlanketThrow,$s.token]
-> ^(CONSTRUCTOR[$i.tree.Token, "CONSTRUCTOR"] { dupTree($atts) } { dupTree($mods) } $i $p? $b magicThrowsException?);
constructor_initializer:
':' tok='this' '(' argument_list? ')'
-> ^(APPLY[$tok.token, "APPLY"] $tok argument_list?) SEMI[$tok.token, ";"]
| ':' tok='base' '(' argument_list? ')'
-> ^(APPLY[$tok.token, "APPLY"] SUPER[$tok.token, "super"] argument_list?) SEMI[$tok.token, ";"]
;
constructor_body[CommonTree init]:
{init == null}?=> s=';' -> $s
| s1=';' -> OPEN_BRACE[$s1.token, "{"] { dupTree(init) } CLOSE_BRACE[$s1.token, "}"]
| a='{' ss+=statement[/* isStatementListCtxt */ true]* b='}' -> $a { dupTree(init) } $ss* $b
;
///////////////////////////////////////////////////////
//static_constructor_declaration:
// identifier '(' ')' static_constructor_body ;
//static_constructor_body:
// block ;
///////////////////////////////////////////////////////
destructor_declaration:
t='~' identifier '(' ')' destructor_body f=magicFinalize[$t.token, $destructor_body.tree] -> $f;
destructor_body:
block ;
///////////////////////////////////////////////////////
// invocation_expression:
// invocation_start (((arguments[null] ('['|'.'|'->')) => arguments[ (CommonTree)adaptor.Create(KGHOLE, "KGHOLE") ] invocation_part)
// | invocation_part)* arguments[ (CommonTree)adaptor.Create(KGHOLE, "KGHOLE") ] ;
// invocation_start:
// predefined_type
// | (identifier generic_argument_list) => identifier generic_argument_list
// | 'this'
// | b='base' -> SUPER[$b.token, "super"]
// | identifier ('::' identifier)?
// | typeof_expression // typeof(Foo).Name
// ;
invocation_part [CommonTree start]:
access_identifier[ $start ]
| brackets[ $start ] ;
///////////////////////////////////////////////////////
statement[bool isStatementListCtxt]:
(declaration_statement) => declaration_statement
| (identifier ':') => labeled_statement[isStatementListCtxt]
| embedded_statement[isStatementListCtxt]
;
embedded_statement[bool isStatementListCtxt]:
block
| selection_statement // if, switch
| iteration_statement // while, do, for, foreach
| jump_statement // break, continue, goto, return, throw
| try_statement
| checked_statement
| unchecked_statement
| lock_statement
| using_statement[isStatementListCtxt]
| yield_statement
| unsafe_statement
| fixed_statement
| expression_statement // expression!
;
fixed_statement:
'fixed' '(' pointer_type fixed_pointer_declarators ')' embedded_statement[/* isStatementListCtxt */ false] ;
fixed_pointer_declarators:
fixed_pointer_declarator (',' fixed_pointer_declarator)* ;
fixed_pointer_declarator:
identifier '=' fixed_pointer_initializer ;
fixed_pointer_initializer:
//'&' variable_reference // unary_expression covers this
expression;
unsafe_statement:
'unsafe'^ block;
labeled_statement[bool isStatementListCtxt]:
identifier ':' statement[isStatementListCtxt] ;
declaration_statement:
(local_variable_declaration
| local_constant_declaration) ';' ;
local_variable_declaration returns [List<string> variableNames]:
local_variable_type local_variable_declarators { $variableNames = $local_variable_declarators.variableNames; };
local_variable_type:
('var') => v='var' -> TYPE_VAR[$v.token, "var"]
| ('dynamic') => d='dynamic' -> TYPE_DYNAMIC[$d.token,"dynamic"]
| type ;
local_variable_declarators returns [List<string> variableNames]
@init {
$variableNames = new List<string>();
}:
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.thetext; } ('=' local_variable_initializer)? ;
local_variable_initializer:
expression
| array_initializer
| stackalloc_initializer;
stackalloc_initializer:
'stackalloc' unmanaged_type '[' expression ']' ;
local_constant_declaration:
'const' type constant_declarators ;
expression_statement:
expression ';' ;
// TODO: should be assignment, call, increment, decrement, and new object expressions
statement_expression:
expression
;
selection_statement:
if_statement
| switch_statement ;
if_statement:
// else goes with closest if
i='if' '(' boolean_expression ')' embedded_statement[/* isStatementListCtxt */ false] (('else') => else_statement)? -> ^(IF[$i.Token] boolean_expression SEP embedded_statement else_statement?)
// 'if' '(' boolean_expression ')' embedded_statement (('else') => else_statement)?
;
else_statement:
'else' embedded_statement[/* isStatementListCtxt */ false] ;
switch_statement:
s='switch' '(' expression ')' switch_block -> ^($s expression switch_block);
switch_block:
'{'! switch_section* '}'! ;
//switch_sections:
// switch_section+ ;
switch_section:
switch_label+ statement_list -> ^(SWITCH_SECTION switch_label+ statement_list);
//switch_labels:
// switch_label+ ;
switch_label:
('case'^ constant_expression ':'!)
| ('default' ':'!);
iteration_statement:
while_statement
| do_statement
| for_statement
| foreach_statement ;
while_statement:
w='while' '(' boolean_expression ')' embedded_statement[/* isStatementListCtxt */ false] -> ^($w boolean_expression SEP embedded_statement);
do_statement:
'do' embedded_statement[/* isStatementListCtxt */ false] 'while' '(' boolean_expression ')' ';' ;
for_statement:
f='for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement[/* isStatementListCtxt */ false]
-> ^($f for_initializer? SEP for_condition? SEP for_iterator? SEP embedded_statement);
for_initializer:
(local_variable_declaration) => local_variable_declaration
| statement_expression_list
;
for_condition:
boolean_expression ;
for_iterator:
statement_expression_list ;
statement_expression_list:
statement_expression (',' statement_expression)* ;
foreach_statement:
f='foreach' '(' local_variable_type identifier 'in' expression ')' embedded_statement[/* isStatementListCtxt */ false]
-> ^($f local_variable_type identifier expression SEP embedded_statement);
jump_statement:
break_statement
| continue_statement
| goto_statement
| return_statement
| throw_statement ;
break_statement:
'break' ';' ;
continue_statement:
'continue' ';' ;
goto_statement:
'goto' ( identifier
| 'case' constant_expression
| 'default') ';' ;
return_statement:
'return'^ expression? ';'! ;
throw_statement
// If throw exp is missing then it is the var from closest enclosing catch
@init {
CommonTree var = null;
bool missingThrowExp = true;
}:
t='throw' (e=expression { missingThrowExp = false;})? { var = missingThrowExp ? dupTree($catch_clause::throwVar) : $e.tree; } ';' -> ^($t { var });
try_statement:
t='try' block ( catch_clauses finally_clause?
| finally_clause) -> ^($t block catch_clauses? finally_clause?);
// We rewrite the catch clauses so that they all have the form "(catch Type Var)" by introducing
// Throwable and dummy vars as necessary
catch_clauses:
catch_clause+;
catch_clause
scope { CommonTree throwVar; }
@init {
CommonTree ty = null, var = null;
}:
c='catch' ('(' given_t=class_type { ty = $given_t.tree; } (given_v=identifier { var = $given_v.tree; } | magic_v=magicCatchVar { var = $magic_v.tree; } ) ')'
| magic_t=magicThrowableType[true,$c.token] magic_v=magicCatchVar { ty = $magic_t.tree; var = $magic_v.tree; }) { $catch_clause::throwVar = var; } block
-> ^($c { ty } { var } block)
;
finally_clause:
'finally'^ block ;
checked_statement:
'checked' block ;
unchecked_statement:
'unchecked' block -> ^(UNCHECKED block);
lock_statement:
'lock' '(' expression ')' embedded_statement[/* isStatementListCtxt */ false] ;
// TODO: Can we avoid surrounding this with braces if not needed?
using_statement[bool isStatementListCtxt]
@init {
CommonTree disposers = null;
}:
// see http://msdn.microsoft.com/en-us/library/yh598w02.aspx for translation
u='using' '(' resource_acquisition c=')' embedded_statement[/* isStatementListCtxt */ false]
{
disposers = addDisposeVars($c.token, $resource_acquisition.resourceNames, Cfg.TranslatorMakeJavaNamingConventions ? "dispose" : "Dispose");
AddToImports(String.Format("CS2JNet.System{0}Disposable", Cfg.TranslatorMakeJavaNamingConventions ? ".LCC." : "."));
}
f=magicFinally[$c.token, disposers]
magicTry[$u.token, state.backtracking == 0 ? embeddedStatementToBlock($u.token, $embedded_statement.tree) : null, null, $f.tree]
-> {!isStatementListCtxt}? OPEN_BRACE[$u.token, "{"] resource_acquisition SEMI[$c.token, ";"] magicTry CLOSE_BRACE[$u.token, "}"]
-> resource_acquisition SEMI[$c.token, ";"] magicTry
;
resource_acquisition returns [List<string> resourceNames]
@init {
$resourceNames = new List<string>();
}:
(local_variable_declaration) => local_variable_declaration { $resourceNames = $local_variable_declaration.variableNames; }
| expression { $resourceNames.Add("__newVar"+newVarCtr); } -> ^(TYPE[$expression.tree.Token, "TYPE"] IDENTIFIER[$expression.tree.Token, "IDisposable"])
IDENTIFIER[$expression.tree.Token, "__newVar"+newVarCtr++] ASSIGN[$expression.tree.Token, "="] expression //SEMI[$expression.tree.Token, ";"]
;
yield_statement:
'yield' ('return' expression ';' -> ^(YIELD_RETURN expression)
| 'break' ';' -> YIELD_BREAK) ;
///////////////////////////////////////////////////////
// Lexar Section
///////////////////////////////////////////////////////
predefined_type returns [string thetext]
@after{
string newText;
if (predefined_type_map.TryGetValue($predefined_type.tree.Token.Text, out newText)) {
$predefined_type.tree.Token.Text = newText;
}
if (Cfg.UnsignedNumbersToSigned && predefined_unsigned_type_map.TryGetValue($predefined_type.tree.Token.Text, out newText)) {
$predefined_type.tree.Token.Text = newText;
}
if (Cfg.UnsignedNumbersToBiggerSignedNumbers && predefined_embiggen_unsigned_type_map.TryGetValue($predefined_type.tree.Token.Text, out newText)) {
$predefined_type.tree.Token.Text = newText;
}
}:
'bool' { $thetext = "System.Boolean"; }
| 'byte' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.SByte" : "System.Byte";
if (Cfg.UnsignedNumbersToBiggerSignedNumbers)
$thetext = "System.Short";
}
| 'char' { $thetext = "System.Char"; }
| 'decimal' { $thetext = "System.Decimal"; }
| 'double' { $thetext = "System.Double"; }
| 'float' { $thetext = "System.Single"; }
| 'int' { $thetext = "System.Int32"; }
| 'long' { $thetext = "System.Int64"; }
| 'object' { $thetext = "System.Object"; }
| 'sbyte' { $thetext = "System.SByte"; }
| 'short' { $thetext = "System.Int16"; }
| 'string' { $thetext = "System.String"; }
| 'uint' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.Int32" : "System.UInt32";
if (Cfg.UnsignedNumbersToBiggerSignedNumbers)
$thetext = "System.Int64";
}
| 'ulong' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.Int64" : "System.UInt64";
if (Cfg.UnsignedNumbersToBiggerSignedNumbers)
$thetext = "System.Int64";
}
| 'ushort' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.Int16" : "System.UInt16";
if (Cfg.UnsignedNumbersToBiggerSignedNumbers)
$thetext = "System.Int32";
}
;
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;
keyword:
'abstract' | 'as' | 'base' | 'bool' | 'break' | 'byte' | 'case' | 'catch' | 'char' | 'checked' | 'class' | 'const' | 'continue' | 'decimal' | 'default' | 'delegate' | 'do' | 'double' | 'else' | 'enum' | 'event' | 'explicit' | 'extern' | 'false' | 'finally' | 'fixed' | 'float' | 'for' | 'foreach' | 'goto' | 'if' | 'implicit' | 'in' | 'int' | 'interface' | 'internal' | 'is' | 'lock' | 'long' | 'namespace' | 'new' | 'null' | 'object' | 'operator' | 'out' | 'override' | 'params' | 'private' | 'protected' | 'public' | 'readonly' | 'ref' | 'return' | 'sbyte' | 'sealed' | 'short' | 'sizeof' | 'stackalloc' | 'static' | 'string' | 'struct' | 'switch' | 'this' | 'throw' | 'true' | 'try' | 'typeof' | 'uint' | 'ulong' | 'unchecked' | 'unsafe' | 'ushort' | 'using' | 'virtual' | 'void' | 'volatile' ;
also_keyword:
'add' | 'alias' | 'assembly' | 'module' | 'field' | 'method' | 'param' | 'property' | 'type' | 'yield'
| 'from' | 'into' | 'join' | 'on' | 'where' | 'orderby' | 'group' | 'by' | 'ascending' | 'descending'
| 'equals' | 'select' | 'pragma' | 'let' | 'remove' | 'get' | 'set' | 'var' | '__arglist' | 'dynamic' | 'elif'
| 'endif' | 'define' | 'undef' | 'extends';
literal
@init {
string newText = null;
}
@after{
if (newText != null) {
$literal.tree.Token.Text = newText;
}
}:
Real_literal
| n=NUMBER
{
// Remove '[uU]' from any trailing integer suffix
newText = $n.text.Replace("u","").Replace("U","");
if (newText.Length < $n.text.Length) {
{ Warning($n.line, "[UNSUPPORTED] Unsigned number literal converted to signed number: " + $n.text + " -> " + newText); } ;
}
}
-> {UInt64.Parse($n.text.TrimEnd(new Char[] {'u','U','l','L'})) > Int32.MaxValue}? LONGNUMBER[$n.token, newText]
-> $n
| h=Hex_number
{
// Remove '[uU]' from any trailing integer suffix
newText = $h.text.Replace("u","").Replace("U","");
if (newText.Length < $h.text.Length) {
{ Warning($h.line, "[UNSUPPORTED] Unsigned number literal converted to signed number: " + $h.text + " -> " + newText); } ;
}
}
| Character_literal
| STRINGLITERAL
| Verbatim_string_literal
| TRUE
| FALSE
| NULL
;
void_type:
v='void' -> ^(TYPE[$v.token, "TYPE"] $v);
magicIdentifier[IToken tok, string text]:
-> IDENTIFIER[tok, text]
;
magicThrowableType[bool isOn, IToken tok]:
-> {isOn}? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, Cfg.TranslatorExceptionIsThrowable ? "Throwable" : "Exception"])
->
;
magicCatchVar:
-> IDENTIFIER["__dummyCatchVar" + dummyCatchVarCtr++];
magicPropGetter[CommonTree atts, CommonTree localatts, CommonTree mods, CommonTree localmods, CommonTree type, IToken getTok, CommonTree body, string propName, bool mkBody, string varName]
@init {
CommonTree realBody = body;
}:
b=magicGetterBody[mkBody,getTok,varName] { if (mkBody) realBody = $b.tree; } e=magicThrowsException[!mkBody && Cfg.TranslatorBlanketThrow,getTok]
-> ^(METHOD[$type.token, "METHOD"] { dupTree(mods) } { dupTree(type)} IDENTIFIER[getTok, "get"+propName] { dupTree(realBody) } magicThrowsException?)
;
magicPropSetter[CommonTree atts, CommonTree localatts, CommonTree mods, CommonTree localmods, CommonTree type, IToken setTok, CommonTree body, string propName, bool mkBody, string varName]
@init {
CommonTree realBody = body;
}:
b=magicSetterBody[mkBody,setTok,varName] { if (mkBody) realBody = $b.tree; } e=magicThrowsException[!mkBody && Cfg.TranslatorBlanketThrow,setTok]
-> ^(METHOD[$type.token, "METHOD"] { dupTree(mods) } ^(TYPE[setTok, "TYPE"] IDENTIFIER[setTok, "void"] ) IDENTIFIER[setTok, "set"+propName] ^(PARAMS[setTok, "PARAMS"] { dupTree(type)} IDENTIFIER[setTok, "value"]) { dupTree(realBody) } magicThrowsException? )
;
magicSemi:
-> SEMI;
magicMkPropertyVar[CommonTree mods, CommonTree type, string varText] :
-> ^(FIELD[$type.token, "FIELD"] {dupTree(mods)} { dupTree(type) } IDENTIFIER[$type.token, varText])
;
magicGetterBody[bool isOn, IToken getTok, string varName]:
-> { isOn }? OPEN_BRACE[getTok,"{"] ^(RETURN[getTok, "return"] IDENTIFIER[getTok, varName]) CLOSE_BRACE[getTok,"}"]
->
;
magicSetterBody[bool isOn, IToken setTok, string varName]:
-> { isOn }? OPEN_BRACE[setTok,"{"] IDENTIFIER[setTok, varName] ASSIGN[setTok,"="] IDENTIFIER[setTok, "value"] SEMI[setTok, ";"] CLOSE_BRACE[setTok,"}"]
->
;
magicIdxGetter[CommonTree atts, CommonTree localatts, CommonTree mods, CommonTree localmods, CommonTree type, CommonTree iface, IToken getTok, CommonTree body, CommonTree idxparams]
@init {
CommonTree name = (CommonTree)adaptor.Nil;
if (iface == null) {
name = (CommonTree)adaptor.Create(IDENTIFIER, getTok, "get___idx");
} else {
adaptor.AddChild(name, dupTree(iface));
adaptor.AddChild(name, (CommonTree)adaptor.Create(DOT, getTok, "."));
adaptor.AddChild(name, (CommonTree)adaptor.Create(IDENTIFIER, getTok, "get___idx"));
}
}:
magicThrowsException[Cfg.TranslatorBlanketThrow,getTok]
-> ^(METHOD[$type.token, "METHOD"] { dupTree(mods) } { dupTree(type)} { name } { dupTree(idxparams) } { dupTree(body) } magicThrowsException?)
;
magicIdxSetter[CommonTree atts, CommonTree localatts, CommonTree mods, CommonTree localmods, CommonTree type, CommonTree iface, IToken setTok, CommonTree body, CommonTree idxparams]
@init {
CommonTree name = (CommonTree)adaptor.Nil;
if (iface == null) {
name = (CommonTree)adaptor.Create(IDENTIFIER, setTok, "set___idx");
} else {
adaptor.AddChild(name, dupTree(iface));
adaptor.AddChild(name, (CommonTree)adaptor.Create(DOT, setTok, "."));
adaptor.AddChild(name, (CommonTree)adaptor.Create(IDENTIFIER, setTok, "set___idx"));
}
CommonTree augParams = dupTree(idxparams);
adaptor.AddChild(augParams, dupTree($type));
adaptor.AddChild(augParams, (CommonTree)adaptor.Create(IDENTIFIER, setTok, "value"));
}
:
magicThrowsException[Cfg.TranslatorBlanketThrow,setTok]
-> ^(METHOD[$type.token, "METHOD"] { dupTree(mods) } ^(TYPE[setTok, "TYPE"] IDENTIFIER[setTok, "void"] ) { name } { augParams } { dupTree(body) } magicThrowsException? )
;
// keving: can't get this to work reasonably
//magicMkConstModifiers[IToken tok, List<string> filter]:
// ({ !filter.Contains("static") }?=> -> STATIC[tok, "static"] ) ( { !filter.Contains("public") }?=> -> $magicMkConstModifiers FINAL[tok, "final"] );
magicSmotherExceptions[CommonTree body]:
magicSmotherExceptionsThrow[body, "RuntimeException"]
;
magicSmotherExceptionsThrow[CommonTree body, string exception]:
v=magicCatchVar magicThrowableType[true, body.Token]
-> OPEN_BRACE["{"]
^(TRY["try"]
{ dupTree(body) }
^(CATCH["catch"] magicThrowableType { dupTree($v.tree) }
OPEN_BRACE["{"] ^(THROW["throw"] ^(NEW["new"] ^(TYPE["TYPE"] IDENTIFIER[exception]) ^(ARGS["ARGS"] { dupTree($v.tree) }))) CLOSE_BRACE["}"]))
CLOSE_BRACE["}"]
;
// METHOD{ public static TYPE{ void } main PARAMS{ TYPE{ String [ ] } args } { APPLY{ .{ System exit } ARGS{ APPLY{ .{ Program Main } } } } ;
magicMainArgs[bool isOn, IToken tok]:
-> { isOn }?
^(ARGS[tok, "ARGS"] IDENTIFIER[tok, "args"])
->
;
magicMainApply[bool isOn, IToken tok, string klass, CommonTree args]:
-> { isOn }?
^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,klass] IDENTIFIER[tok,"Main"]) { dupTree(args) } )
->
;
magicMainExit[bool isOn, bool retInt, IToken tok, CommonTree body]:
-> { isOn && retInt }?
^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,"System"] IDENTIFIER[tok,"exit"]) ^(ARGS[tok, "ARGS"] { dupTree(body) } ) )
-> { isOn }?
{ dupTree(body) }
->
;
magicMainWrapper[bool isOn, IToken tok, CommonTree body]:
magicThrowsException[isOn,tok]
-> { isOn }?
^(METHOD[tok, "METHOD"]
PUBLIC[tok, "public"] STATIC[tok,"static"]
^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "void"])
IDENTIFIER[tok, "main"] ^(PARAMS[tok, "PARAMS"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok,"String"] OPEN_BRACKET[tok, "["] CLOSE_BRACKET[tok, "]"]) IDENTIFIER[tok, "args"])
OPEN_BRACE[tok, "{"] { dupTree(body) } SEMI[tok, ";"] CLOSE_BRACE[tok, "}"]
magicThrowsException?)
->
;
magicTry[IToken tok, CommonTree body, CommonTree catches, CommonTree fin]:
->
^(TRY[tok, "try"] { dupTree(body) } { dupTree(catches) } { dupTree(fin) })
;
magicDispose[IToken tok, string var, string disposeMethod]:
-> ^(IF[tok, "if"] ^(NOT_EQUAL[tok, "!="] IDENTIFIER[tok, var] NULL[tok, "null"]) SEP
^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] IDENTIFIER[tok, "Disposable"] IDENTIFIER[tok, "mkDisposable"]) ^(ARGS[tok,"ARGS"] IDENTIFIER[tok, var])) IDENTIFIER[tok, disposeMethod])) SEMI[tok, ";"])
;
magicFinally[IToken tok, CommonTree statement_list]:
->
^(FINALLY[tok, "finally"] OPEN_BRACE[tok, "{"] { dupTree(statement_list) } CLOSE_BRACE[tok, "}"])
;
magicFinalize[IToken tok, CommonTree body]:
magicThrowsException[Cfg.TranslatorBlanketThrow,tok]
->
^(METHOD[tok, "METHOD"]
PROTECTED[tok, "protected"]
^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "void"]) IDENTIFIER[tok, "finalize"]
OPEN_BRACE[tok, "{"]
^(TRY[tok, "try"] { dupTree(body) }
^(FINALLY[tok, "finally"] OPEN_BRACE[tok, "{"] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] SUPER[tok,"super"] IDENTIFIER[tok,"finalize"])) SEMI[tok, ";"] CLOSE_BRACE[tok, "}"]))
CLOSE_BRACE[tok, "}"]
// Always throws Throwable to match Object.finalize()
EXCEPTION[tok, "Throwable"])
;
magicDefaultConstructor[IToken tok, string name]:
->
^(CONSTRUCTOR[tok, "CONSTRUCTOR"]
PUBLIC[tok, "public"]
IDENTIFIER[tok, name]
OPEN_BRACE[tok, "{"]
CLOSE_BRACE[tok, "}"]
)
;
magicThrowsException[bool isOn, IToken tok]:
-> {isOn}? EXCEPTION[tok, Cfg.TranslatorExceptionIsThrowable ? "Throwable" : "Exception"]
->
;
magicDelegateInterface[IToken tok, CommonTree return_type, CommonTree identifier, CommonTree formal_parameter_list, List<String> tyArgs]
@init {
AddToImports("java.util.List");
}:
e1=magicThrowsException[Cfg.TranslatorBlanketThrow, tok]
e2=magicThrowsException[Cfg.TranslatorBlanketThrow, tok]
-> OPEN_BRACE[tok, "{"] // System.Collections.Generic.IList
^(METHOD[tok, "METHOD"] { dupTree(return_type) } IDENTIFIER[tok,"Invoke"] { dupTree(formal_parameter_list) } $e1?)
^(METHOD[tok, "METHOD"] ^(TYPE ^(DOT[tok, "."] ^(DOT[tok, "."] ^(DOT[tok, "."] IDENTIFIER[tok, "System"] IDENTIFIER[tok, "Collections"]) IDENTIFIER[tok, "Generic"]) IDENTIFIER[tok, "IList"] LTHAN[tok,"<"] ^(TYPE { dupTree( identifier) } { mkGenericArgs(tok, tyArgs) }) GT[tok,">"])) IDENTIFIER[tok,"GetInvocationList"] $e2?)
CLOSE_BRACE[tok, "}"]
;
// First execute all but the last one, then execute the last one and (if non-void) return its result.
// List<CompleteCallback> copy, members = this.GetInvocationList();
// synchronized (members) {
// copy = new LinkedList<CompleteCallback>(members);
// }
// for (CompleteCallback d : copy)
// {
// d.Invoke(name, result);
// }
//
magicMultiInvokerMethod[IToken tok, CommonTree return_type, bool retIsVoid, CommonTree type, CommonTree formal_parameter_list, CommonTree argument_list, List<String> tyArgs]
:
e1=magicThrowsException[Cfg.TranslatorBlanketThrow, tok]
-> {retIsVoid}?
^(METHOD[tok, "METHOD"] PUBLIC[tok, "public"] { dupTree($return_type) } IDENTIFIER[tok,"Invoke"] { dupTree($formal_parameter_list) }
OPEN_BRACE[tok, "{"]
^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "IList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) IDENTIFIER[tok, "copy"] COMMA[tok, ","] IDENTIFIER[tok, "members"] ASSIGN[tok, "="] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"])) SEMI[tok, ";"]
^(SYNCHRONIZED[tok, "synchronized"] IDENTIFIER[tok, "members"] OPEN_BRACE[tok, "{"]
IDENTIFIER[tok, "copy"] ASSIGN[tok, "="] ^(NEW[tok, "new"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "LinkedList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) ^(ARGS[tok, "ARGS"] IDENTIFIER[tok, "members"])) SEMI[tok, ";"]
CLOSE_BRACE[tok, "}"]
)
^(FOREACH[tok, "foreach"]
{ $type } IDENTIFIER[tok, "d"] IDENTIFIER[tok, "copy"]
SEP[tok, "SEP"]
OPEN_BRACE[tok, "{"]
^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,"d"] IDENTIFIER[tok,"Invoke"]) { $argument_list }) SEMI[tok, ";"]
CLOSE_BRACE[tok, "}"]
)
CLOSE_BRACE[tok, "}"]
magicThrowsException?
)
-> ^(METHOD[tok, "METHOD"] PUBLIC[tok, "public"] { dupTree($return_type) } IDENTIFIER[tok,"Invoke"] { dupTree($formal_parameter_list) }
OPEN_BRACE[tok, "{"]
^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "IList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) IDENTIFIER[tok, "copy"] COMMA[tok, ","] IDENTIFIER[tok, "members"] ASSIGN[tok, "="] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"])) SEMI[tok, ";"]
^(SYNCHRONIZED[tok, "synchronized"] IDENTIFIER[tok, "members"] OPEN_BRACE[tok, "{"]
IDENTIFIER[tok, "copy"] ASSIGN[tok, "="] ^(NEW[tok, "new"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "LinkedList"] LTHAN[tok, "<"] { dupTree($type) } GT[tok, ">"]) ^(ARGS[tok, "ARGS"] IDENTIFIER[tok, "members"])) SEMI[tok, ";"]
CLOSE_BRACE[tok, "}"]
)
{ $type } IDENTIFIER[tok, "prev"] ASSIGN[tok, "="] NULL[tok, "null"] SEMI[tok,";"]
^(FOREACH[tok, "foreach"]
{ $type } IDENTIFIER[tok, "d"] IDENTIFIER[tok, "copy"]
SEP[tok, "SEP"]
OPEN_BRACE[tok, "{"]
^(IF[tok, "if"] ^(NOT_EQUAL[tok, "!="] IDENTIFIER[tok,"prev"] NULL[tok, "null"]) SEP ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,"prev"] IDENTIFIER[tok,"Invoke"]) { $argument_list }) SEMI[tok, ";"])
IDENTIFIER[tok, "prev"] ASSIGN[tok, "="] IDENTIFIER[tok, "d"] SEMI[tok,";"]
CLOSE_BRACE[tok, "}"]
)
^(RETURN[tok, "return"] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] IDENTIFIER[tok,"prev"] IDENTIFIER[tok,"Invoke"]) { $argument_list }))
CLOSE_BRACE[tok, "}"]
magicThrowsException?
)
;
magicPackage[IToken tok, CommonTree cu, String ns]:
-> { $cu != null }? ^(PACKAGE[tok, "package"] PAYLOAD[tok, ns] { dupTree(cu) })
->
;
magicMultiDelClass[IToken tok, CommonTree atts, CommonTree mods, string className, CommonTree delIface, CommonTree paramConstraints, CommonTree tyParamList, CommonTree invokeMethod, CommonTree members]:
-> ^(CLASS[tok, "class"] { dupTree($atts) } { dupTree($mods) } IDENTIFIER[tok, className] { dupTree(paramConstraints) } { dupTree(tyParamList) } ^(IMPLEMENTS[tok, "implements"] { dupTree(delIface) })
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, "}"] );
magicBoxedType[bool isOn, IToken tok, String boxedName]:
-> { isOn }? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, boxedName])
->
;
magicNumber[bool isOn, IToken tok, string number]:
-> { isOn }? NUMBER[tok, number]
->
;
magicIncrement[bool isOn, IToken tok, CommonTree prevExpr]:
-> { isOn }? ^(PLUS[tok, "+"] { dupTree(prevExpr) } NUMBER[tok, "1"])
->
;