From 43323f46ea7c73bb1785c7b2874c70576dca250e Mon Sep 17 00:00:00 2001 From: Kevin Glynn Date: Tue, 25 Jan 2011 18:26:47 +0100 Subject: [PATCH] resolve indexers --- .../src/cs2j/CLR/TranslationTemplate.cs | 243 ++++++++++++++++-- .../antlr3/src/cs2j/CSharp/NetMaker.g | 58 ++++- .../src/cs2j/CSharp/TemplateExtracter.g | 4 +- 3 files changed, 283 insertions(+), 22 deletions(-) diff --git a/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs b/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs index 25df64f..004234d 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs +++ b/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs @@ -822,10 +822,9 @@ namespace RusticiSoftware.Translator.CLR // guessing that normally imports will be the same for both) public class PropRepTemplate : FieldRepTemplate, IEquatable { - - private string _javaGet = null; + protected string _javaGet = null; [XmlElementAttribute("Get")] - public string JavaGet { + public virtual string JavaGet { get { if (!CanRead) return null; if (_javaGet == null) { @@ -842,7 +841,7 @@ namespace RusticiSoftware.Translator.CLR } set { _javaGet = value; } } - + public override string Java { get @@ -851,9 +850,9 @@ namespace RusticiSoftware.Translator.CLR } } - private string _javaSet = null; + protected string _javaSet = null; [XmlElementAttribute("Set")] - public string JavaSet { + public virtual string JavaSet { get { if (_javaSet == null) { return (CanWrite ? "${this}.set" + Name + "(${value})" : null); @@ -939,6 +938,152 @@ namespace RusticiSoftware.Translator.CLR #endregion } + // An indexer is like a unnamed property that has params + public class IndexerRepTemplate : PropRepTemplate, IEquatable + { + private List _params = null; + [XmlArrayItem("Param")] + public List Params { + get { + if (_params == null) + _params = new List (); + return _params; + } + } + + private List _setParams = null; + private List SetParams { + get { + if (_setParams == null) + { + _setParams = new List (); + foreach (ParamRepTemplate p in Params) + { + _setParams.Add(p); + } + _setParams.Add(new ParamRepTemplate(Type,"value")); + } + return _setParams; + } + } + + [XmlElementAttribute("Get")] + public override string JavaGet { + get { + if (!CanRead) return null; + if (_javaGet == null) { + if (_java == null) { + return (CanRead ? "${this}.get___idx" + mkJavaParams(Params) : null); + } + else { + return _java; + } + } + else { + return _javaGet; + } + } + set { _javaGet = value; } + } + + [XmlElementAttribute("Set")] + public override string JavaSet { + get { + if (_javaSet == null) { + return (CanWrite ? "${this}.set___idx" + mkJavaParams(SetParams): null); + } + else { + return _javaSet; + } + } + set { _javaSet = value; } + } + + public IndexerRepTemplate () : base() + { + } + + public IndexerRepTemplate (string fType, List pars) : base(fType, "this") + { + _params = pars; + } + + public IndexerRepTemplate (string fType, List pars, string[] imps, string javaGet, string javaSet) : base(fType, "this",imps,javaGet,javaSet) + { + _params = pars; + } + + + public override void Apply(Dictionary args) + { + if (Params != null) + { + foreach(ParamRepTemplate p in Params) + { + p.Apply(args); + } + } + if (_setParams != null) + { + foreach(ParamRepTemplate p in _setParams) + { + p.Apply(args); + } + } + base.Apply(args); + } + + #region Equality + + public bool Equals (IndexerRepTemplate other) + { + 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 base.Equals(other); + } + + public override bool Equals (object obj) + { + + IndexerRepTemplate temp = obj as IndexerRepTemplate; + + if (!Object.ReferenceEquals (temp, null)) + return this.Equals (temp); + return false; + } + + public static bool operator == (IndexerRepTemplate a1, IndexerRepTemplate a2) + { + return Object.Equals (a1, a2); + } + + public static bool operator != (IndexerRepTemplate a1, IndexerRepTemplate a2) + { + return !(a1 == a2); + } + + public override int GetHashCode () + { + int hashCode = 0; + foreach (ParamRepTemplate o in Params) { + hashCode = hashCode ^ o.GetHashCode() ; + } + + return base.GetHashCode () ^ hashCode; + } + #endregion + } + // A member of an enum, may also have a numeric value public class EnumMemberRepTemplate : TranslationBase, IEquatable { @@ -1169,6 +1314,25 @@ namespace RusticiSoftware.Translator.CLR return null; } + // Resolve a indexer call (arg types) + public virtual ResolveResult ResolveIndexer(List args, DirectoryHT AppEnv) + { + if (Inherits != null) + { + foreach (String b in Inherits) + { + TypeRepTemplate baseType = BuildType(b, AppEnv); + if (baseType != null) + { + ResolveResult ret = baseType.ResolveIndexer(args,AppEnv); + if (ret != null) + return ret; + } + } + } + return null; + } + // Resolve a cast from this type to castTo public virtual ResolveResult ResolveCastTo(TypeRepTemplate castTo, DirectoryHT AppEnv) { @@ -1734,12 +1898,13 @@ namespace RusticiSoftware.Translator.CLR } } - private List _indexers = null; + [XmlIgnore] + private List _indexers = null; [XmlArrayItem("Indexer")] - public List Indexers { + public List Indexers { get { if (_indexers == null) - _indexers = new List (); + _indexers = new List (); return _indexers; } } @@ -1753,7 +1918,7 @@ namespace RusticiSoftware.Translator.CLR { } - protected InterfaceRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List ms, List ps, List es, List ixs, string[] imps, string javaTemplate) + protected InterfaceRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List ms, List ps, List es, List ixs, string[] imps, string javaTemplate) : base(tName, tParams, usePath, aliases, imps, javaTemplate) { Inherits = inherits; @@ -1789,7 +1954,7 @@ namespace RusticiSoftware.Translator.CLR } if (Indexers != null) { - foreach(MethodRepTemplate i in Indexers) + foreach(IndexerRepTemplate i in Indexers) { i.Apply(args); } @@ -1878,6 +2043,50 @@ namespace RusticiSoftware.Translator.CLR return base.Resolve(name, args, AppEnv); } + public override ResolveResult ResolveIndexer(List args, DirectoryHT AppEnv) + { + + if (Indexers != null) + { + foreach (IndexerRepTemplate i in Indexers) + { + bool matchingArgs = true; + // If either params are null then make sure both represent zero length args + if (i.Params == null || args == null) + { + // Are they both zero length? + matchingArgs = (i.Params == null || i.Params.Count == 0) && (args == null || args.Count == 0); + } + else + { + // Are num args the same? + if (i.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 < i.Params.Count; idx++) { + if (args[idx] == null || !args[idx].IsA(BuildType(i.Params[idx].Type, AppEnv, new UnknownRepTemplate(i.Params[idx].Type)),AppEnv)) + { + matchingArgs = false; + break; + } + } + } + if (matchingArgs) + { + ResolveResult res = new ResolveResult(); + res.Result = i; + res.ResultType = BuildType(i.Type, AppEnv); + return res; + } + } + } + } + return base.ResolveIndexer(args, AppEnv); + } #region Equality public bool Equals (InterfaceRepTemplate other) @@ -1977,7 +2186,7 @@ namespace RusticiSoftware.Translator.CLR } } if (Indexers != null) { - foreach (MethodRepTemplate e in Indexers) { + foreach (IndexerRepTemplate e in Indexers) { hashCode ^= e.GetHashCode(); } } @@ -2039,7 +2248,7 @@ namespace RusticiSoftware.Translator.CLR { } - public ClassRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts, + public ClassRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts, string[] imports, string javaTemplate) : base(tName, tParams, usePath, aliases, inherits, ms, ps, es, ixs, imports, javaTemplate) { @@ -2048,7 +2257,7 @@ namespace RusticiSoftware.Translator.CLR _casts = cts; } - public ClassRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts) + public ClassRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts) : base(tName, tParams, usePath, aliases, inherits, ms, ps, es, ixs, null, null) { _constructors = cs; @@ -2111,7 +2320,7 @@ namespace RusticiSoftware.Translator.CLR return base.Resolve(name, AppEnv); } - public virtual ResolveResult Resolve(List args, DirectoryHT AppEnv) + public ResolveResult Resolve(List args, DirectoryHT AppEnv) { if (Constructors != null) @@ -2259,13 +2468,13 @@ namespace RusticiSoftware.Translator.CLR { } - public StructRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts, + public StructRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts, string[] imports, string javaTemplate) : base(tName, tParams, usePath, aliases, inherits, cs, ms, ps, fs, es, ixs, cts, imports, javaTemplate) { } - public StructRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts) + public StructRepTemplate (string tName, string[] tParams, string[] usePath, AliasRepTemplate[] aliases, string[] inherits, List cs, List ms, List ps, List fs, List es, List ixs, List cts) : base(tName, tParams, usePath, aliases, inherits, cs, ms, ps, fs, es, ixs, cts, null, null) { } diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g index 7b4678c..d28df00 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g @@ -322,7 +322,29 @@ scope { if (ret != null) $primary_expression.tree = ret; }: - ^(INDEX expression expression_list?) + ^(INDEX ie=expression expression_list?) + { + if ($ie.dotNetType != null) { + ResolveResult indexerResult = $ie.dotNetType.ResolveIndexer($expression_list.expTypes ?? new List(), AppEnv); + if (indexerResult != null) { + IndexerRepTemplate indexerRep = indexerResult.Result as IndexerRepTemplate; + if (!String.IsNullOrEmpty(indexerRep.JavaGet)) { + Dictionary myMap = new Dictionary(); + myMap["this"] = wrapExpression($ie.tree, $ie.tree.Token); + for (int idx = 0; idx < indexerRep.Params.Count; idx++) { + myMap[indexerRep.Params[idx].Name] = wrapArgument($expression_list.expTrees[idx], $ie.tree.Token); + if (indexerRep.Params[idx].Name.StartsWith("TYPEOF") && $expression_list.expTreeTypeofTypes[idx] != null) { + // if this argument is a typeof expression then add a TYPEOF_TYPEOF-> typeof's type mapping + myMap[indexerRep.Params[idx].Name + "_TYPE"] = wrapTypeOfType($expression_list.expTreeTypeofTypes[idx], $ie.tree.Token); + } + } + ret = mkJavaWrapper(indexerResult.Result.Java, myMap, $ie.tree.Token); + Imports.Add(indexerResult.Result.Imports); + $dotNetType = indexerResult.ResultType; + } + } + } + } | (^(APPLY (^('.' expression identifier)|identifier) argument_list?)) => ^(APPLY (^('.' e2=expression {expType = $e2.dotNetType; implicitThis = false;} i2=identifier)|i2=identifier) argument_list?) { @@ -745,8 +767,14 @@ expression returns [TypeRepTemplate dotNetType, String rmId, TypeRepTemplate typ (unary_expression assignment_operator) => assignment { $dotNetType = VoidType; } | non_assignment_expression { $dotNetType = $non_assignment_expression.dotNetType; $rmId = $non_assignment_expression.rmId; $typeofType = $non_assignment_expression.typeofType; } ; -expression_list: - expression (',' expression)* ; +expression_list returns [List expTypes, List expTrees, List expTreeTypeofTypes] +@init { + $expTypes = new List(); + $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); })* ; assignment @init { @@ -774,6 +802,30 @@ assignment } } } + | (^(INDEX expression expression_list?) '=') => + ^(INDEX ie=expression expression_list?) ia='=' irhs=expression + { + if ($ie.dotNetType != null) { + ResolveResult indexerResult = $ie.dotNetType.ResolveIndexer($expression_list.expTypes ?? new List(), AppEnv); + if (indexerResult != null) { + IndexerRepTemplate indexerRep = indexerResult.Result as IndexerRepTemplate; + if (!String.IsNullOrEmpty(indexerRep.JavaSet)) { + Dictionary myMap = new Dictionary(); + myMap["this"] = wrapExpression($ie.tree, $ie.tree.Token); + myMap["value"] = wrapExpression($irhs.tree, $irhs.tree.Token); + for (int idx = 0; idx < indexerRep.Params.Count; idx++) { + myMap[indexerRep.Params[idx].Name] = wrapArgument($expression_list.expTrees[idx], $ie.tree.Token); + if (indexerRep.Params[idx].Name.StartsWith("TYPEOF") && $expression_list.expTreeTypeofTypes[idx] != null) { + // if this argument is a typeof expression then add a TYPEOF_TYPEOF-> typeof's type mapping + myMap[indexerRep.Params[idx].Name + "_TYPE"] = wrapTypeOfType($expression_list.expTreeTypeofTypes[idx], $ie.tree.Token); + } + } + ret = mkJavaWrapper(indexerRep.JavaSet, myMap, $ie.tree.Token); + Imports.Add(indexerRep.Imports); + } + } + } + } | unary_expression assignment_operator expression ; diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/TemplateExtracter.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/TemplateExtracter.g index 18ca513..3f691e2 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/TemplateExtracter.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/TemplateExtracter.g @@ -1013,7 +1013,7 @@ interface_event_declaration: interface_indexer_declaration [string returnType]: // attributes? 'new'? type 'this' '[' fpl=formal_parameter_list ']' '{' interface_accessor_declarations '}' - { ((InterfaceRepTemplate)$NSContext::currentTypeRep).Indexers.Add(new MethodRepTemplate($returnType, "this", null, $fpl.paramlist)); } + { ((InterfaceRepTemplate)$NSContext::currentTypeRep).Indexers.Add(new IndexerRepTemplate($returnType, $fpl.paramlist)); } { Debug("Processing interface indexer declaration"); } ; interface_accessor_declarations returns [bool hasGetter, bool hasSetter] @@ -1104,7 +1104,7 @@ indexer_declaration [string returnType, string prefix]: indexer_declarator [string returnType, string prefix]: //(type_name '.')? 'this' '[' fpl=formal_parameter_list ']' - { ((InterfaceRepTemplate)$NSContext::currentTypeRep).Indexers.Add(new MethodRepTemplate($returnType, $prefix+"this", null, $fpl.paramlist)); } + { ((InterfaceRepTemplate)$NSContext::currentTypeRep).Indexers.Add(new IndexerRepTemplate($returnType, $fpl.paramlist)); } { Debug("Processing indexer declaration"); } ;