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=']';