From 1fe7bceadeffb5cbf7e502792b964f9eb48c1c18 Mon Sep 17 00:00:00 2001 From: Kevin Glynn Date: Wed, 26 Jan 2011 11:47:15 +0100 Subject: [PATCH] add support for iterables --- CS2JLibrary/NetFramework/System/String.xml | 4 + .../src/cs2j/CLR/TranslationTemplate.cs | 113 +++++++++++++++++- .../antlr3/src/cs2j/CSharp/JavaPrettyPrint.g | 10 +- .../antlr3/src/cs2j/CSharp/NetMaker.g | 84 ++++++++++++- CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g | 1 + 5 files changed, 204 insertions(+), 8 deletions(-) diff --git a/CS2JLibrary/NetFramework/System/String.xml b/CS2JLibrary/NetFramework/System/String.xml index 4cdd6af..adeabd6 100644 --- a/CS2JLibrary/NetFramework/System/String.xml +++ b/CS2JLibrary/NetFramework/System/String.xml @@ -7,6 +7,10 @@ System.Object + + System.Char + ${expr}.toCharArray() + diff --git a/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs b/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs index 004234d..4578493 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs +++ b/CSharpTranslator/antlr3/src/cs2j/CLR/TranslationTemplate.cs @@ -373,6 +373,77 @@ namespace RusticiSoftware.Translator.CLR } + public class IterableRepTemplate : TranslationBase, IEquatable + { + + public String ReturnType { + get; set; + } + + public override string mkJava() { + return "${expr}"; + } + + public IterableRepTemplate () : base() + { + } + + public IterableRepTemplate (String ty) : base() + { + ReturnType = ty; + } + + public IterableRepTemplate (String ty, string[] imps, string javaRep) : base(imps, javaRep) + { + ReturnType = ty; + } + + + public override void Apply(Dictionary args) + { + if (ReturnType != null) + { + TemplateUtilities.SubstituteInType(ReturnType, args); + } + base.Apply(args); + } + + #region Equality + + public bool Equals (IterableRepTemplate other) + { + if (other == null) + return false; + + return ReturnType == other.ReturnType && base.Equals(other); + } + + public override bool Equals (object obj) + { + + IterableRepTemplate temp = obj as IterableRepTemplate; + + if (!Object.ReferenceEquals (temp, null)) + return this.Equals (temp); + return false; + } + + public static bool operator == (IterableRepTemplate a1, IterableRepTemplate a2) + { + return Object.Equals (a1, a2); + } + + public static bool operator != (IterableRepTemplate a1, IterableRepTemplate a2) + { + return !(a1 == a2); + } + + public override int GetHashCode () + { + return base.GetHashCode () ^ ReturnType.GetHashCode(); + } + #endregion + } public class ConstructorRepTemplate : TranslationBase, IEquatable { @@ -1412,6 +1483,24 @@ namespace RusticiSoftware.Translator.CLR return null; } + public virtual ResolveResult ResolveIterable(DirectoryHT AppEnv) + { + if (Inherits != null) + { + foreach (String b in Inherits) + { + TypeRepTemplate baseType = BuildType(b, AppEnv); + if (baseType != null) + { + ResolveResult ret = baseType.ResolveIterable(AppEnv); + if (ret != null) + return ret; + } + } + } + return null; + } + // Returns true if other is a subclass, or implements our interface public virtual bool IsA (TypeRepTemplate other, DirectoryHT AppEnv) { if (other.TypeName == this.TypeName) @@ -1898,7 +1987,6 @@ namespace RusticiSoftware.Translator.CLR } } - [XmlIgnore] private List _indexers = null; [XmlArrayItem("Indexer")] public List Indexers { @@ -1909,6 +1997,16 @@ namespace RusticiSoftware.Translator.CLR } } + private IterableRepTemplate _iterable = null; + public IterableRepTemplate Iterable { + get { + return _iterable; + } + set { + _iterable = value; + } + } + public InterfaceRepTemplate () : base() { Inherits = null; @@ -2088,6 +2186,19 @@ namespace RusticiSoftware.Translator.CLR return base.ResolveIndexer(args, AppEnv); } + public override ResolveResult ResolveIterable(DirectoryHT AppEnv) + { + + if (Iterable != null) + { + ResolveResult res = new ResolveResult(); + res.Result = Iterable; + res.ResultType = BuildType(Iterable.ReturnType, AppEnv); + return res; + } + return base.ResolveIterable(AppEnv); + } + #region Equality public bool Equals (InterfaceRepTemplate other) { diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/JavaPrettyPrint.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/JavaPrettyPrint.g index 158614b..059c1bf 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/JavaPrettyPrint.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/JavaPrettyPrint.g @@ -218,15 +218,15 @@ options { public string cleanTemplate(string template) { // Are there any markers in the template? Mostly, the answer will be no and we can return tout-de-suite String ret = template; - if (Regex.IsMatch(ret, "\\$\\{.*\\}")) { + if (Regex.IsMatch(ret, "\\$\\{\\w+\\}")) { // ${this}.fred -> fred - ret = Regex.Replace(ret, "\\$\\{.*\\}\\.", String.Empty); + ret = Regex.Replace(ret, "\\$\\{\\w+?\\}\\.", String.Empty); // (a,${var},b) -> (a,b) - ret = Regex.Replace(ret, "\\$\\{.*\\},", String.Empty); + ret = Regex.Replace(ret, "\\$\\{\\w+?\\},", String.Empty); // (a,${var}) -> (a) - ret = Regex.Replace(ret, ",\\$\\{.*\\}", String.Empty); + ret = Regex.Replace(ret, ",\\$\\{\\w+?\\}", String.Empty); // (${var}) -> () - ret = Regex.Replace(ret, "\\$\\{.*\\}", String.Empty); + ret = Regex.Replace(ret, "\\$\\{\\w+?\\}", String.Empty); } return ret; } diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g index d28df00..255f6b8 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g @@ -208,8 +208,9 @@ scope SymTab { } - // counter to ensure that the catch vars we introduce are unique + // counter to ensure that the vars we introduce are unique protected int dummyScrutVarCtr = 0; + protected int dummyForeachVarCtr = 0; protected CommonTree convertSectionsToITE(List sections) { CommonTree ret = null; @@ -256,6 +257,33 @@ scope SymTab { return ret; } + // embeddedStatement is either ";", "{ .... }", or a single statement + protected CommonTree prefixCast(CommonTree ty, CommonTree id, CommonTree foreachVar, CommonTree embeddedStatement, IToken tok) { + CommonTree root = embeddedStatement; + if (!embeddedStatement.IsNil && adaptor.GetType(embeddedStatement) == SEMI) { + // Do nothing, id is unused + } + else { + // Make cast statement + CommonTree kast = (CommonTree)adaptor.Nil; + kast = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(CAST_EXPR, tok, "CAST"), kast); + adaptor.AddChild(kast, (CommonTree)adaptor.DupTree(ty)); + adaptor.AddChild(kast, (CommonTree)adaptor.DupTree(foreachVar)); + CommonTree vardec = (CommonTree)adaptor.Nil; + adaptor.AddChild(vardec, (CommonTree)adaptor.DupTree(ty)); + adaptor.AddChild(vardec, (CommonTree)adaptor.DupTree(id)); + adaptor.AddChild(vardec, (CommonTree)adaptor.Create(ASSIGN, tok, "=")); + adaptor.AddChild(vardec, (CommonTree)adaptor.DupTree(kast)); + root = (CommonTree)adaptor.Nil; + // Make a { statement } + adaptor.AddChild(root, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{")); + adaptor.AddChild(root, vardec); + // todo: strip "{ }" + adaptor.AddChild(root, (CommonTree)adaptor.DupTree(embeddedStatement)); + adaptor.AddChild(root, (CommonTree)adaptor.Create(OPEN_BRACE, tok, "{")); + } + return (CommonTree)adaptor.RulePostProcessing(root); + } } compilation_unit @@ -1459,11 +1487,54 @@ iteration_statement scope SymTab; @init { $SymTab::symtab = new Dictionary(); + CommonTree ret = null; + CommonTree newType = null; + CommonTree newIdentifier = null; + CommonTree newExpression = null; + CommonTree newEmbeddedStatement = null; +} +@after { + if (ret != null) + $iteration_statement.tree = ret; }: ^('while' boolean_expression SEP embedded_statement) | do_statement | ^('for' for_initializer? SEP for_condition? SEP for_iterator? SEP embedded_statement) - | ^('foreach' local_variable_type identifier expression SEP { $SymTab::symtab[$identifier.thetext] = $local_variable_type.dotNetType; } embedded_statement); + | ^(f='foreach' local_variable_type identifier expression s=SEP { $SymTab::symtab[$identifier.thetext] = $local_variable_type.dotNetType; } embedded_statement) + magicObjectType[$f.token] magicForeachVar[$f.token] + { + newType = $local_variable_type.tree; + newIdentifier = $identifier.tree; + newExpression = $expression.tree; + newEmbeddedStatement = $embedded_statement.tree; + TypeRepTemplate exprType = $expression.dotNetType; + TypeRepTemplate elType = null; + // translate expression, if available + if (exprType != null) { + ResolveResult iterable = exprType.ResolveIterable(AppEnv); + if (iterable != null) { + Dictionary myMap = new Dictionary(); + myMap["expr"] = wrapExpression($expression.tree, $expression.tree.Token); + newExpression = mkJavaWrapper(iterable.Result.Java, myMap, $expression.tree.Token); + Imports.Add(iterable.Result.Imports); + elType = iterable.ResultType; + } + } + bool needCast = true; + if (elType != null && $local_variable_type.dotNetType != null) { + if (elType.IsA($local_variable_type.dotNetType, AppEnv)) { + needCast = false; + } + } + // Construct new foreach using newExpression and needCast + if (needCast) { + newType = $magicObjectType.tree; + newIdentifier = $magicForeachVar.tree; + newEmbeddedStatement = prefixCast($local_variable_type.tree, $identifier.tree, newIdentifier, $embedded_statement.tree, $embedded_statement.tree.Token); + } + } + -> ^($f { newType } { newIdentifier } { newExpression } $s { newEmbeddedStatement }) + ; do_statement: 'do' embedded_statement 'while' '(' boolean_expression ')' ';' ; for_initializer: @@ -1577,6 +1648,15 @@ magicScrutineeVar [IToken tok] returns [String thetext] }: -> IDENTIFIER[tok,$thetext]; +magicForeachVar [IToken tok] returns [String thetext] +@init { + $thetext = "__dummyForeachVar" + dummyForeachVarCtr++; +}: + -> IDENTIFIER[tok,$thetext]; + +magicObjectType [IToken tok]: + -> ^(TYPE[tok, "TYPE"] OBJECT[tok, "System.Object"]); + magicCastOperator[CommonTree mods, String methodName, CommonTree header, CommonTree body] @init { IToken tok = ((CommonTree)$header.Children[0]).Token; diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g index 9dbf4ab..d00cfa7 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g @@ -61,6 +61,7 @@ tokens { THROW = 'throw'; ELSE = 'else'; BREAK = 'break'; + OBJECT = 'object'; OPEN_BRACKET='['; CLOSE_BRACKET=']';