diff --git a/CS2JLibrary/NetFramework/System/Collections/Generic/KeyCollection'1.xml b/CS2JLibrary/NetFramework/System/Collections/Generic/KeyCollection'1.xml
index b6d21f6..664f39c 100644
--- a/CS2JLibrary/NetFramework/System/Collections/Generic/KeyCollection'1.xml
+++ b/CS2JLibrary/NetFramework/System/Collections/Generic/KeyCollection'1.xml
@@ -42,6 +42,16 @@
CopyTo
System.Void
+
+
+ CS2JNet.JavaSupport.Collections.Generic.EnumeratorSupport
+
+ new EnumeratorSupport*[T]*(${this}.iterator())
+
+
+ GetEnumerator
+ System.Collections.Generic.IEnumerator*[T]*
+
diff --git a/CS2JLibrary/NetFramework/System/Collections/IEnumerator.xml b/CS2JLibrary/NetFramework/System/Collections/IEnumerator.xml
new file mode 100644
index 0000000..fab0041
--- /dev/null
+++ b/CS2JLibrary/NetFramework/System/Collections/IEnumerator.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ CS2JNet.System.Collections.Generic.IEnumeratorSupport
+
+ IEnumeratorSupport
+ System.Collections.IEnumerator
+
+ System.Object
+ Current>
+ ${this:16}.getcurrent()
+
+jEYi0rdl/kMLr7uBNG0M9LMlbCQ=C/hbBQnMGlWnPvwE61XrMusMlyKT+K792pEYR7D7CnpO7Td1gFgCCfkSdFVZ1axk+sLzebWIQKH8+NFRC6+hlNpViODt46v/300e+fi2Yx8BWhpq5e51zfNAhHIdaUemMqHMHNG5BMOngpFx1yrO/zxHvj7HPJqGBwJV7w8yPtU=
diff --git a/CS2JLibrary/src/CS2JNet/System/Collections/Generic/ICollectionSupport.java b/CS2JLibrary/src/CS2JNet/System/Collections/Generic/ICollectionSupport.java
index fc1f4ec..cc788b5 100644
--- a/CS2JLibrary/src/CS2JNet/System/Collections/Generic/ICollectionSupport.java
+++ b/CS2JLibrary/src/CS2JNet/System/Collections/Generic/ICollectionSupport.java
@@ -20,12 +20,14 @@
package CS2JNet.System.Collections.Generic;
+import java.util.Collection;
+
/**
* @author kevin.glynn@twigletsoftware.com
*
*/
-public interface ICollectionSupport extends Iterable {
+public interface ICollectionSupport extends Collection {
public boolean Contains(T x) throws Exception;
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs
new file mode 100644
index 0000000..62f779f
--- /dev/null
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/Fragments.cs
@@ -0,0 +1,181 @@
+/*
+ Copyright 2010,2011 Kevin Glynn (kevin.glynn@twigletsoftware.com)
+*/
+
+using System;
+using System.Collections.Generic;
+using Antlr.Runtime.Tree;
+
+namespace Twiglet.CS2J.Translator
+{
+ public class Fragments
+ {
+
+ public static string GenericCollectorMethods(string T, string S)
+ {
+ return genericCollectorMethodsStr.Replace("${T}", T).Replace("${S}", S);
+ }
+
+ private static string genericCollectorMethodsStr = @"
+ public Iterator<${T}> iterator() {
+ Iterator<${T}> ret = null;
+ try
+ {
+ ret = this.GetEnumerator().iterator();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ public boolean add(${T} el) {
+ try
+ {
+ this.Add(el);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return true;
+ }
+
+ public boolean addAll(Collection extends ${T}> c) {
+ for (${T} el : c) {
+ this.add(el);
+ }
+ return true;
+ }
+
+ public void clear() {
+ try
+ {
+ this.Clear();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean contains(Object o) {
+ boolean ret = false;
+ try
+ {
+ ret = this.Contains((${T}) o);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ public boolean containsAll(Collection> c) {
+ boolean ret = true;
+ for (Object el : c) {
+ if (!this.contains(el)) {
+ ret = false;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ public boolean isEmpty() {
+ return this.size() == 0;
+ }
+
+ public boolean remove(Object o) {
+ boolean ret = false;
+ try
+ {
+ ret = this.Remove((${T}) o);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ public boolean removeAll(Collection> c) {
+ boolean ret = false;
+ for (Object el : c) {
+ ret = ret | this.remove(el);
+ }
+ return ret;
+ }
+
+ public boolean retainAll(Collection> c) {
+ boolean ret = false;
+ Object[] thisCopy = this.toArray();
+ for (Object el : thisCopy) {
+ if (!c.contains(el)) {
+ ret = ret | this.remove(el);
+ }
+ }
+ return false;
+ }
+
+ public int size() {
+ int ret = -1;
+ try {
+ return this.getCount();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+
+ public Object[] toArray() {
+ Object[] ret = new Object[this.size()];
+ int i = 0;
+ for (Object el : this) {
+ ret[i] = el;
+ }
+ return ret;
+ }
+
+ // NOTE: Moved to after the method name, like C# not Java, to help the poor parser.
+ public ${S}[] toArray<${S}>(${S}[] a) {
+ ArrayList<${T}> ret = new ArrayList<${T}>(this.size());
+ for (${T} el : this) {
+ ret.add(el);
+ }
+ return ret.toArray(a);
+ }
+";
+
+ public static string GenIterator = @"
+ public Iterator<${T}> iterator() {
+ Iterator<${T}> ret = null;
+ try
+ {
+ ret = this.GetEnumerator().iterator();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return ret;
+ }";
+
+ private static Dictionary _fragmentsLibrary = null;
+ public static Dictionary FragmentsLibrary
+ { get
+ {
+ if (_fragmentsLibrary == null)
+ {
+ _fragmentsLibrary = new Dictionary();
+ }
+ return _fragmentsLibrary;
+ }
+ }
+ }
+}
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g
index e1bc3e3..8c880df 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g
@@ -26,6 +26,11 @@ scope NSContext {
List typeVariables;
// all typevariables in all scopes
List globalTypeVariables;
+
+ // Does this type implement ICollection?
+ bool IsGenericICollection;
+ string GenericICollectionTyVar;
+ bool IsICollection;
}
// A scope to keep track of the mapping from variables to types
@@ -185,7 +190,6 @@ scope MkNonGeneric {
}
private ClassRepTemplate dateType = null;
-
protected ClassRepTemplate DateType {
get {
if (dateType == null) {
@@ -195,6 +199,26 @@ scope MkNonGeneric {
}
}
+ private InterfaceRepTemplate iCollectionType = null;
+ protected InterfaceRepTemplate ICollectionType {
+ get {
+ if (iCollectionType == null) {
+ iCollectionType = (InterfaceRepTemplate)findType("System.Collections.ICollection");
+ }
+ return iCollectionType;
+ }
+ }
+
+ private InterfaceRepTemplate genericICollectionType = null;
+ protected InterfaceRepTemplate GenericICollectionType {
+ get {
+ if (genericICollectionType == null) {
+ genericICollectionType = (InterfaceRepTemplate)findType("System.Collections.Generic.ICollection", new TypeRepTemplate[] {ObjectType});
+ }
+ return genericICollectionType;
+ }
+ }
+
// Map of Java built in types to their object based equivalents
Dictionary primitive_to_object_type_map = new Dictionary()
{
@@ -319,6 +343,7 @@ scope MkNonGeneric {
protected int dummyScrutVarCtr = 0;
protected int dummyForeachVarCtr = 0;
protected int dummyStaticConstructorCatchVarCtr = 0;
+ protected int dummyTyVarCtr = 0;
// It turns out that 'default:' doesn't have to be last in the switch statement, so
// we need some jiggery pokery when converting to if-then-else.
@@ -518,6 +543,11 @@ scope NSContext, PrimitiveRep, MkNonGeneric;
$NSContext::typeVariables = new List();
$NSContext::globalTypeVariables = new List();
+
+ $NSContext::IsGenericICollection = false;
+ $NSContext::GenericICollectionTyVar = "";
+ $NSContext::IsICollection = false;
+
}:
^(pkg=PACKAGE ns=PAYLOAD { $NSContext::currentNS = $ns.text; } dec=type_declaration )
-> ^($pkg $ns { mkImports() } $dec);
@@ -1630,6 +1660,11 @@ scope NSContext,SymTab;
$NSContext::globalNamespaces = new List(((NSContext_scope)$NSContext.ToArray()[1]).globalNamespaces);
$NSContext::typeVariables = new List();
$NSContext::globalTypeVariables = new List(((NSContext_scope)$NSContext.ToArray()[1]).globalTypeVariables);
+
+ $NSContext::IsGenericICollection = false;
+ $NSContext::GenericICollectionTyVar = "";
+ $NSContext::IsICollection = false;
+
$SymTab::symtab = new Dictionary();
}
:
@@ -1659,6 +1694,12 @@ scope NSContext,SymTab;
}
$SymTab::symtab["super"] = baseType;
}
+ if ($NSContext::IsICollection) {
+ Debug(10, $NSContext::currentNS + " is a Collection");
+ }
+ if ($NSContext::IsGenericICollection) {
+ Debug(10, $NSContext::currentNS + " is a Generic Collection");
+ }
}
class_body magicAnnotation[$modifiers.tree, $identifier.tree, null, $c.token])
-> {$class_implements.hasExtends && $class_implements.extendDotNetType.IsA(AppEnv.Search("System.Attribute", new UnknownRepTemplate("System.Attribute")), AppEnv)}? magicAnnotation
@@ -1680,7 +1721,8 @@ class_extend:
// If first implements type is a class then convert to extends
class_implements returns [bool hasExtends, TypeRepTemplate extendDotNetType]:
- class_implement_or_extend { $hasExtends = $class_implement_or_extend.hasExtends; $extendDotNetType = $class_implement_or_extend.extendDotNetType; }class_implement* ;
+ class_implement_or_extend { $hasExtends = $class_implement_or_extend.hasExtends; $extendDotNetType = $class_implement_or_extend.extendDotNetType; }
+ class_implement* ;
class_implement_or_extend returns [bool hasExtends, TypeRepTemplate extendDotNetType]
@init {
@@ -1691,18 +1733,36 @@ class_implement_or_extend returns [bool hasExtends, TypeRepTemplate extendDotNet
$hasExtends = true;
$extendDotNetType = $t.dotNetType;
}
+ if($t.dotNetType.IsA(ICollectionType,AppEnv)) $NSContext::IsICollection = true;
+ if($t.dotNetType.IsA(GenericICollectionType,AppEnv)) {
+ $NSContext::IsGenericICollection = true;
+ $NSContext::GenericICollectionTyVar = $t.dotNetType.TypeParams[0];
+ }
} )
-> { $t.dotNetType is ClassRepTemplate }? ^(EXTENDS[$i.token, "extends"] type)
-> ^($i $t);
class_implement:
- ^(IMPLEMENTS type) ;
+ ^(IMPLEMENTS t=type
+ {
+ if($t.dotNetType.IsA(ICollectionType,AppEnv)) $NSContext::IsICollection = true;
+ if($t.dotNetType.IsA(GenericICollectionType,AppEnv)) {
+ $NSContext::IsGenericICollection = true;
+ $NSContext::GenericICollectionTyVar = $t.dotNetType.TypeParams[0];
+ }
+ }) ;
-interface_type_list:
- type (',' type)* ;
-
-class_body:
- '{' class_member_declarations? '}' ;
+class_body
+@init {
+ CommonTree collectorNodes = null;
+ if ($NSContext::IsGenericICollection) {
+ collectorNodes = this.parseString("class_member_declarations", Fragments.GenericCollectorMethods($NSContext::GenericICollectionTyVar, $NSContext::GenericICollectionTyVar + "__" + dummyTyVarCtr++));
+ AddToImports("java.util.Iterator");
+ AddToImports("java.util.Collection");
+ AddToImports("java.util.ArrayList");
+ }
+}:
+ '{' class_member_declarations? '}' -> '{' class_member_declarations? { dupTree(collectorNodes) } '}' ;
class_member_declarations:
class_member_declaration+ ;
@@ -1816,6 +1876,10 @@ scope NSContext,SymTab;
$NSContext::globalNamespaces = new List(((NSContext_scope)$NSContext.ToArray()[1]).globalNamespaces);
$NSContext::typeVariables = new List();
$NSContext::globalTypeVariables = new List(((NSContext_scope)$NSContext.ToArray()[1]).globalTypeVariables);
+
+ $NSContext::IsGenericICollection = false;
+ $NSContext::IsICollection = false;
+
$SymTab::symtab = new Dictionary();
}
:
@@ -1881,8 +1945,6 @@ interface_declaration:
class_extends? interface_body ) ;
interface_modifiers:
modifier+ ;
-interface_base:
- ':' interface_type_list ;
interface_body:
'{' interface_member_declarations? '}' ;
interface_member_declarations:
@@ -2384,3 +2446,185 @@ magicThrowableType[bool isOn, IToken tok]:
magicEventCollectionType[IToken tok, CommonTree type]:
-> ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "IEventCollection"] LTHAN[tok, "<"] { dupTree(type) } GT[tok, ">"] )
;
+
+// METHOD{ public TYPE{ Iterator < TYPE{ JAVAWRAPPER{ T } } > } kiterator { TYPE{ Iterator < TYPE{ JAVAWRAPPER{ T } } > } ret = null ; try{ { ret = APPLY{ .{ JAVAWRAPPER{ ${this:16}.GetEnumerator() this EXPRESSION{ this } } iterator } } ; } catch{ TYPE{ JAVAWRAPPER{ Exception } } e { APPLY{ .{ e printStackTrace } } ; } } } return{ ret } } Exception }
+//
+
+magicXXGenericIterator[bool isOn, IToken tok, String tyVar]
+@init {
+ if (isOn) AddToImports("java.util.Iterator");
+}
+:
+-> {isOn}? ^(METHOD[tok, "METHOD"]
+ PUBLIC[tok, "public"]
+ ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "Iterator"] LTHAN[tok, "<"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, tyVar]) GT[tok, ">"])
+ IDENTIFIER[tok, "iterator"]
+ OPEN_BRACE[tok, "{"]
+ // Iterator ret = null;
+ ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "Iterator"] LTHAN[tok, "<"] ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, tyVar]) GT[tok, ">"]) IDENTIFIER[tok, "ret"] ASSIGN[tok,"="] NULL[tok,"null"] SEMI[tok, ";"]
+ // try { ret = this.GetEnumerator().iterator(); } catch (Exception e) { e.printstackTrace(); }}
+ ^(TRY[tok, "try"]
+ OPEN_BRACE[tok, "{"]
+ IDENTIFIER[tok, "ret"] ASSIGN[tok,"="] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] THIS[tok, "this"] IDENTIFIER[tok, "GetEnumerator"])) IDENTIFIER[tok,"iterator"])) SEMI[tok,";"]
+ CLOSE_BRACE[tok, "}"]
+ ^(CATCH[tok, "catch"] ^(TYPE[tok,"TYPE"] IDENTIFIER[tok, "Exception"]) IDENTIFIER[tok, "e"]
+ OPEN_BRACE[tok, "{"]
+ ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] IDENTIFIER[tok, "e"] IDENTIFIER[tok,"printStackTrace"])) SEMI[tok,";"]
+ CLOSE_BRACE[tok, "}"]
+ )
+ )
+ // return ret;
+ ^(RETURN[tok, "return"] IDENTIFIER[tok, "ret"])
+ CLOSE_BRACE[tok, "}"]
+ )
+
+->
+;
+
+// IDENTIFIER[tok, "ret"] ASSIGN[tok,"="] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] THIS[tok, "this"] IDENTIFIER[tok, "GetEnumerator"])) IDENTIFIER[tok,"iterator"])) SEMI[tok,";"]
+
+magicGenericIterator[bool isOn, IToken tok, String tyVar]
+@init {
+ if (isOn) AddToImports("java.util.Iterator");
+}
+:
+ magicType[isOn, tok, "Iterator", new string[\] {tyVar}]
+ n=magicToken[isOn, tok, NULL, "null"]
+ magicAssignment[isOn, tok, $magicType.tree, "ret", $n.tree]
+
+ thisT=magicToken[isOn, tok, THIS, "this"]
+ thisEnum=magicDot[isOn, tok, $thisT.tree, "GetEnumerator"]
+ mkIter=magicDot[isOn, tok, $thisEnum.tree, "iterator"]
+ tryBody=magicApply[isOn, tok, $mkIter.tree, null]
+
+ magicTryCatch[isOn, tok, $tryBody.tree]
+
+ magicMethod[isOn, tok, "iterator", $magicType.tree, null, $magicTryCatch.tree]
+
+-> {isOn}? magicMethod
+->
+;
+
+magicIterator[bool isOn, IToken tok]
+@init {
+ if (isOn) AddToImports("java.util.Iterator");
+}
+:
+ magicType[isOn, tok, "Iterator", null]
+ n=magicToken[isOn, tok, NULL, "null"]
+ magicAssignment[isOn, tok, $magicType.tree, "ret", $n.tree]
+// magicSmotherExceptions[isOn, tok, ]
+ magicMethod[isOn, tok, "iterator", $magicType.tree, null, $magicAssignment.tree]
+-> {isOn}? magicMethod
+// ^(METHOD[tok, "METHOD"]
+// PUBLIC[tok, "public"]
+// ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "Iterator"])
+// IDENTIFIER[tok, "iterator"]
+// OPEN_BRACE[tok, "{"]
+// // Iterator ret = null;
+// ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, "Iterator"]) IDENTIFIER[tok, "ret"] ASSIGN[tok,"="] NULL[tok,"null"] SEMI[tok, ";"]
+// // try { ret = this.GetEnumerator().iterator(); } catch (Exception e) { e.printstackTrace(); }}
+// ^(TRY[tok, "try"]
+// OPEN_BRACE[tok, "{"]
+// IDENTIFIER[tok, "ret"] ASSIGN[tok,"="] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] THIS[tok, "this"] IDENTIFIER[tok, "GetEnumerator"])) IDENTIFIER[tok,"iterator"])) SEMI[tok,";"]
+// CLOSE_BRACE[tok, "}"]
+// ^(CATCH[tok, "catch"] ^(TYPE[tok,"TYPE"] IDENTIFIER[tok, "Exception"]) IDENTIFIER[tok, "e"]
+// OPEN_BRACE[tok, "{"]
+// ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] IDENTIFIER[tok, "e"] IDENTIFIER[tok,"printStackTrace"])) SEMI[tok,";"]
+// CLOSE_BRACE[tok, "}"]
+// )
+// )
+// // return ret;
+// ^(RETURN[tok, "return"] IDENTIFIER[tok, "ret"])
+// CLOSE_BRACE[tok, "}"]
+// )
+//
+->
+;
+
+magicToken[bool isOn, IToken tok, int tokenType, string text]
+@init {
+ CommonTree ret = null;
+ if (isOn)
+ ret = (CommonTree)adaptor.Create(tokenType, tok, text);
+}:
+-> {isOn}? { ret }
+->
+;
+
+// public { }
+magicMethod[bool isOn, IToken tok, string name, CommonTree retType, CommonTree args, CommonTree body]:
+-> {isOn}?
+ ^(METHOD[tok, "METHOD"]
+ PUBLIC[tok, "public"]
+ { dupTree(retType) }
+ IDENTIFIER[tok, name]
+ { dupTree(args) }
+ OPEN_BRACE[tok, "{"]
+ { dupTree(body) }
+ CLOSE_BRACE[tok, "}"]
+ )
+->
+;
+
+magicType[bool isOn, IToken tok, string name, string[\] args]
+@init {
+ CommonTree argsTree = null;
+ if (args != null && args.Length > 0) {
+ CommonTree root = (CommonTree)adaptor.Nil;
+ adaptor.AddChild(root, (CommonTree)adaptor.Create(LTHAN, tok, "<"));
+ foreach (string a in args) {
+ CommonTree root0 = (CommonTree)adaptor.Nil;
+ root0 = (CommonTree)adaptor.BecomeRoot((CommonTree)adaptor.Create(TYPE, tok, "TYPE"), root0);
+ adaptor.AddChild(root0, (CommonTree)adaptor.Create(IDENTIFIER, tok, a));
+ adaptor.AddChild(root, root0);
+ }
+ adaptor.AddChild(root, (CommonTree)adaptor.Create(GT, tok, ">"));
+ argsTree = (CommonTree)adaptor.RulePostProcessing(root);
+ }
+}
+:
+-> {isOn}?
+ ^(TYPE[tok, "TYPE"]
+ IDENTIFIER[tok, name]
+ { dupTree(argsTree) }
+ )
+->
+;
+
+// ? = exp ;
+magicAssignment[bool isOn, IToken tok, CommonTree type, string name, CommonTree exp]:
+-> {isOn}?
+ { dupTree(type) }
+ IDENTIFIER[tok, name]
+ ASSIGN[tok, "="]
+ { dupTree(exp) }
+ SEMI[tok, ";"]
+->
+;
+
+magicTryCatch[bool isOn, IToken tok, CommonTree body]:
+-> {isOn}?
+ ^(TRY[tok, "try"]
+ OPEN_BRACE[tok, "{"]
+ { dupTree(body) }
+ CLOSE_BRACE[tok, "}"]
+ ^(CATCH[tok, "catch"] ^(TYPE[tok,"TYPE"] IDENTIFIER[tok, "Exception"]) IDENTIFIER[tok, "e"]
+ OPEN_BRACE[tok, "{"]
+ ^(APPLY[tok, "APPLY"] ^(DOT[tok, "."] IDENTIFIER[tok, "e"] IDENTIFIER[tok,"printStackTrace"])) SEMI[tok,";"]
+ CLOSE_BRACE[tok, "}"]
+ )
+ )
+->
+;
+
+magicDot[bool isOn, IToken tok, CommonTree lhs, string rhs]:
+-> {isOn}? ^(DOT[tok, "."] { dupTree(lhs) } IDENTIFIER[tok, rhs])
+->
+;
+
+magicApply[bool isOn, IToken tok, CommonTree methodExp, CommonTree args]:
+-> {isOn}? ^(APPLY[tok, "APPLY"] { dupTree(methodExp) } { dupTree(args) })
+->
+;
+