diff --git a/CS2JLibrary/NetFramework/System/Collections/Generic/IList'1.xml b/CS2JLibrary/NetFramework/System/Collections/Generic/IList'1.xml new file mode 100644 index 0000000..b03e750 --- /dev/null +++ b/CS2JLibrary/NetFramework/System/Collections/Generic/IList'1.xml @@ -0,0 +1,209 @@ + + + + + java.util.List + + List*[${T}]* + System.Collections.Generic.IList + + T + + + + + + + T + ${expr} + + + + + ${this:16}.add(${arg}) + + + T + arg + + + Add + + System.Int32 + + + + java.util.Arrays + + ${this:16}.addAll(Arrays.asList(${arg})) + + + T[] + arg + + + AddRange + System.Void + + + + ${this:16}.addAll(${arg}) + + + System.Collections.Generic.IEnumerable*[T]* + arg + + + AddRange + System.Void + + + + ${this:16}.clear() + + Clear + System.Void + + + + ${this:16}.contains(${key}) + + + T + key + + + Contains + System.Boolean + + + + ${this:16}.add(${index}, ${value}) + + + System.Int32 + index + + + T + value + + + Insert + System.Void + + + + ${this:16}.remove(${value}) + + + T + value + + + Remove + System.Boolean + + + + ${this:16}.remove((int)${value}) + + + System.Int32 + index + + + RemoveAt + System.Void + + + ${this:16}.toArray(new ${T}[${this}.size()]) + + + ToArray + T[] + + + + java.util.Collections + + Collections.sort(${this}) + + Sort + System.Void + + + + + + ${this:16}.size() + System.Int32 + Count + ${this:16}.size() + ${this:16}.setCount(${value}) + + + + + + + + + System.Int32 + i + + + T + ${this:16}.get(${i}) + ${this:16}.add(${i}, ${value}) + + + + + + new ArrayList*[${T}]*() + + + + + new ArrayList*[${T}]*(${length}) + + + System.Int32 + length + + + + + new ArrayList*[${T}]*(Arrays.asList(${collection})) + + + T[] + collection + + + + + + new ArrayList*[${T}]*(${collection}) + + + System.IEnumerable[T] + collection + + + + + + + + +rUong3D9EauJhCA+cIiWlGuXn08=esb0vH9iEN6TefBNnLiampoglnuOe2oggi0NVh+r9eoUKf6vzAQCfNGubdlKaf8IausdKZ3wS212MtQtXkJ8TFKPjK+gOpmoVhFKd/6rPnT5xt89+N7s5cByTPW8epjPNnAH7pEiRbzk5+JpH/xKeNCCoGoADV4L/E0TIsZRCH4= diff --git a/CS2JLibrary/src/CS2JNet/JavaSupport/util/ListSupport.java b/CS2JLibrary/src/CS2JNet/JavaSupport/util/ListSupport.java new file mode 100644 index 0000000..8be9c43 --- /dev/null +++ b/CS2JLibrary/src/CS2JNet/JavaSupport/util/ListSupport.java @@ -0,0 +1,93 @@ +/* + Copyright 2010,2011 Kevin Glynn (kevin.glynn@twigletsoftware.com) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author(s): + + Kevin Glynn (kevin.glynn@twigletsoftware.com) +*/ + +package CS2JNet.JavaSupport.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author keving + * + */ +public class ListSupport { + + // If the sequence of elements in stretch appears in l, then returns a new list, a copy of l without + // the final such sequence. Otherwise returns l. + public static List removeFinalStretch(List l, List stretch) { + List ret = l; + boolean found = true; + int endIdx = l.size() - 1; + while (endIdx >= stretch.size() - 1) { + // is this the start of a sequence of stretch? + found = true; + for (int j = 0; j < stretch.size(); j++) { + if (l.get(endIdx - j) != stretch.get(stretch.size() - j - 1)) { + found = false; + break; + } + } + if (found) { + break; + } + endIdx--; + } + if (found) { + // stretch starts at l(endIdx - stretch.size()) + // don't use subList, create a totally new list. + ret = new ArrayList(l.size() - stretch.size()); + for (int i = 0; i <= endIdx - stretch.size(); i++){ + ret.add(l.get(i)); + } + for (int i = endIdx+1; i < l.size(); i++){ + ret.add(l.get(i)); + } + } + + return ret; + } + + public static void main(String[] args) { + List master = Arrays.asList(new Integer[] {0,1,2,3,4,5,1,2,3,4,5}); + List find0 = Arrays.asList(new Integer[] {0}); + List find1 = Arrays.asList(new Integer[] {2,3,4}); + List find2 = Arrays.asList(new Integer[] {2,4}); + List find3 = Arrays.asList(new Integer[] {4,5}); + + for (int i : removeFinalStretch(master,find0)) { + System.out.printf("%1d ",i); + } + System.out.println(); + for (int i : removeFinalStretch(master,find1)) { + System.out.printf("%1d ",i); + } + System.out.println(); + for (int i : removeFinalStretch(master,find2)) { + System.out.printf("%1d ",i); + } + System.out.println(); + for (int i : removeFinalStretch(master,find3)) { + System.out.printf("%1d ",i); + } + System.out.println(); + } + +} diff --git a/CSharpTranslator/antlr3/src/CS2JTemplateGenerator/Main.cs b/CSharpTranslator/antlr3/src/CS2JTemplateGenerator/Main.cs index 1ad92f8..6e49007 100755 --- a/CSharpTranslator/antlr3/src/CS2JTemplateGenerator/Main.cs +++ b/CSharpTranslator/antlr3/src/CS2JTemplateGenerator/Main.cs @@ -224,8 +224,9 @@ namespace Twiglet.CS2J.Utility MethodInfo invoker = t.GetMethod("Invoke"); if (invoker == null) throw new Exception("Unexpected: class " + t.FullName + " inherits from System.Delegate but doesn't have an Invoke method"); - buildParameters(d.Params, invoker); - d.Return = TypeHelper.buildTypeName(invoker.ReturnType); + List pars = new List(); + buildParameters(pars, invoker); + d.Invoke = new InvokeRepTemplate(TypeHelper.buildTypeName(invoker.ReturnType), "Invoke", null, pars); } private IList mkTemplates(string typeName) diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs index ad19829..c5eb9ef 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs @@ -11,6 +11,15 @@ namespace Twiglet.CS2J.Translator public class Fragments { + public static string DelegateObject(String delName, String args, String body) + { + return delegateObject.Replace("${D}",delName).Replace("${A}",args).Replace("${B}",body); + } + + private static string delegateObject = @" + new ${D}() { public void Invoke(${A}) { ${B}; } } +"; + public static string GenericCollectorMethods(string T, string S) { return genericCollectorMethodsStr.Replace("${T}", T).Replace("${S}", S); @@ -153,6 +162,39 @@ namespace Twiglet.CS2J.Translator } "; + public static string MultiDelegateMethods(string Del, string DelClass, string TyArgs) + { + return multiDelegateMethodsStr.Replace("${Del}", Del).Replace("${DelClass}", DelClass).Replace("${TyArgs}", TyArgs); + } + + private static string multiDelegateMethodsStr = @" + private System.Collections.Generic.IList<${Del}> _invocationList = new ArrayList<${Del}>(); + + public static ${Del} Combine ${TyArgs} (${Del} a, ${Del} b) throws Exception { + ${DelClass} ret = new ${DelClass}(); + ret._invocationList = a.GetInvocationList(); + ret._invocationList.addAll(b.GetInvocationList()); + return ret; + } + + public static ${Del} Remove ${TyArgs} (${Del} a, ${Del} b) throws Exception { + System.Collections.Generic.IList<${Del}> aInvList = a.GetInvocationList(); + System.Collections.Generic.IList<${Del}> newInvList = ListSupport.removeFinalStretch(aInvList, b.GetInvocationList()); + if (aInvList == newInvList) { + return a; + } + else { + ${DelClass} ret = new ${DelClass}(); + ret._invocationList = newInvList; + return ret; + } + } + + public System.Collections.Generic.IList<${Del}> GetInvocationList() throws Exception { + return _invocationList; + } +"; + public static string GenIterator = @" public Iterator<${T}> iterator() { Iterator<${T}> ret = null; diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs index 63ca763..04b521d 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Templates.cs @@ -279,7 +279,16 @@ braceblock(statements) ::= << cast_expr(type, exp) ::= ""()"" construct(type, args, inits) ::= ""new () /* [UNIMPLEMENTED] */"" -array_construct(type, args, inits) ::= ""new []"" +delegate(type, args, body) ::= << +new () + { + + } +>> +lambda(args, body) ::= << +() => +>> +array_construct(type, args, inits) ::= ""new []"" array_initializer(init) ::= ""{ }"" application(func, funcparens, args) ::= ""()"" index(func, funcparens, args) ::= ""[]"" diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTemplate/TranslationTemplate.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTemplate/TranslationTemplate.cs index a48045e..2f0d774 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTemplate/TranslationTemplate.cs +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTemplate/TranslationTemplate.cs @@ -897,6 +897,22 @@ namespace Twiglet.CS2J.Translator.TypeRep } + public class InvokeRepTemplate : MethodRepTemplate + { + public InvokeRepTemplate() + { + + } + public InvokeRepTemplate (string retType, string methodName, string[] tParams, List pars) : base(retType, methodName, tParams, pars) + { + } + + public override string mkJava() + { + return "${this:16}.Invoke" + mkJavaParams(this.Params); + } + } + // A user-defined cast from one type to another public class CastRepTemplate : TranslationBase, IEquatable { @@ -2540,41 +2556,16 @@ namespace Twiglet.CS2J.Translator.TypeRep [XmlType("Delegate")] public class DelegateRepTemplate : TypeRepTemplate, IEquatable { - private List _params = null; - [XmlArrayItem("Param")] - public List Params { + private InvokeRepTemplate _invoke = null; + public InvokeRepTemplate Invoke { get { - if (_params == null) - _params = new List (); - return _params; + return _invoke; } set { - _params = value; + _invoke = value; } } - private string _return; - public string Return { - get { return _return; } - set { - _return=value.Replace("<","*[").Replace(">","]*"); - } - } - - protected string _javaInvoke = null; - [XmlElementAttribute("Invoke")] - public virtual string JavaInvoke { - get { - if (_javaInvoke == null) { - return "${this:16}.Invoke" + mkJavaParams(Params); - } - else { - return _javaInvoke; - } - } - set { _javaInvoke = value; } - } - public DelegateRepTemplate() : base() { @@ -2583,41 +2574,15 @@ namespace Twiglet.CS2J.Translator.TypeRep public DelegateRepTemplate(DelegateRepTemplate copyFrom) : base(copyFrom) { - foreach (ParamRepTemplate p in copyFrom.Params) + if (copyFrom.Invoke != null) { - Params.Add(new ParamRepTemplate(p)); + Invoke = copyFrom.Invoke; } - - if (!String.IsNullOrEmpty(copyFrom.Return)) - { - Return = copyFrom.Return; - } - if (!String.IsNullOrEmpty(copyFrom.JavaInvoke)) - { - JavaInvoke = copyFrom.JavaInvoke; - } - } - - public DelegateRepTemplate(string retType, List args) - : base() - { - Return = retType; - _params = args; } public override void Apply(Dictionary args) { - if (Params != null) - { - foreach(ParamRepTemplate p in Params) - { - p.Apply(args); - } - } - if (Return != null) - { - Return = TemplateUtilities.SubstituteInType(Return, args); - } + Invoke.Apply(args); base.Apply(args); } public override TypeRepTemplate Instantiate(ICollection args) @@ -2633,16 +2598,7 @@ namespace Twiglet.CS2J.Translator.TypeRep if (other == null) return false; - if (Params != other.Params) { - if (Params == null || other.Params == null || Params.Count != other.Params.Count) - return false; - for (int i = 0; i < Params.Count; i++) { - if (Params[i] != other.Params[i]) - return false; - } - } - - return Return == other.Return && JavaInvoke == other.JavaInvoke && base.Equals(other); + return Invoke == other.Invoke && base.Equals(other); } public override bool Equals (object obj) @@ -2668,12 +2624,8 @@ namespace Twiglet.CS2J.Translator.TypeRep public override int GetHashCode () { int hashCode = base.GetHashCode (); - if (Params != null) { - foreach (ParamRepTemplate e in Params) { - hashCode ^= e.GetHashCode(); - } - } - return (Return ?? String.Empty).GetHashCode() ^ (JavaInvoke ?? String.Empty).GetHashCode() ^ hashCode; + + return (Invoke ?? new InvokeRepTemplate()).GetHashCode() ^ hashCode; } #endregion } @@ -2897,6 +2849,56 @@ namespace Twiglet.CS2J.Translator.TypeRep } } } + // Look for a property which holds a delegate with the right type + if (Properties != null) + { + foreach (PropRepTemplate p in Properties) + { + if (p.Name == name) + { + // Is p's type a delegate? + DelegateRepTemplate del = BuildType(p.Type, AppEnv, null) as DelegateRepTemplate; + if (del != null) + { + bool matchingArgs = true; + if (del.Invoke.Params == null || args == null) + { + // Are they both zero length? + matchingArgs = (del.Invoke.Params == null || del.Invoke.Params.Count == 0) && (args == null || args.Count == 0); + } + else + { + // Are num args the same? + if (del.Invoke.Params.Count != args.Count) + { + matchingArgs = false; + } + else + { + // check that for each argument in the caller its type 'IsA' the type of the formal argument + for (int idx = 0; idx < del.Invoke.Params.Count; idx++) { + if (args[idx] == null || !args[idx].IsA(BuildType(del.Invoke.Params[idx].Type, AppEnv, new UnknownRepTemplate(del.Invoke.Params[idx].Type)),AppEnv)) + { + matchingArgs = false; + break; + } + } + } + } + if (matchingArgs) + { + ResolveResult delRes = new ResolveResult(); + delRes.Result = del; + delRes.ResultType = BuildType(del.Invoke.Return, AppEnv); + DelegateResolveResult res = new DelegateResolveResult(); + res.Result = p; + res.ResultType = BuildType(p.Type, AppEnv); + res.DelegateResult = delRes; + return res; } + } + } + } + } return base.Resolve(name, args, AppEnv); } @@ -3202,6 +3204,63 @@ namespace Twiglet.CS2J.Translator.TypeRep } + public override ResolveResult Resolve(String name, List args, DirectoryHT AppEnv) + { + + // Look for a property which holds a delegate with the right type + if (Fields != null) + { + foreach (FieldRepTemplate f in Fields) + { + if (f.Name == name) + { + // Is f's type a delegate? + DelegateRepTemplate del = BuildType(f.Type, AppEnv, null) as DelegateRepTemplate; + if (del != null) + { + bool matchingArgs = true; + if (del.Invoke.Params == null || args == null) + { + // Are they both zero length? + matchingArgs = (del.Invoke.Params == null || del.Invoke.Params.Count == 0) && (args == null || args.Count == 0); + } + else + { + // Are num args the same? + if (del.Invoke.Params.Count != args.Count) + { + matchingArgs = false; + } + else + { + // check that for each argument in the caller its type 'IsA' the type of the formal argument + for (int idx = 0; idx < del.Invoke.Params.Count; idx++) { + if (args[idx] == null || !args[idx].IsA(BuildType(del.Invoke.Params[idx].Type, AppEnv, new UnknownRepTemplate(del.Invoke.Params[idx].Type)),AppEnv)) + { + matchingArgs = false; + break; + } + } + } + } + if (matchingArgs) + { + ResolveResult delRes = new ResolveResult(); + delRes.Result = del; + delRes.ResultType = BuildType(del.Invoke.Return, AppEnv); + DelegateResolveResult res = new DelegateResolveResult(); + res.Result = f; + res.ResultType = BuildType(f.Type, AppEnv); + res.DelegateResult = delRes; + return res; + } + } + } + } + } + return base.Resolve(name, args, AppEnv); + } + public override ResolveResult Resolve(String name, bool forWrite, DirectoryHT AppEnv) { @@ -3585,6 +3644,13 @@ namespace Twiglet.CS2J.Translator.TypeRep } - + // Used when the result of resolving the callee of an APPLY node is a pointer to a delegate + public class DelegateResolveResult : ResolveResult + { + public ResolveResult DelegateResult + { + get; set; + } + } } diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g index 7291be6..cfe5996 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g @@ -190,6 +190,99 @@ scope TypeContext { return root; } + protected CommonTree mkGenericArgs(IToken tok, List 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 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; + root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(ARGS, tok, "ARGS"), root); + + // take every second child + for (int i = 1; i < adaptor.GetChildCount(pars); i+=2) { + adaptor.AddChild(root, dupTree((CommonTree)adaptor.GetChild(pars, i))); + } + root = (CommonTree)adaptor.RulePostProcessing(root); + return root; + } + + protected CommonTree mkType(IToken tok, CommonTree id, List 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 tyargs) { + StringBuilder ty = new StringBuilder(); + ty.Append(tyName); + ty.Append(mkTypeArgString(tyargs)); + return ty.ToString(); + } + + protected string mkTypeArgString(List 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) @@ -384,31 +477,38 @@ namespace_member_declaration } @after { if (isCompUnit) { - if (CUKeys.Contains(ns+"."+$ty.name)) { - { Warning($ty.start.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + ns+"."+$ty.name); } - } - else { - CUMap.Add(ns+"."+$ty.name, new CUnit($namespace_member_declaration.tree,CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces)); - CUKeys.Add(ns+"."+$ty.name); - } - }; -} -: + foreach (KeyValuePair treeEntry in $ty.compUnits) { + if (treeEntry.Value != null) { + if (CUKeys.Contains(ns+"."+treeEntry.Key)) { + { Warning(treeEntry.Value.Token.Line, "[UNSUPPORTED] Cannot have a class with multiple generic type overloadings: " + ns+"."+treeEntry.Key); } + } + else { + CUMap.Add(ns+"."+treeEntry.Key, new CUnit(mkPackage(treeEntry.Value.Token, treeEntry.Value, ns),CollectSearchPath,CollectAliasKeys,CollectAliasNamespaces)); + CUKeys.Add(ns+"."+treeEntry.Key); + } + } + }; + } +}: namespace_declaration - | attributes? modifiers? ty=type_declaration[$attributes.tree, mangleModifiersForType($modifiers.tree)] { isCompUnit = true; } -> ^(PACKAGE[$ty.start.Token, "package"] PAYLOAD[ns] $ty); + | attributes? modifiers? ty=type_declaration[$attributes.tree, mangleModifiersForType($modifiers.tree)] { 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 [string name] +type_declaration[CommonTree atts, CommonTree mods] returns [Dictionary compUnits] +@init { + $compUnits = new Dictionary(); +} : ('partial') => p='partial'! { Warning($p.line, "[UNSUPPORTED] 'partial' definition"); } - (pc=class_declaration[$atts, $mods, true /* toplevel */] { $name=$pc.name; } - | ps=struct_declaration[$atts, $mods, true /* toplevel */] { $name=$ps.name; } - | pi=interface_declaration[$atts, $mods] { $name=$pi.name; }) - | c=class_declaration[$atts, $mods, true /* toplevel */] { $name=$c.name; } - | s=struct_declaration[$atts, $mods, true /* toplevel */] { $name=$s.name; } - | i=interface_declaration[$atts, $mods] { $name=$i.name; } - | e=enum_declaration[$atts, $mods] { $name=$e.name; } - | d=delegate_declaration[$atts, $mods] { $name=$d.name; } + (pc=class_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($pc.name, $pc.tree); } + | ps=struct_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($ps.name, $ps.tree); } + | pi=interface_declaration[$atts, $mods] { $compUnits.Add($pi.name, $pi.tree); } ) + | c=class_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($c.name, $c.tree); } + | s=struct_declaration[$atts, $mods, true /* toplevel */] { $compUnits.Add($s.name, $s.tree); } + | i=interface_declaration[$atts, $mods] { $compUnits.Add($i.name, $i.tree); } + | e=enum_declaration[$atts, $mods] { $compUnits.Add($e.name, $e.tree); } + | d=delegate_declaration[$atts, $mods] { $compUnits = $d.compUnits; } ; // Identifiers qualified_identifier returns [string thetext]: @@ -448,7 +548,7 @@ class_member_declaration: | cd=class_declaration[$a.tree, $m.tree, false /* toplevel */] -> $cd | sd=struct_declaration[$a.tree, $m.tree, false /* toplevel */] -> $sd | ed=enum_declaration[$a.tree, $m.tree] -> $ed - | dd=delegate_declaration[$a.tree, $m.tree] -> $dd + | dd=delegate_declaration[$a.tree, $m.tree] -> { 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, $m.modList] -> $con3 | de3=destructor_declaration -> $de3 @@ -462,12 +562,8 @@ primary_expression: // 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 - // try the simple one first, this has no argS and no expressions - // symantically could be object creation - // keving: No, try object_creation_expression first, it could be new type ( xx ) {} - // can also match delegate_creation, will have to distinguish in NetMaker.g | (object_creation_expression) => oc2=object_creation_expression -> $oc2 - | delegate_creation_expression -> delegate_creation_expression // new FooDelegate (MyFunction) + // | 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 (... @@ -617,9 +713,9 @@ unchecked_expression: default_value_expression: 'default'^ '('! type ')'! ; anonymous_method_expression: - 'delegate'^ explicit_anonymous_function_signature? block; + 'delegate'^ explicit_anonymous_function_signature? block; explicit_anonymous_function_signature: - '(' explicit_anonymous_function_parameter_list? ')' ; + '(' explicit_anonymous_function_parameter_list? ')' -> ^(PARAMS explicit_anonymous_function_parameter_list?); explicit_anonymous_function_parameter_list: explicit_anonymous_function_parameter (',' explicit_anonymous_function_parameter)* ; explicit_anonymous_function_parameter: @@ -875,16 +971,16 @@ conditional_expression: lambda_expression: anonymous_function_signature '=>' anonymous_function_body; anonymous_function_signature: - '(' (explicit_anonymous_function_parameter_list - | implicit_anonymous_function_parameter_list)? ')' - | implicit_anonymous_function_parameter_list + '(' (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 + expression -> OPEN_BRACE[$expression.tree.Token, "{"] expression CLOSE_BRACE[$expression.tree.Token, "}"] | block ; /////////////////////////////////////////////////////// @@ -1107,8 +1203,13 @@ method_body [bool smotherExceptions] returns [CommonTree exceptionList]: ; throw_exceptions: - {IsJavaish}?=> 'throws'! t1=identifier { $t1.tree.Type = EXCEPTION; } (','! tn=identifier { $tn.tree.Type = EXCEPTION; } )* + {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 = ""; @@ -1234,14 +1335,39 @@ integral_type: 'sbyte' | 'byte' | 'short' | 'ushort' | 'int' | 'uint' | 'long' | 'ulong' | 'char' ; // B.2.12 Delegates -delegate_declaration[CommonTree atts, CommonTree mods] returns [string name] +delegate_declaration[CommonTree atts, CommonTree mods] returns [Dictionary compUnits] scope TypeContext; +@init { + $compUnits = new Dictionary(); + CommonTree delClassMemberNodes = null; + CommonTree ifTree = null; + String delName = ""; + String multiDelName = ""; +} +@after { + $compUnits.Add(delName, dupTree($delegate_declaration.tree)); +} : - d='delegate' return_type identifier { $name = $identifier.text; $TypeContext::typeName = $identifier.text; } variant_generic_parameter_list? - '(' formal_parameter_list? ')' type_parameter_constraints_clauses? ';' magicInvoker[$d.token, $return_type.tree, $identifier.tree, $formal_parameter_list.tree] -> + d='delegate' return_type identifier { delName = $identifier.text; $TypeContext::typeName = $identifier.text; } variant_generic_parameter_list? {ifTree = mkType($d.token, $identifier.tree, $variant_generic_parameter_list.tyargs); } + '(' 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", Fragments.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.ArrayList"); + AddToImports("CS2JNet.JavaSupport.util.ListSupport"); + } + magicMultiDelClass[$d.token, $atts, $mods, 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) } { dupTree($mods) } identifier type_parameter_constraints_clauses? variant_generic_parameter_list? magicInvoker); + ^(INTERFACE[$d.token, "interface"] { dupTree($atts) } { dupTree($mods) } identifier { dupTree($type_parameter_constraints_clauses.tree) } { dupTree($variant_generic_parameter_list.tree) } magicDelegateInterface) + ; delegate_modifiers: modifier+ ; // 4.0 @@ -1279,9 +1405,9 @@ type_variable_name: // keving: TOTEST we drop new constraints, but what will happen in Java for this case? constructor_constraint: 'new' '(' ')' ; -return_type: - type - | void_type ; +return_type returns [string thetext]: + type {$thetext = $type.thetext; } + | void_type {$thetext = "System.Void"; }; formal_parameter_list returns [int numArgs] @init { $numArgs = 0; @@ -1917,9 +2043,59 @@ magicThrowsException[bool isOn, IToken tok]: -> ; -magicInvoker[IToken tok, CommonTree return_type, CommonTree identifier, CommonTree formal_parameter_list]: - magicThrowsException[true, tok] --> OPEN_BRACE[tok, "{"] - ^(METHOD[tok, "METHOD"] { dupTree(return_type) } IDENTIFIER[tok,"Invoke"] { dupTree(formal_parameter_list) } magicThrowsException) +magicDelegateInterface[IToken tok, CommonTree return_type, CommonTree identifier, CommonTree formal_parameter_list, List tyArgs] +@init { + AddToImports("java.util.List"); +}: + e1=magicThrowsException[true, tok] + e2=magicThrowsException[true, 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. +magicMultiInvokerMethod[IToken tok, CommonTree return_type, bool retIsVoid, CommonTree type, CommonTree formal_parameter_list, CommonTree argument_list, List tyArgs] +: + e1=magicThrowsException[true, tok] +-> {retIsVoid}? + ^(METHOD[tok, "METHOD"] PUBLIC[tok, "public"] { dupTree($return_type) } IDENTIFIER[tok,"Invoke"] { dupTree($formal_parameter_list) } + OPEN_BRACE[tok, "{"] + ^(FOREACH[tok, "foreach"] + { $type } IDENTIFIER[tok, "d"] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"])) + 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 } IDENTIFIER[tok, "prev"] ASSIGN[tok, "="] NULL[tok, "null"] SEMI[tok,";"] + ^(FOREACH[tok, "foreach"] + { $type } IDENTIFIER[tok, "d"] ^(APPLY[tok, "APPLY"] ^(DOT[tok,"."] THIS[tok,"this"] IDENTIFIER[tok,"GetInvocationList"])) + 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, "}"]) +; + diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g index 50949db..7eb699b 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g @@ -156,6 +156,7 @@ options { precedence[i] = int.MaxValue; } precedence[ASSIGN] = 1; + precedence[LAMBDA] = 1; precedence[PLUS_ASSIGN] = 1; precedence[MINUS_ASSIGN] = 1; precedence[STAR_ASSIGN] = 1; @@ -378,7 +379,7 @@ primary_expression returns [int precedence] // | ('base' brackets) => 'this' brackets primary_expression_part* // | primary_expression_start primary_expression_part* | ^(NEW type argument_list? object_or_collection_initializer?) { $precedence = precedence[NEW]; }-> construct(type = {$type.st}, args = {$argument_list.st}, inits = {$object_or_collection_initializer.st}) - | ^(NEW_DELEGATE delegate_creation_expression) // new FooDelegate (MyFunction) + | ^(NEW_DELEGATE type argument_list? class_body) -> delegate(type = {$type.st}, args = {$argument_list.st}, body={$class_body.st}) | ^(NEW_ANON_OBJECT anonymous_object_creation_expression) // new {int X, string Y} | sizeof_expression // sizeof (struct) | checked_expression -> { $checked_expression.st } // checked (... @@ -430,7 +431,7 @@ primary_expression_part: access_identifier: access_operator type_or_generic ; access_operator returns [int precedence]: - (op='.' | op='->') { $precedence = precedence[$op.token.Type]; } -> string(payload = { $op.token.Text }) ; + (op=DOT | op='->') { $precedence = precedence[$op.token.Type]; } -> string(payload = { $op.token.Text }) ; brackets_or_arguments: brackets | arguments ; brackets: @@ -479,15 +480,25 @@ rank_specifier: // dim_separators: // ','+ ; -wrapped returns [int precedence]: +wrapped returns [int precedence] +@init { + $precedence = int.MaxValue; + Dictionary templateMap = new Dictionary(); +}: ^(JAVAWRAPPEREXPRESSION expression) { $precedence = $expression.precedence; } -> { $expression.st } | ^(JAVAWRAPPERARGUMENT argument_value) { $precedence = $argument_value.precedence; } -> { $argument_value.st } - | ^(JAVAWRAPPERTYPE type) { $precedence = int.MaxValue; } -> { $type.st } + | ^(JAVAWRAPPERTYPE type) -> { $type.st } + | ^(JAVAWRAPPER t=identifier + (k=identifier v=wrapped + { + templateMap[$k.st.ToString()] = new ReplacementDescriptor($v.st != null ? $v.st.ToString() : "", $v.precedence); + } + )*) -> string(payload = {fillTemplate($t.st.ToString(), templateMap)}) ; -delegate_creation_expression: +//delegate_creation_expression: // 'new' - type_name '(' type_name ')' ; +// type_name '(' type_name ')' ; anonymous_object_creation_expression: // 'new' anonymous_object_initializer ; @@ -504,7 +515,7 @@ primary_or_array_creation_expression returns [int precedence]: // new Type[2] { } array_creation_expression returns [int precedence]: ^(NEW_ARRAY - (type ('[' expression_list ']' rank_specifiers? ai1=array_initializer? -> array_construct(type = { $type.st }, args = { $expression_list.st }, inits = { $ai1.st }) // new int[4] + (type ('[' expression_list? ']' rank_specifiers? ai1=array_initializer? -> array_construct(type = { $type.st }, args = { $expression_list.st }, inits = { $ai1.st }) // new int[4] | ai2=array_initializer -> array_construct(type = { $type.st }, inits = { $ai2.st }) ) | rank_specifier array_initializer // var a = new[] { 1, 10, 100, 1000 }; // int[] @@ -552,16 +563,7 @@ default_value_expression } -> unsupported(reason = {"default expressions are not yet supported"}, text = { someText } ) ; anonymous_method_expression: - ^('delegate' explicit_anonymous_function_signature? block); -explicit_anonymous_function_signature: - '(' 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'; - + ^('delegate' formal_parameter_list? block); /////////////////////////////////////////////////////// object_creation_expression: @@ -785,7 +787,7 @@ non_assignment_expression returns [int precedence] $precedence = int.MaxValue; }: //'non ASSIGNment' - (anonymous_function_signature '=>') => lambda_expression + (anonymous_function_signature '=>') => lambda_expression { $precedence = precedence[LAMBDA]; } -> { $lambda_expression.st; } | (query_expression) => query_expression | ^(cop=COND_EXPR ce1=non_assignment_expression ce2=expression ce3=expression) { $precedence = precedence[$cop.token.Type]; } -> cond( condexp = { $ce1.st }, thenexp = { $ce2.st }, elseexp = { $ce3.st }, @@ -809,19 +811,20 @@ non_assignment_expression returns [int precedence] // lambda Section /////////////////////////////////////////////////////// lambda_expression: - anonymous_function_signature '=>' anonymous_function_body; + anonymous_function_signature? '=>' block + { + StringTemplate lambdaText = %lambda(); + %{lambdaText}.args = $anonymous_function_signature.st; + %{lambdaText}.body = $block.st; + $st = %unsupported(); + %{$st}.reason = "to translate lambda expressions we need an explicit delegate type, try adding a cast"; + %{$st}.text = lambdaText; + } + ; anonymous_function_signature: - '(' (explicit_anonymous_function_parameter_list - | implicit_anonymous_function_parameter_list)? ')' - | implicit_anonymous_function_parameter_list + ^(PARAMS fps+=formal_parameter+) -> list(items= {$fps}, sep={", "}) + | ^(PARAMS_TYPELESS ids+=identifier+) -> list(items= {$ids}, sep={", "}) ; -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 @@ -1286,9 +1289,9 @@ jump_statement: | ^('return' expression?) -> return(exp = { $expression.st }) | ^('throw' expression?) -> throw(exp = { $expression.st }); goto_statement: - 'goto' ( identifier - | 'case' constant_expression - | 'default') ';' ; + 'goto' ( identifier -> op(op={"goto"}, post={$identifier.st}) + | 'case' constant_expression -> op(op={"goto case"}, post={$constant_expression.st}) + | 'default' -> string(payload={"goto default"}) ) ';' ; catch_clauses: c+=catch_clause+ -> seplist(items={ $c }, sep = { "\n" }) ; catch_clause: diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g index 23718fe..142de08 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g @@ -517,6 +517,249 @@ scope MkNonGeneric { adaptor.AddChild(root, (CommonTree)adaptor.DupTree(rhs)); return root; } + + // either ^(PARAMS (type identifier)*) or ^(ARGS identifier*) depending on value of formal + protected CommonTree mkParams(List inParams, bool formal, IToken tok) { + CommonTree root = (CommonTree)adaptor.Nil; + root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(formal ? PARAMS : ARGS, tok, formal ? "PARAMS" : "ARGS"), root); + foreach (ParamRepTemplate p in inParams) { + if (formal) { + TypeRepTemplate ty = findType(p.Type); + CommonTree typeRoot = (CommonTree)adaptor.Nil; + typeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), typeRoot); + adaptor.AddChild(typeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, ty.Java)); + adaptor.AddChild(root, typeRoot); + AddToImports(ty.Imports); + } + adaptor.AddChild(root, (CommonTree)adaptor.Create(IDENTIFIER, tok, p.Name)); + } + return root; + } + + // make ^(PARAMS (type identifier)*) from a List for the names + protected CommonTree mkTypedParams(List inParams, List ids, IToken tok) { + CommonTree root = (CommonTree)adaptor.Nil; + root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(PARAMS, tok, "PARAMS"), root); + CommonTree[] idsArray = ids.ToArray(); + int i = 0; + foreach (ParamRepTemplate p in inParams) { + TypeRepTemplate ty = findType(p.Type); + CommonTree typeRoot = (CommonTree)adaptor.Nil; + typeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), typeRoot); + adaptor.AddChild(typeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, ty.Java)); + adaptor.AddChild(root, typeRoot); + AddToImports(ty.Imports); + adaptor.AddChild(root, dupTree(idsArray[i])); + i++; + } + return root; + } + + // public List GetInvocationList() throws Exception { + // List ret = new ArrayList(); + // ret.add(this); + // return ret; + // } + protected CommonTree mkDelegateGetInvocationList(CommonTree delTree, TypeRepTemplate delType, IToken tok) { + +// | ^(METHOD attributes? modifiers? type member_name type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? method_body exception*) + CommonTree method = (CommonTree)adaptor.Nil; + method = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(METHOD, tok, "METHOD"), method); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(PUBLIC, tok, "public")); + + CommonTree retTypeRoot = (CommonTree)adaptor.Nil; + retTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), retTypeRoot); + adaptor.AddChild(retTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, "List")); + AddToImports("java.util.List"); + adaptor.AddChild(retTypeRoot, (CommonTree)adaptor.Create(LTHAN, tok, "<")); + CommonTree delTypeRoot = (CommonTree)adaptor.Nil; + if (delTree != null) { + delTypeRoot = dupTree(delTree); + } + else { + delTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTypeRoot); + adaptor.AddChild(delTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, delType.Java)); + AddToImports(delType.Imports); + } + adaptor.AddChild(retTypeRoot, delTypeRoot); + + adaptor.AddChild(retTypeRoot, (CommonTree)adaptor.Create(GT, tok, ">")); + + adaptor.AddChild(method, retTypeRoot); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(IDENTIFIER, tok, "GetInvocationList")); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{")); + + + CommonTree body = (CommonTree)adaptor.Nil; + + // List ret = new ArrayList(); + CommonTree retdecl = (CommonTree)adaptor.Nil; + + adaptor.AddChild(retdecl, dupTree(retTypeRoot)); + adaptor.AddChild(retdecl, (CommonTree)adaptor.Create(IDENTIFIER, tok, "ret")); + adaptor.AddChild(retdecl, (CommonTree)adaptor.Create(ASSIGN, tok, "=")); + + CommonTree newA = (CommonTree)adaptor.Nil; + newA = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(NEW, tok, "new"), newA); + + CommonTree alTypeRoot = (CommonTree)adaptor.Nil; + alTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), alTypeRoot); + adaptor.AddChild(alTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, "ArrayList")); + AddToImports("java.util.ArrayList"); + adaptor.AddChild(alTypeRoot, (CommonTree)adaptor.Create(LTHAN, tok, "<")); + + adaptor.AddChild(alTypeRoot, dupTree(delTypeRoot)); + + adaptor.AddChild(alTypeRoot, (CommonTree)adaptor.Create(GT, tok, ">")); + + adaptor.AddChild(newA, alTypeRoot); + adaptor.AddChild(retdecl, newA); + adaptor.AddChild(body, retdecl); + adaptor.AddChild(body, (CommonTree)adaptor.Create(SEMI, tok, ";")); + + // ret.add(this) + CommonTree retaddcall = (CommonTree)adaptor.Nil; + retaddcall = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(APPLY, tok, "APPLY"), retaddcall); + + CommonTree retadd = (CommonTree)adaptor.Nil; + retadd = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(DOT, tok, "."), retadd); + adaptor.AddChild(retadd, (CommonTree)adaptor.Create(IDENTIFIER, tok, "ret")); + adaptor.AddChild(retadd, (CommonTree)adaptor.Create(IDENTIFIER, tok, "add")); + + adaptor.AddChild(retaddcall, retadd); + + CommonTree arg = (CommonTree)adaptor.Nil; + arg = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(ARGS, tok, "ARGS"), arg); + + adaptor.AddChild(arg, (CommonTree)adaptor.Create(THIS, tok, "this")); + adaptor.AddChild(retaddcall, arg); + adaptor.AddChild(body,retaddcall); + adaptor.AddChild(body, (CommonTree)adaptor.Create(SEMI, tok, ";")); + + // return ret; + CommonTree ret = (CommonTree)adaptor.Nil; + ret = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(RETURN, tok, "return"), ret); + adaptor.AddChild(ret, (CommonTree)adaptor.Create(IDENTIFIER, tok, "ret")); + adaptor.AddChild(body,ret); + + adaptor.AddChild(method, body); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(CLOSE_BRACE, tok, "}")); + adaptor.AddChild(method, (CommonTree)adaptor.Create(EXCEPTION, tok, "Exception")); + + return method; + } + + // new () { public void Invoke() throws Exception { [return] arg[0](); } + // public List GetInvocationList() throws Exception { ... }} + protected CommonTree mkDelegateObject(CommonTree delTree, CommonTree methTree, DelegateRepTemplate delg, IToken tok) { + CommonTree root = (CommonTree)adaptor.Nil; + root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(NEW_DELEGATE, tok, "NEW_DELEGATE"), root); + if (delTree != null) { + adaptor.AddChild(root, dupTree(delTree)); + } + else { + CommonTree delTyTree = (CommonTree)adaptor.Nil; + delTyTree = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTyTree); + adaptor.AddChild(delTyTree, (CommonTree)adaptor.Create(IDENTIFIER, tok, delg.Java)); + AddToImports(delg.Imports); + adaptor.AddChild(root, delTyTree); + } + + adaptor.AddChild(root, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{")); + +// | ^(METHOD attributes? modifiers? type member_name type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? method_body exception*) + CommonTree method = (CommonTree)adaptor.Nil; + method = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(METHOD, tok, "METHOD"), method); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(PUBLIC, tok, "public")); + + TypeRepTemplate returnType = findType(delg.Invoke.Return); + AddToImports(returnType.Imports); + CommonTree retTypeRoot = (CommonTree)adaptor.Nil; + retTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), retTypeRoot); + adaptor.AddChild(retTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, returnType.Java)); + adaptor.AddChild(method, retTypeRoot); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(IDENTIFIER, tok, "Invoke")); + if (delg.Invoke.Params.Count > 0) { + adaptor.AddChild(method, mkParams(delg.Invoke.Params, true, tok)); + } + adaptor.AddChild(method, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{")); + + CommonTree ret = (CommonTree)adaptor.Nil; + ret = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(RETURN, tok, "return"), ret); + + CommonTree call = (CommonTree)adaptor.Nil; + call = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(APPLY, tok, "APPLY"), call); + adaptor.AddChild(call, dupTree(methTree)); + if (delg.Invoke.Params.Count > 0) { + adaptor.AddChild(call, mkParams(delg.Invoke.Params, false, tok)); + } + if (returnType.IsA(voidType, AppEnv)) { + adaptor.AddChild(ret, call); + adaptor.AddChild(method, ret); + } + else { + adaptor.AddChild(method, call); + adaptor.AddChild(method, (CommonTree)adaptor.Create(SEMI, tok, ";")); + } + + adaptor.AddChild(method, (CommonTree)adaptor.Create(CLOSE_BRACE, tok, "}")); + adaptor.AddChild(method, (CommonTree)adaptor.Create(EXCEPTION, tok, "Exception")); + adaptor.AddChild(root, method); + adaptor.AddChild(root, mkDelegateGetInvocationList(delTree, delg, tok)); + + adaptor.AddChild(root, (CommonTree)adaptor.Create(CLOSE_BRACE, tok, "}")); + + return root; + } + + // new () { public void Invoke() throw exception } + protected CommonTree mkDelegateObject(CommonTree delTree, CommonTree argsTree, CommonTree bodyTree, DelegateRepTemplate delg, IToken tok) { + CommonTree root = (CommonTree)adaptor.Nil; + root = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(NEW_DELEGATE, tok, "NEW_DELEGATE"), root); + if (delTree != null) { + adaptor.AddChild(root, dupTree(delTree)); + } + else { + CommonTree delTyTree = (CommonTree)adaptor.Nil; + delTyTree = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), delTyTree); + adaptor.AddChild(delTyTree, (CommonTree)adaptor.Create(IDENTIFIER, tok, delg.Java)); + AddToImports(delg.Imports); + adaptor.AddChild(root, delTyTree); + } + + adaptor.AddChild(root, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{")); + +// | ^(METHOD attributes? modifiers? type member_name type_parameter_constraints_clauses? type_parameter_list? formal_parameter_list? method_body exception*) + CommonTree method = (CommonTree)adaptor.Nil; + method = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(METHOD, tok, "METHOD"), method); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(PUBLIC, tok, "public")); + + TypeRepTemplate returnType = findType(delg.Invoke.Return); + AddToImports(returnType.Imports); + CommonTree retTypeRoot = (CommonTree)adaptor.Nil; + retTypeRoot = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), retTypeRoot); + adaptor.AddChild(retTypeRoot, (CommonTree)adaptor.Create(IDENTIFIER, tok, returnType.Java)); + adaptor.AddChild(method, retTypeRoot); + + adaptor.AddChild(method, (CommonTree)adaptor.Create(IDENTIFIER, tok, "Invoke")); + adaptor.AddChild(method, dupTree(argsTree)); + adaptor.AddChild(method, dupTree(bodyTree)); + adaptor.AddChild(method, (CommonTree)adaptor.Create(EXCEPTION, tok, "Exception")); + adaptor.AddChild(root, method); + adaptor.AddChild(root, mkDelegateGetInvocationList(delTree, delg, tok)); + + adaptor.AddChild(root, (CommonTree)adaptor.Create(CLOSE_BRACE, tok, "}")); + + return root; + } + } public compilation_unit @@ -589,7 +832,7 @@ constructor_declaration // rmId is the rightmost ID in an expression like fdfd.dfdsf.returnme, otherwise it is null // used in switch labels to strip down qualified types, which Java doesn't grok // thedottedtext is the text read so far that *might* be part of a qualified type -primary_expression returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] +primary_expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] scope { bool parentIsApply; } @@ -605,7 +848,7 @@ scope { if (ret != null) $primary_expression.tree = ret; }: - ^(index=INDEX ie=expression expression_list?) + ^(index=INDEX ie=expression[ObjectType] expression_list?) { expType = $ie.dotNetType ?? (new UnknownRepTemplate("INDEXER.BASE")); if (expType.IsUnknownType) { @@ -635,26 +878,26 @@ scope { WarningFailedResolve($index.token.Line, "Could not resolve index expression against " + expType.TypeName); } } - | (^(APPLY (^('.' expression identifier)|identifier) argument_list?)) => - ^(APPLY (^(d0='.' e2=expression {expType = $e2.dotNetType; implicitThis = false;} i2=identifier)|i2=identifier) argument_list?) + | (^(APPLY (^('.' expression[ObjectType] identifier generic_argument_list?)|(identifier generic_argument_list?)) argument_list?)) => + ^(APPLY (^(d0='.' e2=expression[ObjectType] {expType = $e2.dotNetType; implicitThis = false;} i2=identifier generic_argument_list?)|(i2=identifier generic_argument_list?)) argument_list?) { if (implicitThis && SymTabLookup($i2.thetext) != null) { - // we have a delegate reference (I hope ...)? + // we have a local var with a delegate reference (I hope ...)? DelegateRepTemplate idType = SymTabLookup($i2.thetext) as DelegateRepTemplate; if (idType != null) { Dictionary myMap = new Dictionary(); myMap["this"] = wrapExpression($i2.tree, $i2.tree.Token); - for (int idx = 0; idx < idType.Params.Count; idx++) { - myMap[idType.Params[idx].Name] = wrapArgument($argument_list.argTrees[idx], $i2.tree.Token); - if (idType.Params[idx].Name.StartsWith("TYPEOF") && $argument_list.argTreeTypeofTypes[idx] != null) { + for (int idx = 0; idx < idType.Invoke.Params.Count; idx++) { + myMap[idType.Invoke.Params[idx].Name] = wrapArgument($argument_list.argTrees[idx], $i2.tree.Token); + if (idType.Invoke.Params[idx].Name.StartsWith("TYPEOF") && $argument_list.argTreeTypeofTypes[idx] != null) { // if this argument is a typeof expression then add a TYPEOF_TYPEOF-> typeof's type mapping - myMap[idType.Params[idx].Name + "_TYPE"] = wrapTypeOfType($argument_list.argTreeTypeofTypes[idx], $i2.tree.Token); + myMap[idType.Invoke.Params[idx].Name + "_TYPE"] = wrapTypeOfType($argument_list.argTreeTypeofTypes[idx], $i2.tree.Token); } } - AddToImports(idType.Imports); - ret = mkJavaWrapper(idType.JavaInvoke, myMap, $i2.tree.Token); - $dotNetType = AppEnv.Search(idType.Return); - } + AddToImports(idType.Invoke.Imports); + ret = mkJavaWrapper(idType.Invoke.Java, myMap, $i2.tree.Token); + $dotNetType = AppEnv.Search(idType.Invoke.Return); + } } else { @@ -665,40 +908,54 @@ scope { WarningFailedResolve($i2.tree.Token.Line, "Could not find type needed to resolve method application"); } $dotNetType = new UnknownRepTemplate(expType.TypeName+".APPLY"); - ResolveResult methodResult = expType.Resolve($i2.thetext, $argument_list.argTypes ?? new List(), AppEnv); - if (methodResult != null) { - if (!String.IsNullOrEmpty(methodResult.Result.Warning)) Warning($d0.line, methodResult.Result.Warning); + ResolveResult calleeResult = expType.Resolve($i2.thetext, $argument_list.argTypes ?? new List(), AppEnv); + if (calleeResult != null) { + if (!String.IsNullOrEmpty(calleeResult.Result.Warning)) Warning($d0.line, calleeResult.Result.Warning); DebugDetail($i2.tree.Token.Line + ": Found '" + $i2.thetext + "'"); - - // We are calling a method on an expression. If it has a primitive type then cast it to + + // We are calling a method or a delegate on an expression. If it has a primitive type then cast it to // the appropriate Object type. CommonTree e2InBox = expType.IsUnboxedType && Cfg.ExperimentalTransforms ? castToBoxedType(expType, $e2.tree, $d0.token) : $e2.tree; - - MethodRepTemplate methodRep = methodResult.Result as MethodRepTemplate; Dictionary myMap = new Dictionary(); - if (!implicitThis) { - myMap["this"] = wrapExpression(e2InBox, $i2.tree.Token); + MethodRepTemplate calleeMethod = null; + + if (calleeResult is DelegateResolveResult) { + // We have a field/property that is pointing at a delegate, first extract the delegate ... + Dictionary delMap = new Dictionary(); + if (!implicitThis) { + delMap["this"] = wrapExpression(e2InBox, $i2.tree.Token); + } + myMap["this"] = mkJavaWrapper(calleeResult.Result.Java, delMap, $i2.tree.Token); + AddToImports(calleeResult.Result.Imports); + calleeMethod = ((DelegateRepTemplate)((DelegateResolveResult)calleeResult).DelegateResult.Result).Invoke; } - for (int idx = 0; idx < methodRep.Params.Count; idx++) { - myMap[methodRep.Params[idx].Name] = wrapArgument($argument_list.argTrees[idx], $i2.tree.Token); - if (methodRep.Params[idx].Name.StartsWith("TYPEOF") && $argument_list.argTreeTypeofTypes[idx] != null) { + else { + if (!implicitThis) { + myMap["this"] = wrapExpression(e2InBox, $i2.tree.Token); + } + calleeMethod = calleeResult.Result as MethodRepTemplate; + } + + for (int idx = 0; idx < calleeMethod.Params.Count; idx++) { + myMap[calleeMethod.Params[idx].Name] = wrapArgument($argument_list.argTrees[idx], $i2.tree.Token); + if (calleeMethod.Params[idx].Name.StartsWith("TYPEOF") && $argument_list.argTreeTypeofTypes[idx] != null) { // if this argument is a typeof expression then add a TYPEOF_TYPEOF-> typeof's type mapping - myMap[methodRep.Params[idx].Name + "_TYPE"] = wrapTypeOfType($argument_list.argTreeTypeofTypes[idx], $i2.tree.Token); + myMap[calleeMethod.Params[idx].Name + "_TYPE"] = wrapTypeOfType($argument_list.argTreeTypeofTypes[idx], $i2.tree.Token); } } - ret = mkJavaWrapper(methodResult.Result.Java, myMap, $i2.tree.Token); - AddToImports(methodResult.Result.Imports); - $dotNetType = methodResult.ResultType; + ret = mkJavaWrapper(calleeMethod.Java, myMap, $i2.tree.Token); + AddToImports(calleeMethod.Imports); + $dotNetType = calleeResult.ResultType; } else { WarningFailedResolve($i2.tree.Token.Line, "Could not resolve method application of " + $i2.thetext + " against " + expType.TypeName); } } } - | ^(APPLY {$primary_expression::parentIsApply = true; } expression {$primary_expression::parentIsApply = false; } argument_list?) - | (^((POSTINC|POSTDEC) (^('.' expression identifier) | identifier))) => - (^(POSTINC {popstr = "+";} (^('.' pse=expression pi=identifier {implicitThis = false;}) | pi=identifier)) - | ^(POSTDEC {popstr = "-";} (^('.' pse=expression pi=identifier {implicitThis = false;}) | pi=identifier))) + | ^(APPLY {$primary_expression::parentIsApply = true; } expression[ObjectType] {$primary_expression::parentIsApply = false; } argument_list?) + | (^((POSTINC|POSTDEC) (^('.' expression[objectType] identifier) | identifier))) => + (^(POSTINC {popstr = "+";} (^('.' pse=expression[ObjectType] pi=identifier {implicitThis = false;}) | pi=identifier)) + | ^(POSTDEC {popstr = "-";} (^('.' pse=expression[ObjectType] pi=identifier {implicitThis = false;}) | pi=identifier))) { if (implicitThis && SymTabLookup($pi.thetext) != null) { // Is this a wrapped parameter? @@ -762,108 +1019,69 @@ scope { WarningFailedResolve($pi.tree.Token.Line, "Could not resolve field or property expression against " + seType.ToString()); } } - } - - | ^(POSTINC expression) { $dotNetType = $expression.dotNetType; } - | ^(POSTDEC expression) { $dotNetType = $expression.dotNetType; } - | ^(d1='.' e1=expression i1=identifier generic_argument_list?) + } + | ^(POSTINC expression[ObjectType]) { $dotNetType = $expression.dotNetType; } + | ^(POSTDEC expression[ObjectType]) { $dotNetType = $expression.dotNetType; } + | ^('->' expression[ObjectType] identifier generic_argument_list?) + | predefined_type { $dotNetType = $predefined_type.dotNetType; } + | 'this' { $dotNetType = SymTabLookup("this"); } + | SUPER { $dotNetType = SymTabLookup("super"); } + | (^(d1='.' e1=expression[ObjectType] {expType = $e1.dotNetType; implicitThis = false;} i=identifier)|i=identifier) generic_argument_list? magicInputPeId[$d1.tree,$i.tree,$generic_argument_list.tree] { // TODO: generic_argument_list is ignored .... - // Possibilities: - // - accessing a property/field of some object - // - a qualified type name - // - part of a qualified type name - expType = $e1.dotNetType; - - // Is it a property read? Ensure we are not being applied to arguments or about to be assigned - if (expType != null && - ($primary_expression.Count == 1 || !((primary_expression_scope)($primary_expression.ToArray()[1])).parentIsApply)) { - - DebugDetail($d1.token.Line + ": '" + $i1.thetext + "' might be a property"); - - $dotNetType = new UnknownRepTemplate(expType.TypeName+".DOTACCESS."+ $i1.thetext); - - ResolveResult fieldResult = expType.Resolve($i1.thetext, false, AppEnv); - if (fieldResult != null) { - if (!String.IsNullOrEmpty(fieldResult.Result.Warning)) Warning($d1.line, fieldResult.Result.Warning); - - // We are calling a method on an expression. If it has a primitive type then cast it to - // the appropriate Object type. - CommonTree e1InBox = $e1.dotNetType.IsUnboxedType && Cfg.ExperimentalTransforms ? castToBoxedType($e1.dotNetType, $e1.tree, $d1.token) : $e1.tree; - - Dictionary myMap = new Dictionary(); - myMap["this"] = wrapExpression(e1InBox, $i1.tree.Token); - ret = mkJavaWrapper(fieldResult.Result.Java, myMap, $i1.tree.Token); - AddToImports(fieldResult.Result.Imports); - $dotNetType = fieldResult.ResultType; - } - else if ($e1.thedottedtext != null) { - string staticType = $e1.thedottedtext + "." + $i1.thetext; - $dotNetType = findType(staticType); - if (!$dotNetType.IsUnknownType) { - AddToImports($dotNetType.Imports); - } - else { - // remember text so far - $thedottedtext = staticType; - } - } - else { - // Could not find identifier in e1's type and we aren't building up a static type reference, so emit warning - WarningFailedResolve($i1.tree.Token.Line, "Could not resolve identifier " + $i1.thetext + " against " + expType.TypeName); - } - - } - $rmId = $identifier.thetext; - } - | ^('->' expression identifier generic_argument_list?) - | predefined_type { $dotNetType = $predefined_type.dotNetType; } - | 'this' { $dotNetType = SymTabLookup("this"); } - | SUPER { $dotNetType = SymTabLookup("super"); } - | (identifier generic_argument_list) => identifier generic_argument_list - | i=identifier - { // Possibilities: // - a variable in scope. - // - a property/field of current object + // - a property/field of some object // - a type name + // - a method name if we are in a delegate type context then create a delegate (in C# it is an implicit cast) // - part of a type name bool found = false; - TypeRepTemplate idType = SymTabLookup($identifier.thetext); - if (idType != null) { - // Is this a wrapped parameter? - if (idType.IsWrapped) { - Dictionary myMap = new Dictionary(); - myMap["this"] = wrapExpression($i.tree, $i.tree.Token); - ret = mkJavaWrapper("${this}.getValue()", myMap, $i.tree.Token); - } - $dotNetType = idType; - found = true; + if (implicitThis) { + // single identifier, might be a variable + TypeRepTemplate idType = SymTabLookup($i.thetext); + if (idType != null) { + // Is this a wrapped parameter? + if (idType.IsWrapped) { + Dictionary myMap = new Dictionary(); + myMap["this"] = wrapExpression($i.tree, $i.tree.Token); + ret = mkJavaWrapper("${this}.getValue()", myMap, $i.tree.Token); + } + $dotNetType = idType; + found = true; + } } if (!found) { - // Not a variable, is it a property? - TypeRepTemplate thisType = SymTabLookup("this"); + // Not a variable, expType is the type of 'expression', or 'this'. // Is it a property read? Ensure we are not being applied to arguments or about to be assigned - if (thisType != null && !thisType.IsUnknownType && + if (expType != null && !expType.IsUnknownType && ($primary_expression.Count == 1 || !((primary_expression_scope)($primary_expression.ToArray()[1])).parentIsApply)) { - DebugDetail($identifier.tree.Token.Line + ": '" + $identifier.thetext + "' might be a property"); - ResolveResult fieldResult = thisType.Resolve($identifier.thetext, false, AppEnv); + DebugDetail($i.tree.Token.Line + ": '" + $i.thetext + "' might be a property"); + ResolveResult fieldResult = expType.Resolve($i.thetext, false, AppEnv); if (fieldResult != null) { if (!String.IsNullOrEmpty(fieldResult.Result.Warning)) Warning($i.tree.Token.Line, fieldResult.Result.Warning); - DebugDetail($identifier.tree.Token.Line + ": Found '" + $identifier.thetext + "'"); - ret = mkJavaWrapper(fieldResult.Result.Java, null, $i.tree.Token); + DebugDetail($i.tree.Token.Line + ": Found '" + $i.thetext + "'"); + + Dictionary myMap = new Dictionary(); + if (!implicitThis) { + // We are accessing a field / property on an expression. If it has a primitive type then cast it to + // the appropriate Object type. + CommonTree e1InBox = expType.IsUnboxedType && Cfg.ExperimentalTransforms ? castToBoxedType(expType, $e1.tree, $d1.token) : $e1.tree; + myMap["this"] = wrapExpression(e1InBox, $i.tree.Token); + } + ret = mkJavaWrapper(fieldResult.Result.Java, myMap, $i.tree.Token); AddToImports(fieldResult.Result.Imports); $dotNetType = fieldResult.ResultType; found = true; } } } - if (!found) { + if (!found && (implicitThis || $e1.thedottedtext != null)) { + String textSoFar = (implicitThis ? "" : $e1.thedottedtext + ".") + $i.thetext; // Not a variable, not a property read, is it a type name? - TypeRepTemplate staticType = findType($i.thetext); + TypeRepTemplate staticType = findType(textSoFar); if (!staticType.IsUnknownType) { AddToImports(staticType.Imports); $dotNetType = staticType; @@ -871,10 +1089,25 @@ scope { } } if (!found) { - // Not a variable, not a property read, not a type, is it part of a type name? - $dotNetType = new UnknownRepTemplate($identifier.thetext); - $thedottedtext = $identifier.thetext; + // Could be a reference to a method group. If we are in a Delegate Type context then create a delegate object. + if ($typeCtxt != null && $typeCtxt is DelegateRepTemplate) { + // Since 'type' is a delegate then we assume that argument_list[0] will be a method group name. + // use an anonymous inner class to generate a delegate object (object wih an Invoke with appropriate arguments) + // new () { public void Invoke() throw exception { [return] arg[0](); } } + DelegateRepTemplate delType = $typeCtxt as DelegateRepTemplate; + ret = mkDelegateObject((CommonTree)$typeCtxt.Tree, $magicInputPeId.tree, delType, $i.tree.Token); + $dotNetType = $typeCtxt; + found = true; + } } + if (!found) { + // Not a variable, not a property read, not a type, is it part of a type name? + $dotNetType = new UnknownRepTemplate($i.thetext); + $thedottedtext = (implicitThis || String.IsNullOrEmpty($e1.thedottedtext) ? "" : $e1.thedottedtext + ".") + $i.thetext; + } + $rmId = $i.thetext; + if (ret == null) + ret = $magicInputPeId.tree; } | primary_expression_start { $dotNetType = $primary_expression_start.dotNetType; } | literal { $dotNetType = $literal.dotNetType; } @@ -883,6 +1116,26 @@ scope { // | primary_expression_start primary_expression_part* | ^(n=NEW type argument_list? object_or_collection_initializer?) { + // look for delegate creation + if ($type.dotNetType is DelegateRepTemplate && $argument_list.argTypes != null && $argument_list.argTypes.Count > 0) { + + // argument_list should consist of just a single expression, either a method group or a value of a delegate type. + // If its a delegate type, then that is the result of this expression otherwise we create a delegte object. + if ($argument_list.argTypes[0] is DelegateRepTemplate) { + ret = dupTree((CommonTree)adaptor.GetChild($argument_list.tree, 0)); + $dotNetType = $argument_list.argTypes[0]; + } + else { + // Since 'type' is a delegate then we assume that argument_list[0] will be a method group name. + // use an anonymous inner class to generate a delegate object (object wih an Invoke with appropriate arguments) + // new () { public void Invoke() throw exception { [return] arg[0](); } } + DelegateRepTemplate delType = $type.dotNetType as DelegateRepTemplate; + ret = mkDelegateObject($type.tree, (CommonTree)adaptor.GetChild($argument_list.tree, 0), delType, $n.token); + $dotNetType = $type.dotNetType; + } + } + else { + // assume object constructor ClassRepTemplate conType = $type.dotNetType as ClassRepTemplate; $dotNetType = $type.dotNetType; if (conType == null) { @@ -911,14 +1164,24 @@ scope { else if ($argument_list.argTypes != null && $argument_list.argTypes.Count > 0) { // assume we have a zero-arg constructor, so don't print warning WarningFailedResolve($n.token.Line, "Could not resolve constructor against " + conType.TypeName); } + } } - | ^(NEW_DELEGATE delegate_creation_expression) // new FooDelegate (MyFunction) | ^(NEW_ANON_OBJECT 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) {} + | ^(d='delegate' formal_parameter_list? block) + { + if ($typeCtxt != null && $typeCtxt is DelegateRepTemplate) { + // Since 'type' is a delegate then we assume that argument_list[0] will be a method group name. + // use an anonymous inner class to generate a delegate object (object wih an Invoke with appropriate arguments) + // new () { public void Invoke() throw exception { [return] arg[0](); } } + DelegateRepTemplate delType = $typeCtxt as DelegateRepTemplate; + ret = mkDelegateObject((CommonTree)$typeCtxt.Tree, $formal_parameter_list.tree, $block.tree, delType, $d.token); + $dotNetType = $typeCtxt; + } + } | typeof_expression { $dotNetType = $typeof_expression.dotNetType; $typeofType = $typeof_expression.typeofType; } // typeof(Foo).Name ; @@ -939,8 +1202,8 @@ brackets_or_arguments: brackets | arguments ; brackets: '[' expression_list? ']' ; -paren_expression: - '(' expression ')' ; +paren_expression[TypeRepTemplate typeCtxt]: + '(' expression[$typeCtxt] ')' ; arguments: '(' argument_list? ')' ; argument_list returns [List argTypes, List argTrees, List argTreeTypeofTypes] @@ -961,7 +1224,7 @@ argument_value returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType] @init { string refVar = null; }: - expression { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; } + expression[ObjectType] { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; } | ref_variable_reference { $dotNetType = $ref_variable_reference.dotNetType; $typeofType = $ref_variable_reference.typeofType; } | o='out' variable_reference { refVar = "refVar___" + dummyRefVarCtr++; } magicCreateOutVar[$o.token, refVar, ($variable_reference.dotNetType != null ? (CommonTree)$variable_reference.dotNetType.Tree : null)] @@ -995,7 +1258,7 @@ ref_variable_reference returns [TypeRepTemplate dotNetType, TypeRepTemplate type ; // lvalue variable_reference returns [TypeRepTemplate dotNetType, TypeRepTemplate typeofType]: - expression { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; }; + expression[ObjectType] { $dotNetType = $expression.dotNetType; $typeofType = $expression.typeofType; }; rank_specifiers[TypeRepTemplate inTy] returns [TypeRepTemplate dotNetType] @init { TypeRepTemplate ty = $inTy; @@ -1018,10 +1281,10 @@ anonymous_object_initializer: member_declarator_list: member_declarator (',' member_declarator)* ; member_declarator: - qid ('=' expression)? ; -primary_or_array_creation_expression returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext]: + qid ('=' expression[ObjectType])? ; +primary_or_array_creation_expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext]: (array_creation_expression) => array_creation_expression { $dotNetType = $array_creation_expression.dotNetType; $thedottedtext = null; } - | primary_expression { $dotNetType = $primary_expression.dotNetType; $rmId = $primary_expression.rmId; $typeofType = $primary_expression.typeofType; $thedottedtext = $primary_expression.thedottedtext; } + | primary_expression[$typeCtxt] { $dotNetType = $primary_expression.dotNetType; $rmId = $primary_expression.rmId; $typeofType = $primary_expression.typeofType; $thedottedtext = $primary_expression.thedottedtext; } ; // new Type[2] { } array_creation_expression returns [TypeRepTemplate dotNetType]: @@ -1037,26 +1300,15 @@ array_initializer: variable_initializer_list: variable_initializer (',' variable_initializer)* ; variable_initializer: - expression | array_initializer ; + expression[ObjectType] | array_initializer ; sizeof_expression: ^('sizeof' unmanaged_type ); checked_expression: - ^('checked' expression ) ; + ^('checked' expression[ObjectType] ) ; unchecked_expression: - ^('unchecked' expression ) ; + ^('unchecked' expression[ObjectType] ) ; 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: - 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: @@ -1073,7 +1325,7 @@ collection_initializer: element_initializer_list: element_initializer (',' element_initializer)* ; element_initializer: - non_assignment_expression + non_assignment_expression[ObjectType] | '{' expression_list '}' ; // object-initializer eg's // Rectangle r = new Rectangle { @@ -1088,7 +1340,7 @@ member_initializer_list: member_initializer: identifier '=' initializer_value ; initializer_value: - expression + expression[ObjectType] | object_or_collection_initializer ; /////////////////////////////////////////////////////// @@ -1288,10 +1540,10 @@ statement_list: /////////////////////////////////////////////////////// // Expression Section /////////////////////////////////////////////////////// -expression returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] +expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] : - (unary_expression assignment_operator) => assignment { $dotNetType = VoidType; $thedottedtext = null;} - | non_assignment_expression { $dotNetType = $non_assignment_expression.dotNetType; $rmId = $non_assignment_expression.rmId; $typeofType = $non_assignment_expression.typeofType; $thedottedtext = $non_assignment_expression.thedottedtext; } + (unary_expression[ObjectType] assignment_operator) => assignment { $dotNetType = VoidType; $thedottedtext = null;} + | non_assignment_expression[$typeCtxt] { $dotNetType = $non_assignment_expression.dotNetType; $rmId = $non_assignment_expression.rmId; $typeofType = $non_assignment_expression.typeofType; $thedottedtext = $non_assignment_expression.thedottedtext; } ; expression_list returns [List expTypes, List expTrees, List expTreeTypeofTypes] @init { @@ -1299,26 +1551,52 @@ expression_list returns [List expTypes, List expTre $expTrees = new List(); $expTreeTypeofTypes = new List(); }: - e1=expression { $expTypes.Add($e1.dotNetType); $expTrees.Add(dupTree($e1.tree)); $expTreeTypeofTypes.Add($e1.typeofType); } - (',' en=expression { $expTypes.Add($en.dotNetType); $expTrees.Add(dupTree($en.tree)); $expTreeTypeofTypes.Add($en.typeofType); })* ; + e1=expression[ObjectType] { $expTypes.Add($e1.dotNetType); $expTrees.Add(dupTree($e1.tree)); $expTreeTypeofTypes.Add($e1.typeofType); } + (',' en=expression[ObjectType] { $expTypes.Add($en.dotNetType); $expTrees.Add(dupTree($en.tree)); $expTreeTypeofTypes.Add($en.typeofType); })* ; assignment @init { CommonTree ret = null; bool isThis = false; + bool isLocalVar = false; TypeRepTemplate expType = null; + TypeRepTemplate lhsType = ObjectType; + + ResolveResult fieldResult = null; + ResolveResult indexerResult = null; } @after { if (ret != null) $assignment.tree = ret; }: - ((^('.' expression identifier generic_argument_list?) | identifier) assignment_operator) => - (^('.' se=expression i=identifier generic_argument_list?) | i=identifier { isThis = true;}) a=assignment_operator rhs=expression + ((^('.' expression[ObjectType] identifier generic_argument_list?) | identifier) assignment_operator) => + (^('.' se=expression[ObjectType] i=identifier generic_argument_list?) + | i=identifier { isThis = true; }) + { + TypeRepTemplate varType = SymTabLookup($i.thetext); + if (isThis && varType != null) { + isLocalVar = true; + lhsType = varType; + } + else { + expType = (isThis ? SymTabLookup("this") : $se.dotNetType); + if (expType == null) { + expType = new UnknownRepTemplate("FIELD.BASE"); + } + if (expType.IsUnknownType) { + WarningFailedResolve($i.tree.Token.Line, "Could not find type of expression for field /property access"); + } + fieldResult = expType.Resolve($i.thetext, true, AppEnv); + if (fieldResult != null) { + lhsType = fieldResult.ResultType ?? lhsType; + } + } + } + a=assignment_operator rhs=expression[lhsType] { - if (isThis && SymTabLookup($i.thetext) != null) { + if (isLocalVar) { // Is this a wrapped parameter? - TypeRepTemplate idType = SymTabLookup($i.thetext); - if (idType.IsWrapped) { + if (lhsType.IsWrapped) { Dictionary myMap = new Dictionary(); myMap["this"] = wrapExpression($i.tree, $i.tree.Token); myMap["value"] = wrapExpression($rhs.tree, $rhs.tree.Token); @@ -1327,14 +1605,6 @@ assignment // a simple variable assignment } else { - TypeRepTemplate seType = (isThis ? SymTabLookup("this") : $se.dotNetType); - if (seType == null) { - seType = new UnknownRepTemplate("FIELD.BASE"); - } - if (seType.IsUnknownType) { - WarningFailedResolve($i.tree.Token.Line, "Could not find type of expression for field /property access"); - } - ResolveResult fieldResult = seType.Resolve($i.thetext, true, AppEnv); if (fieldResult != null) { if (!String.IsNullOrEmpty(fieldResult.Result.Warning)) Warning($i.tree.Token.Line, fieldResult.Result.Warning); if (fieldResult.Result is PropRepTemplate) { @@ -1346,7 +1616,7 @@ assignment if ($a.tree.Token.Type != ASSIGN) { // We have to resolve property reads and writes separately, because they may come from // different parent classes - ResolveResult readFieldResult = seType.Resolve($i.thetext, false, AppEnv); + ResolveResult readFieldResult = expType.Resolve($i.thetext, false, AppEnv); if (readFieldResult.Result is PropRepTemplate) { if (!String.IsNullOrEmpty(readFieldResult.Result.Warning)) Warning($i.tree.Token.Line, readFieldResult.Result.Warning); PropRepTemplate readPropRep = readFieldResult.Result as PropRepTemplate; @@ -1377,18 +1647,24 @@ assignment } } else { - WarningFailedResolve($i.tree.Token.Line, "Could not resolve field or property expression against " + seType.ToString()); + WarningFailedResolve($i.tree.Token.Line, "Could not resolve field or property expression against " + expType.ToString()); } } } - | (^(INDEX expression expression_list?) assignment_operator) => - ^(INDEX ie=expression expression_list?) ia=assignment_operator irhs=expression - { + | (^(INDEX expression[ObjectType] expression_list?) assignment_operator) => + ^(INDEX ie=expression[ObjectType] expression_list?) + { expType = $ie.dotNetType ?? (new UnknownRepTemplate("INDEXER.BASE")); if (expType.IsUnknownType) { WarningFailedResolve($ie.tree.Token.Line, "Could not find type of expression for Indexer"); } - ResolveResult indexerResult = expType.ResolveIndexer($expression_list.expTypes ?? new List(), AppEnv); + indexerResult = expType.ResolveIndexer($expression_list.expTypes ?? new List(), AppEnv); + if (indexerResult != null) { + lhsType = indexerResult.ResultType ?? lhsType; + } + } + ia=assignment_operator irhs=expression[lhsType] + { if (indexerResult != null) { if (!String.IsNullOrEmpty(indexerResult.Result.Warning)) Warning($ia.tree.Token.Line, indexerResult.Result.Warning); IndexerRepTemplate indexerRep = indexerResult.Result as IndexerRepTemplate; @@ -1438,26 +1714,26 @@ assignment WarningFailedResolve($ie.tree.Token.Line, "Could not resolve index expression against " + expType.ToString()); } } - | unary_expression assignment_operator expression ; + | unary_expression[ObjectType] assignment_operator expression[ObjectType] ; -unary_expression returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] +unary_expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] @init { $thedottedtext = null; }: //('(' arguments ')' ('[' | '.' | '(')) => primary_or_array_creation_expression cast_expression { $dotNetType = $cast_expression.dotNetType; } - | primary_or_array_creation_expression { $dotNetType = $primary_or_array_creation_expression.dotNetType; $rmId = $primary_or_array_creation_expression.rmId; $typeofType = $primary_or_array_creation_expression.typeofType; $thedottedtext = $primary_or_array_creation_expression.thedottedtext; } - | ^(MONOPLUS u1=unary_expression) { $dotNetType = $u1.dotNetType; } - | ^(MONOMINUS u2=unary_expression) { $dotNetType = $u2.dotNetType; } - | ^(MONONOT u3=unary_expression) { $dotNetType = $u3.dotNetType; } - | ^(MONOTWIDDLE u4=unary_expression) { $dotNetType = $u4.dotNetType; } - | ^(PREINC u5=unary_expression) { $dotNetType = $u5.dotNetType; } - | ^(PREDEC u6=unary_expression) { $dotNetType = $u6.dotNetType; } - | ^(MONOSTAR unary_expression) { $dotNetType = ObjectType; } - | ^(ADDRESSOF unary_expression) { $dotNetType = ObjectType; } - | ^(PARENS expression) { $dotNetType = $expression.dotNetType; $rmId = $expression.rmId; $typeofType = $expression.typeofType; } + | primary_or_array_creation_expression[$typeCtxt] { $dotNetType = $primary_or_array_creation_expression.dotNetType; $rmId = $primary_or_array_creation_expression.rmId; $typeofType = $primary_or_array_creation_expression.typeofType; $thedottedtext = $primary_or_array_creation_expression.thedottedtext; } + | ^(MONOPLUS u1=unary_expression[ObjectType]) { $dotNetType = $u1.dotNetType; } + | ^(MONOMINUS u2=unary_expression[ObjectType]) { $dotNetType = $u2.dotNetType; } + | ^(MONONOT u3=unary_expression[ObjectType]) { $dotNetType = $u3.dotNetType; } + | ^(MONOTWIDDLE u4=unary_expression[ObjectType]) { $dotNetType = $u4.dotNetType; } + | ^(PREINC u5=unary_expression[ObjectType]) { $dotNetType = $u5.dotNetType; } + | ^(PREDEC u6=unary_expression[ObjectType]) { $dotNetType = $u6.dotNetType; } + | ^(MONOSTAR unary_expression[ObjectType]) { $dotNetType = ObjectType; } + | ^(ADDRESSOF unary_expression[ObjectType]) { $dotNetType = ObjectType; } + | ^(PARENS expression[$typeCtxt]) { $dotNetType = $expression.dotNetType; $rmId = $expression.rmId; $typeofType = $expression.typeofType; } ; cast_expression returns [TypeRepTemplate dotNetType] @@ -1468,7 +1744,7 @@ cast_expression returns [TypeRepTemplate dotNetType] if (ret != null) $cast_expression.tree = ret; }: - ^(c=CAST_EXPR type expression) + ^(c=CAST_EXPR type expression[$type.dotNetType ?? ObjectType]) { $dotNetType = $type.dotNetType; if ($type.dotNetType != null && $expression.dotNetType != null) { @@ -1504,7 +1780,7 @@ shortcut_assignment_operator: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | ' //addressof_expression: // '&' unary_expression ; -non_assignment_expression returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] +non_assignment_expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType, string rmId, TypeRepTemplate typeofType, string thedottedtext] scope MkNonGeneric, PrimitiveRep; @init { $MkNonGeneric::scrubGenericArgs = false; @@ -1515,16 +1791,16 @@ scope MkNonGeneric, PrimitiveRep; $thedottedtext = null; }: //'non ASSIGNment' - (anonymous_function_signature '=>') => lambda_expression + (anonymous_function_signature[null]? '=>') => lambda_expression[$typeCtxt] { $dotNetType = $lambda_expression.dotNetType; } | (query_expression) => query_expression - | ^(COND_EXPR non_assignment_expression e1=expression e2=expression) {$dotNetType = $e1.dotNetType; } - | ^('??' n1=non_assignment_expression non_assignment_expression) {$dotNetType = $n1.dotNetType; } - | ^('||' n2=non_assignment_expression non_assignment_expression) {$dotNetType = $n2.dotNetType; } - | ^('&&' n3=non_assignment_expression non_assignment_expression) {$dotNetType = $n3.dotNetType; } - | ^('|' n4=non_assignment_expression non_assignment_expression) {$dotNetType = $n4.dotNetType; } - | ^('^' n5=non_assignment_expression non_assignment_expression) {$dotNetType = $n5.dotNetType; } - | ^('&' n6=non_assignment_expression non_assignment_expression) {$dotNetType = $n6.dotNetType; } - | ^(eq='==' ne1=non_assignment_expression ne2=non_assignment_expression + | ^(COND_EXPR non_assignment_expression[ObjectType] e1=expression[ObjectType] e2=expression[ObjectType]) {$dotNetType = $e1.dotNetType; } + | ^('??' n1=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n1.dotNetType; } + | ^('||' n2=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n2.dotNetType; } + | ^('&&' n3=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n3.dotNetType; } + | ^('|' n4=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n4.dotNetType; } + | ^('^' n5=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n5.dotNetType; } + | ^('&' n6=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n6.dotNetType; } + | ^(eq='==' ne1=non_assignment_expression[ObjectType] ne2=non_assignment_expression[ObjectType] { // if One arg is null then leave original operator nullArg = $ne1.dotNetType != null && $ne2.dotNetType != null && ($ne1.dotNetType.IsExplicitNull || $ne2.dotNetType.IsExplicitNull); @@ -1548,7 +1824,7 @@ scope MkNonGeneric, PrimitiveRep; -> {dateArgs}? $opde ->^($eq $ne1 $ne2) - | ^(neq='!=' neqo1=non_assignment_expression neqo2=non_assignment_expression + | ^(neq='!=' neqo1=non_assignment_expression[ObjectType] neqo2=non_assignment_expression[ObjectType] { // if One arg is null then leave original operator nullArg = $neqo1.dotNetType != null && $neqo2.dotNetType != null && ($neqo1.dotNetType.IsExplicitNull || $neqo2.dotNetType.IsExplicitNull); @@ -1574,7 +1850,7 @@ scope MkNonGeneric, PrimitiveRep; -> {dateArgs}? $opdne ->^($neq $neqo1 $neqo2) - | ^(gt='>' gt1=non_assignment_expression gt2=non_assignment_expression + | ^(gt='>' gt1=non_assignment_expression[ObjectType] gt2=non_assignment_expression[ObjectType] { // if One arg is null then leave original operator nullArg = $gt1.dotNetType != null && $gt2.dotNetType != null && ($gt1.dotNetType.IsExplicitNull || $gt2.dotNetType.IsExplicitNull); @@ -1590,7 +1866,7 @@ scope MkNonGeneric, PrimitiveRep; -> {dateArgs}? $opgt ->^($gt $gt1 $gt2) - | ^(lt='<' lt1=non_assignment_expression lt2=non_assignment_expression + | ^(lt='<' lt1=non_assignment_expression[ObjectType] lt2=non_assignment_expression[ObjectType] { // if One arg is null then leave original operator nullArg = $lt1.dotNetType != null && $lt2.dotNetType != null && ($lt1.dotNetType.IsExplicitNull || $lt2.dotNetType.IsExplicitNull); @@ -1606,7 +1882,7 @@ scope MkNonGeneric, PrimitiveRep; -> {dateArgs}? $oplt ->^($lt $lt1 $lt2) - | ^(ge='>=' ge1=non_assignment_expression ge2=non_assignment_expression + | ^(ge='>=' ge1=non_assignment_expression[ObjectType] ge2=non_assignment_expression[ObjectType] { // if One arg is null then leave original operator nullArg = $ge1.dotNetType != null && $ge2.dotNetType != null && ($ge1.dotNetType.IsExplicitNull || $ge2.dotNetType.IsExplicitNull); @@ -1622,7 +1898,7 @@ scope MkNonGeneric, PrimitiveRep; -> {dateArgs}? $opge ->^($ge $ge1 $ge2) - | ^(le='<=' le1=non_assignment_expression le2=non_assignment_expression + | ^(le='<=' le1=non_assignment_expression[ObjectType] le2=non_assignment_expression[ObjectType] { // if One arg is null then leave original operator nullArg = $le1.dotNetType != null && $le2.dotNetType != null && ($le1.dotNetType.IsExplicitNull || $le2.dotNetType.IsExplicitNull); @@ -1638,72 +1914,68 @@ scope MkNonGeneric, PrimitiveRep; -> {dateArgs}? $ople ->^($le $le1 $le2) - | ^(INSTANCEOF non_assignment_expression { $MkNonGeneric::scrubGenericArgs = true; $PrimitiveRep::primitiveTypeAsObject = true; } non_nullable_type) {$dotNetType = BoolType; } - | ^('<<' n7=non_assignment_expression non_assignment_expression) {$dotNetType = $n7.dotNetType; } - | ^(RIGHT_SHIFT n8=non_assignment_expression non_assignment_expression) {$dotNetType = $n8.dotNetType; } + | ^(INSTANCEOF non_assignment_expression[ObjectType] { $MkNonGeneric::scrubGenericArgs = true; $PrimitiveRep::primitiveTypeAsObject = true; } non_nullable_type) {$dotNetType = BoolType; } + | ^('<<' n7=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n7.dotNetType; } + | ^(RIGHT_SHIFT n8=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n8.dotNetType; } // TODO: need to munge these numeric types - | ^('+' n9=non_assignment_expression non_assignment_expression) {$dotNetType = $n9.dotNetType; } - | ^('-' n10=non_assignment_expression non_assignment_expression) {$dotNetType = $n10.dotNetType; } - | ^('*' n11=non_assignment_expression non_assignment_expression) {$dotNetType = $n11.dotNetType; } - | ^('/' n12=non_assignment_expression non_assignment_expression) {$dotNetType = $n12.dotNetType; } - | ^('%' n13=non_assignment_expression non_assignment_expression) {$dotNetType = $n13.dotNetType; } + | ^('+' n9=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n9.dotNetType; } + | ^('-' n10=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n10.dotNetType; } + | ^('*' n11=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n11.dotNetType; } + | ^('/' n12=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n12.dotNetType; } + | ^('%' n13=non_assignment_expression[ObjectType] non_assignment_expression[ObjectType]) {$dotNetType = $n13.dotNetType; } // | ^(UNARY_EXPRESSION unary_expression) - | unary_expression {$dotNetType = $unary_expression.dotNetType; $rmId = $unary_expression.rmId; $typeofType = $unary_expression.typeofType; $thedottedtext = $unary_expression.thedottedtext; } + | unary_expression[$typeCtxt] + { + $dotNetType = $unary_expression.dotNetType; + $rmId = $unary_expression.rmId; + $typeofType = $unary_expression.typeofType; + $thedottedtext = $unary_expression.thedottedtext; + } ; -// /////////////////////////////////////////////////////// -// // Conditional Expression Section -// /////////////////////////////////////////////////////// -// -// multiplicative_expression: -// unary_expression ( ('*'|'/'|'%') unary_expression)* ; -// additive_expression: -// multiplicative_expression (('+'|'-') multiplicative_expression)* ; -// // >> check needed (no whitespace) -// shift_expression: -// additive_expression (('<<'|'>' '>') additive_expression)* ; -// relational_expression: -// shift_expression -// ( (('<'|'>'|'>='|'<=') shift_expression) -// | (('is'|'as') non_nullable_type) -// )* ; -// 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: -// conditional_or_expression ('??' conditional_or_expression)* ; -// conditional_expression: -// null_coalescing_expression ('?' expression ':' expression)? ; -// - /////////////////////////////////////////////////////// // lambda Section /////////////////////////////////////////////////////// -lambda_expression: - anonymous_function_signature '=>' anonymous_function_body; -anonymous_function_signature: - '(' (explicit_anonymous_function_parameter_list - | implicit_anonymous_function_parameter_list)? ')' - | implicit_anonymous_function_parameter_list +lambda_expression[TypeRepTemplate typeCtxt] returns [TypeRepTemplate dotNetType] +@init { + CommonTree ret = null; +} +@after { + if (ret != null) + $lambda_expression.tree = ret; +}: + anonymous_function_signature[$typeCtxt]? d='=>' block + { + if ($typeCtxt != null && $typeCtxt is DelegateRepTemplate && $anonymous_function_signature.isTypedParams) { + // use an anonymous inner class to generate a delegate object (object wih an Invoke with appropriate arguments) + // new () { public void Invoke() throw exception } + DelegateRepTemplate delType = $typeCtxt as DelegateRepTemplate; + ret = mkDelegateObject((CommonTree)$typeCtxt.Tree, $anonymous_function_signature.tree, $block.tree, delType, $d.token); + $dotNetType = $typeCtxt; + } + } + ; +anonymous_function_signature[TypeRepTemplate typeCtxt] returns [bool isTypedParams] +@init { + $isTypedParams = true; + CommonTree ret = null; + List ids = new List(); +} +@after { + if (ret != null) + $anonymous_function_signature.tree = ret; +}: + ^(PARAMS (parameter_modifier? type identifier)+) + | ^(p=PARAMS_TYPELESS (identifier { ids.Add($identifier.tree); })+) + { + if ($typeCtxt != null && $typeCtxt is DelegateRepTemplate && ids.Count == ((DelegateRepTemplate)$typeCtxt).Invoke.Params.Count) { + ret = mkTypedParams(((DelegateRepTemplate)$typeCtxt).Invoke.Params, ids, $p.token); + } + else { + $isTypedParams = false; + } + } ; -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 @@ -1724,17 +1996,17 @@ query_body_clause: | join_clause | orderby_clause; from_clause: - 'from' type? identifier 'in' expression ; + 'from' type? identifier 'in' expression[ObjectType] ; join_clause: - 'join' type? identifier 'in' expression 'on' expression 'equals' expression ('into' identifier)? ; + 'join' type? identifier 'in' expression[ObjectType] 'on' expression[ObjectType] 'equals' expression[ObjectType] ('into' identifier)? ; let_clause: - 'let' identifier '=' expression; + 'let' identifier '=' expression[ObjectType]; orderby_clause: 'orderby' ordering_list ; ordering_list: ordering (',' ordering)* ; ordering: - expression ordering_direction + expression[ObjectType] ordering_direction ; ordering_direction: 'ascending' @@ -1743,13 +2015,13 @@ select_or_group_clause: select_clause | group_clause ; select_clause: - 'select' expression ; + 'select' expression[ObjectType] ; group_clause: - 'group' expression 'by' expression ; + 'group' expression[ObjectType] 'by' expression[ObjectType] ; where_clause: 'where' boolean_expression ; boolean_expression: - expression; + expression[ObjectType]; /////////////////////////////////////////////////////// // B.2.13 Attributes @@ -1792,7 +2064,7 @@ named_argument_list: named_argument: identifier '=' attribute_argument_expression ; attribute_argument_expression: - expression ; + expression[ObjectType] ; /////////////////////////////////////////////////////// // Class Section @@ -1919,7 +2191,7 @@ constant_declarators[TypeRepTemplate ty]: constant_declarator[TypeRepTemplate ty]: identifier { $SymTab::symtab[$identifier.thetext] = $ty; } ('=' constant_expression)? ; constant_expression returns [string rmId]: - expression {$rmId = $expression.rmId; }; + expression[ObjectType] {$rmId = $expression.rmId; }; /////////////////////////////////////////////////////// field_declaration[CommonTree tyTree, TypeRepTemplate ty]: @@ -2051,13 +2323,13 @@ scope PrimitiveRep; bool isRefOut = false; }: (parameter_modifier { isRefOut = $parameter_modifier.isRefOut; if (isRefOut) { $PrimitiveRep::primitiveTypeAsObject = true; AddToImports("CS2JNet.JavaSupport.language.RefSupport");} })? - type identifier { $type.dotNetType.IsWrapped = isRefOut; $SymTab::symtab[$identifier.thetext] = $type.dotNetType; } default_argument? magicRef[isRefOut, $type.tree.Token, $type.tree] + type identifier { $type.dotNetType.IsWrapped = isRefOut; $SymTab::symtab[$identifier.thetext] = $type.dotNetType; } default_argument? magicRef[isRefOut, $type.tree != null ? $type.tree.Token : null, $type.tree] -> {isRefOut}? magicRef identifier default_argument? -> parameter_modifier? type identifier default_argument? ; // 4.0 default_argument: - '=' expression; + '=' expression[ObjectType]; parameter_modifier returns [bool isRefOut] @init { $isRefOut = true; @@ -2202,7 +2474,7 @@ embedded_statement[bool isStatementListCtxt] | switch_statement[isStatementListCtxt] | iteration_statement // while, do, for, foreach | jump_statement - | (^(('return' | 'throw') expression?)) => (^(jt='return' (je=expression {jumpStatementHasExpression = true;})?) | ^(jt='throw' (je=expression{ jumpStatementHasExpression = true; })?)) + | (^(('return' | 'throw') expression[ObjectType]?)) => (^(jt='return' (je=expression[ObjectType] {jumpStatementHasExpression = true;})?) | ^(jt='throw' (je=expression[ObjectType]{ jumpStatementHasExpression = true; })?)) { emitPrePost = adaptor.GetChildCount($statement::preStatements) > 0 || adaptor.GetChildCount($statement::postStatements) > 0; if (emitPrePost) { idName = "resVar___" + dummyVarCtr++; @@ -2243,7 +2515,7 @@ scope { $switch_statement::isFirstCase = true; $switch_statement::defaultTree = null; }: - ^(s='switch' se=expression sv=magicScrutineeVar[$s.token] + ^(s='switch' se=expression[ObjectType] sv=magicScrutineeVar[$s.token] { if ($expression.dotNetType != null) { $switch_statement::isEnum = $expression.dotNetType.IsA(AppEnv.Search("System.Enum"), AppEnv); @@ -2272,7 +2544,7 @@ fixed_pointer_declarator: identifier '=' fixed_pointer_initializer ; fixed_pointer_initializer: //'&' variable_reference // unary_expression covers this - expression; + expression[ObjectType]; labeled_statement[bool isStatementListCtxt]: ^(':' identifier statement[isStatementListCtxt]) ; declaration_statement: @@ -2302,7 +2574,7 @@ local_variable_declarator[CommonTree tyTree, TypeRepTemplate ty] } }: i=identifier { $SymTab::symtab[$i.thetext] = $ty; } - (e='=' local_variable_initializer { hasInit = true; constructStruct = false; constructEnum = false; } )? + (e='=' local_variable_initializer[$ty ?? ObjectType] { hasInit = true; constructStruct = false; constructEnum = false; } )? magicConstructStruct[constructStruct, $tyTree, ($i.tree != null ? $i.tree.Token : null)] magicConstructDefaultEnum[constructEnum, $ty, zeroEnum, $identifier.tree != null ? $identifier.tree.Token : null] // eg. event EventHandler IInterface.VariableName = Foo; @@ -2311,20 +2583,20 @@ local_variable_declarator[CommonTree tyTree, TypeRepTemplate ty] -> {constructEnum}? $i ASSIGN[$i.tree.Token, "="] magicConstructDefaultEnum -> $i ; -local_variable_initializer: - expression +local_variable_initializer[TypeRepTemplate typeCtxt]: + expression[$typeCtxt] | array_initializer | stackalloc_initializer; stackalloc_initializer: - 'stackalloc' unmanaged_type '[' expression ']' ; + 'stackalloc' unmanaged_type '[' expression[ObjectType] ']' ; local_constant_declaration: 'const' type constant_declarators[$type.dotNetType] ; expression_statement: - expression ';' ; + expression[ObjectType] ';' ; // TODO: should be assignment, call, increment, decrement, and new object expressions statement_expression: - expression + expression[ObjectType] ; else_statement: 'else' embedded_statement[/* isStatementListCtxt */ false] ; @@ -2392,7 +2664,7 @@ scope SymTab; ^('while' boolean_expression SEP embedded_statement[/* isStatementListCtxt */ false]) | do_statement | ^('for' for_initializer? SEP for_condition? SEP for_iterator? SEP embedded_statement[/* isStatementListCtxt */ false]) - | ^(f='foreach' local_variable_type identifier expression s=SEP { $SymTab::symtab[$identifier.thetext] = $local_variable_type.dotNetType; } embedded_statement[/* isStatementListCtxt */ false]) + | ^(f='foreach' local_variable_type identifier expression[ObjectType] s=SEP { $SymTab::symtab[$identifier.thetext] = $local_variable_type.dotNetType; } embedded_statement[/* isStatementListCtxt */ false]) magicObjectType[$f.token] magicForeachVar[$f.token] { newType = $local_variable_type.tree; @@ -2475,9 +2747,9 @@ checked_statement: unchecked_statement: 'unchecked' block ; lock_statement: - 'lock' '(' expression ')' embedded_statement[/* isStatementListCtxt */ false] ; + 'lock' '(' expression[ObjectType] ')' embedded_statement[/* isStatementListCtxt */ false] ; yield_statement: - 'yield' ('return' expression ';' + 'yield' ('return' expression[ObjectType] ';' | 'break' ';') ; /////////////////////////////////////////////////////// @@ -2840,3 +3112,8 @@ magicBoxedType[bool isOn, IToken tok, String boxedName]: -> { isOn }? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, boxedName]) -> ; + +magicInputPeId[CommonTree dotTree, CommonTree idTree, CommonTree galTree]: + -> { dotTree != null}? {dupTree(dotTree)} { dupTree(galTree) } + -> {dupTree(idTree)} { dupTree(galTree) } +; diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g index 445180f..1436678 100644 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g @@ -867,6 +867,7 @@ scope NSContext; $NSContext::searchpath = new List(); $NSContext::aliases = new List(); DelegateRepTemplate dlegate = new DelegateRepTemplate(); + ClassRepTemplate multiDelegateClass = new ClassRepTemplate(); } : 'delegate' return_type identifier variant_generic_parameter_list? @@ -878,12 +879,26 @@ scope NSContext; if ($variant_generic_parameter_list.tyargs != null && $variant_generic_parameter_list.tyargs.Count > 0) { dlegate.TypeParams = $variant_generic_parameter_list.tyargs.ToArray(); } - dlegate.Return=$return_type.thetext; - dlegate.Params=$formal_parameter_list.paramlist; + dlegate.Invoke = new InvokeRepTemplate($return_type.thetext, "Invoke", null, $formal_parameter_list.paramlist); AppEnv[genericNameSpace] = dlegate; dlegate.Uses = this.CollectUses; dlegate.Aliases = this.CollectAliases; dlegate.Imports = new string[] {dlegate.TypeName}; + + // now add a class for the MultiDelegateClass that we will be generating + genericNameSpace = NSPrefix(ParentNameSpace) + mkGenericTypeAlias("__Multi"+$identifier.text, $variant_generic_parameter_list.tyargs); + multiDelegateClass.TypeName = NSPrefix(ParentNameSpace) + "__Multi" + $identifier.text; + multiDelegateClass.Inherits = new String[] { dlegate.TypeName }; + if ($variant_generic_parameter_list.tyargs != null && $variant_generic_parameter_list.tyargs.Count > 0) { + multiDelegateClass.TypeParams = $variant_generic_parameter_list.tyargs.ToArray(); + } + multiDelegateClass.Methods.Add(new MethodRepTemplate($return_type.thetext, "Invoke", null, $formal_parameter_list.paramlist)); + multiDelegateClass.Methods.Add(new MethodRepTemplate("System.Collections.Generic.List*[" + dlegate.TypeName + "]*", "GetInvocationList", null, null)); + AppEnv[genericNameSpace] = multiDelegateClass; + multiDelegateClass.Uses = this.CollectUses; + multiDelegateClass.Aliases = this.CollectAliases; + multiDelegateClass.Imports = new string[] {multiDelegateClass.TypeName}; + } ; delegate_modifiers: diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTranslator.csproj b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTranslator.csproj index c83425b..dba655a 100755 --- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTranslator.csproj +++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTranslator.csproj @@ -24,7 +24,7 @@ DEBUG;TRACE prompt 4 - -translator-timestamp-files=false -translator-keep-parens=false -netdir=/Users/keving/gitrepos/cs2j/CS2JLibrary/NetFramework/ -dumpxmls -xmldir=/Users/keving/tmp/xml/se -odir=/Users/keving/tmp/java/se/src -appdir=/Users/keving/svnrepos/ScormEngineNet/src/app/ScormEngine.Core /Users/keving/svnrepos/ScormEngineNet/src/app/ScormEngine.Core/Logic/Integration/IntegrationInterface.cs + --debug 5 -experimental-transforms=true -translator-timestamp-files=false -translator-keep-parens=false -netdir=/Users/keving/gitrepos/cs2j/CS2JLibrary/NetFramework/ -dumpxmls -xmldir=/Users/keving/tmp/xml/libomv -odir=/Users/keving/tmp/java/libomv/src -csdir=/Users/keving/Projects/libomv-0.8.3-source/Programs/VisualParamGenerator/ -excsdir=/Users/keving/Projects/libomv-0.8.3-source/Programs/VisualParamGenerator/template.cs x86 diff --git a/CSharpTranslator/antlr3/src/CSharpParser/cs.g b/CSharpTranslator/antlr3/src/CSharpParser/cs.g index e5e43c4..f32469b 100644 --- a/CSharpTranslator/antlr3/src/CSharpParser/cs.g +++ b/CSharpTranslator/antlr3/src/CSharpParser/cs.g @@ -30,6 +30,7 @@ tokens { DESTRUCTOR; METHOD_HEADER; PARAMS; + PARAMS_TYPELESS; SWITCH_SECTION; MONOPLUS; @@ -126,6 +127,9 @@ tokens { MOD = '%'; STAR = '*'; + LAMBDA = '=>'; + COMMA = ','; + TYPE; TYPE_VAR; TYPE_DYNAMIC; @@ -271,6 +275,9 @@ public class_member_declaration: ) ; +public java_delegate_creation_expression: + 'new' type '(' ')' '{' class_member_declaration '}'; + public primary_expression: ('this' brackets) => 'this' brackets primary_expression_part* | ('base' brackets) => 'base' brackets primary_expression_part* @@ -771,12 +778,19 @@ public variable_declarator: public method_declaration: method_header method_body ; public method_header: - member_name '(' formal_parameter_list? ')' type_parameter_constraints_clauses? ; + member_name '(' formal_parameter_list? ')' type_parameter_constraints_clauses? + // Only have throw Exceptions if IsJavaish + throw_exceptions? +; public method_body: block ; public member_name: qid ; // IInterface.Method logic added. +throw_exceptions: + {IsJavaish}?=> 'throws' identifier (',' identifier)* + ; + /////////////////////////////////////////////////////// public property_declaration: member_name '{' accessor_declarations '}' ;