diff --git a/CS2JLibrary/NetFramework/System/EnumAsNumber.xml b/CS2JLibrary/NetFramework/System/EnumAsNumber.xml
new file mode 100644
index 0000000..27f48e6
--- /dev/null
+++ b/CS2JLibrary/NetFramework/System/EnumAsNumber.xml
@@ -0,0 +1,98 @@
+
+
+
+
+ Enum
+ System.EnumAsNumber
+
+
+ System.Int32
+
+
+
+
+ CS2JNet.System.EnumSupport
+
+ EnumSupport.isDefined(${enumType}, ${value})
+
+
+ System.Object
+ enumType
+
+
+ System.Object
+ value
+
+
+ IsDefined
+ System.Boolean
+
+
+
+ CS2JNet.System.EnumSupport
+
+ EnumSupport.toString(${this}, ${modifier})
+
+
+ System.String
+ modifier
+
+
+ ToString
+ System.String
+
+
+
+ Enum.valueOf((Class*[? extends Enum]*)${enumType:15}, ${value})
+
+
+ System.Type
+ enumType
+
+
+ System.String
+ value
+
+
+ Parse
+ System.Object
+
+
+
+
+
+
+
+
+
+
+ ${to_type}.values()[${expr}]
+ System.Byte
+
+
+
+ (byte)(((Enum)${expr}).ordinal())
+ System.Enum
+ System.Byte
+
+
+
+ ${to_type}.values()[${expr}]
+ System.Int32
+
+
+
+ ((Enum)${expr}).ordinal()
+ System.Enum
+ System.Int32
+
+
+
+
+IJMEeLm8aEBz8xz+22PUOm4mKmY=GBzy7yxUC2deFlJLdqC849pFbVEg5Zv+sB5LLtV4mnAixFeiQ5PlOHal7FqDSoqMtMpjMYpc9rjRvkWrQSWWWMJ5IAOI4HZBcTy1CYAWXnBXMjoUscMdyFIgzQF7ExrANCDt0LUn7xWCAb2S57bcj7yIREPjDonAM6YPOWi9Xa4=
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs
index 11d765b..4c123ed 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JMain.cs
@@ -130,6 +130,8 @@ namespace Twiglet.CS2J.Translator
.Add ("translator-keep-parens=", v => cfg.TranslatorKeepParens = Boolean.Parse(v))
.Add ("translator-timestamp-files=", v => cfg.TranslatorAddTimeStamp = Boolean.Parse(v))
.Add ("translator-exception-is-throwable=", v => cfg.TranslatorExceptionIsThrowable = Boolean.Parse(v))
+ .Add ("experimental-enums-numericconsts", v => cfg.EnumsAsNumericConsts = true)
+ .Add ("experimental-unsigned-translatesigned", v => cfg.UnsignedNumbersToSigned = true)
.Add ("experimental-transforms=", v => cfg.ExperimentalTransforms = Boolean.Parse(v))
.Add ("internal-isjavaish", v => cfg.InternalIsJavaish = true)
;
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JSettings.cs b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JSettings.cs
index 3fca330..90b4c39 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JSettings.cs
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JMain/CS2JSettings.cs
@@ -56,6 +56,16 @@ namespace Twiglet.CS2J.Translator
get; set;
}
+ public bool EnumsAsNumericConsts
+ {
+ get; set;
+ }
+
+ public bool UnsignedNumbersToSigned
+ {
+ get; set;
+ }
+
public bool ExperimentalTransforms
{
get; set;
@@ -99,6 +109,9 @@ namespace Twiglet.CS2J.Translator
TranslatorAddTimeStamp = true;
TranslatorExceptionIsThrowable = false;
+ EnumsAsNumericConsts = false;
+ UnsignedNumbersToSigned = false;
+
ExperimentalTransforms = false;
InternalIsJavaish = false;
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g
index 15becb6..79849bf 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaMaker.g
@@ -467,6 +467,13 @@ scope TypeContext {
{"string", "String"}
};
+ Dictionary predefined_unsigned_type_map = new Dictionary()
+ {
+ {"uint", "int"},
+ {"ulong", "long"},
+ {"ushort", "short"}
+ };
+
protected CommonTree mkHole() {
return mkHole(null);
}
@@ -1439,13 +1446,20 @@ remove_accessor_declaration:
///////////////////////////////////////////////////////
enum_declaration[CommonTree atts, CommonTree mods] returns [string name]
scope TypeContext;
+@init {
+ CommonTree constType = null;
+}
:
- e='enum' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } enum_base? enum_body ';'?
- -> ^(ENUM[$e.token, "ENUM"] { dupTree($atts) } { dupTree($mods) } identifier enum_base? enum_body);
+ { Cfg.EnumsAsNumericConsts }? =>
+ e1='enum' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } magicBoxedType[true,$e1.token,"System.Int32"] { constType = $magicBoxedType.tree; } (enum_base {constType = $enum_base.tree; } )? enum_body_asnumber[constType] ';'?
+ -> ^(CLASS[$e1.token, "class"] { dupTree($atts) } { dupTree($mods) } identifier enum_body_asnumber)
+
+ | e2='enum' identifier { $name = $identifier.thetext; $TypeContext::typeName = $identifier.thetext; } enum_base? enum_body ';'?
+ -> ^(ENUM[$e2.token, "ENUM"] { dupTree($atts) } { dupTree($mods) } identifier enum_base? enum_body);
enum_base:
- ':' integral_type ;
-enum_body:
- '{' (enum_member_declarations ','?)? '}' -> ^(ENUM_BODY enum_member_declarations? ) ;
+ c=':' integral_type -> ^(TYPE[$c.token, "TYPE"] integral_type) ;
+enum_body:
+ '{' (enum_member_declarations ','?)? '}' -> ^(ENUM_BODY enum_member_declarations? ) ;
enum_member_declarations
@init {
SortedList members = new SortedList();
@@ -1502,6 +1516,25 @@ enum_member_declaration[ SortedList members, ref int next]
integral_type:
'sbyte' | 'byte' | 'short' | 'ushort' | 'int' | 'uint' | 'long' | 'ulong' | 'char' ;
+// this escheme translates enums to a class containing numeric constants
+enum_body_asnumber [ CommonTree typeTree ]:
+ '{' (enum_member_declarations_asnumber[typeTree] (','!)?)? '}' ;
+enum_member_declarations_asnumber [ CommonTree typeTree ]
+@init {
+ CommonTree prevTree = null;
+}:
+ e1=enum_member_declaration_asnumber[typeTree, prevTree] { prevTree = $e1.thisTree; }
+ (','! en=enum_member_declaration_asnumber[typeTree, prevTree] { prevTree = $en.thisTree; })*
+ ;
+enum_member_declaration_asnumber [ CommonTree typeTree, CommonTree prevTree ] returns [ CommonTree thisTree ]
+@init {
+ CommonTree prev = $prevTree;
+}:
+ attributes? identifier { $thisTree = $identifier.tree; }
+ (eq='=' expression -> ^(FIELD[$eq.token, "FIELD"] attributes? PUBLIC[$eq.token, "public"] STATIC[$eq.token, "static"] FINAL[$eq.token, "final"] { dupTree(typeTree) } identifier $eq expression)
+ | magicNumber[$prevTree == null, $identifier.tree.Token, "0"] magicIncrement[$prevTree != null, $identifier.tree.token, $prevTree]
+ { prev = $prevTree == null ? $magicNumber.tree : $magicIncrement.tree; } -> ^(FIELD[$identifier.tree.Token, "FIELD"] attributes? PUBLIC[$identifier.tree.Token, "public"] STATIC[$identifier.tree.Token, "static"] FINAL[$identifier.tree.Token, "final"] { dupTree(typeTree) } identifier ASSIGN[$identifier.tree.Token, "="] { dupTree(prev) })) ;
+
// B.2.12 Delegates
delegate_declaration[CommonTree atts, CommonTree mods, bool toplevel] returns [Dictionary compUnits]
scope TypeContext;
@@ -1962,6 +1995,9 @@ predefined_type returns [string thetext]
if (predefined_type_map.TryGetValue($predefined_type.tree.Token.Text, out newText)) {
$predefined_type.tree.Token.Text = newText;
}
+ if (Cfg.UnsignedNumbersToSigned && predefined_unsigned_type_map.TryGetValue($predefined_type.tree.Token.Text, out newText)) {
+ $predefined_type.tree.Token.Text = newText;
+ }
}:
'bool' { $thetext = "System.Boolean"; }
| 'byte' { $thetext = "System.Byte"; }
@@ -1975,9 +2011,9 @@ predefined_type returns [string thetext]
| 'sbyte' { $thetext = "System.SByte"; }
| 'short' { $thetext = "System.Int16"; }
| 'string' { $thetext = "System.String"; }
- | 'uint' { $thetext = "System.UInt32"; }
- | 'ulong' { $thetext = "System.UInt64"; }
- | 'ushort' { $thetext = "System.UInt16"; }
+ | 'uint' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.Int32" : "System.UInt32"; }
+ | 'ulong' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.Int64" : "System.UInt64"; }
+ | 'ushort' { $thetext = Cfg.UnsignedNumbersToSigned ? "System.Int16" : "System.UInt16"; }
;
identifier returns [string thetext]
@@ -2271,3 +2307,18 @@ magicMultiDelClass[IToken tok, CommonTree atts, CommonTree mods, string classNam
//magicClassFromDescriptor[IToken tok, ClassDescriptor klass]:
//-> ^(CLASS[tok] PAYLOAD[tok, klass.Comments] { dupTree(klass.Atts) } { dupTree(klass.Mods) } { dupTree(klass.Identifier) } { dupTree(klass.TypeParameterConstraintsClauses) } { dupTree(klass.TypeParameterList) } { dupTree(klass.ClassBase) } OPEN_BRACE[tok, "{"] { dupTree(klass.ClassBody) } { emitPartialTypes(klass.PartialTypes) } CLOSE_BRACE[tok, "}"] );
+
+magicBoxedType[bool isOn, IToken tok, String boxedName]:
+ -> { isOn }? ^(TYPE[tok, "TYPE"] IDENTIFIER[tok, boxedName])
+ ->
+;
+
+magicNumber[bool isOn, IToken tok, string number]:
+ -> { isOn }? NUMBER[tok, number]
+ ->
+;
+
+magicIncrement[bool isOn, IToken tok, CommonTree prevExpr]:
+ -> { isOn }? ^(PLUS[tok, "+"] { dupTree(prevExpr) } NUMBER[tok, "1"])
+ ->
+;
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g
index 3fbef49..46ca8c1 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/JavaPrettyPrint.g
@@ -1268,7 +1268,7 @@ enum_declaration
^(ENUM { preComments = CollectedComments; } attributes? modifiers? identifier enum_base? enum_body )
-> enum(comments = { preComments}, modifiers = { $modifiers.st }, name={$identifier.text}, body={$enum_body.st}) ;
enum_base:
- ':' integral_type ;
+ type ;
enum_body:
^(ENUM_BODY es+=enum_member_declaration*) -> enum_body(values={$es});
enum_member_declaration:
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g
index d383354..26cfb3c 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/NetMaker.g
@@ -2397,7 +2397,7 @@ remove_accessor_declaration:
enum_declaration:
^(ENUM attributes? modifiers? identifier enum_base? enum_body );
enum_base:
- ':' integral_type ;
+ type ;
enum_body:
^(ENUM_BODY enum_member_declarations?) ;
enum_member_declarations:
@@ -2949,9 +2949,9 @@ predefined_type returns [TypeRepTemplate dotNetType]
| 'sbyte' { ns = "System.SByte"; }
| 'short' { ns = "System.Int16"; }
| 'string' { ns = "System.String"; }
- | 'uint' { ns = "System.UInt32"; }
- | 'ulong' { ns = "System.UInt64"; }
- | 'ushort' { ns = "System.UInt16"; }
+ | 'uint' { ns = Cfg.UnsignedNumbersToSigned ? "System.Int32" : "System.UInt32"; }
+ | 'ulong' { ns = Cfg.UnsignedNumbersToSigned ? "System.Int64" : "System.UInt64"; }
+ | 'ushort' { ns = Cfg.UnsignedNumbersToSigned ? "System.Int16" : "System.UInt16"; }
;
// Don't trust identifier.text in tree grammars: Doesn't work for our magic additions because the text function goes back to the
diff --git a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g
index 35d3b8d..62e7306 100644
--- a/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g
+++ b/CSharpTranslator/antlr3/src/CS2JTranslator/CS2JTransform/TemplateExtracter.g
@@ -924,11 +924,16 @@ remove_accessor_declaration:
// enum declaration
///////////////////////////////////////////////////////
enum_declaration
+scope {
+ String baseType;
+}
scope NSContext;
@init {
$NSContext::searchpath = new List();
$NSContext::aliases = new List();
- EnumRepTemplate eenum = new EnumRepTemplate();
+ TypeRepTemplate eenum = Cfg.EnumsAsNumericConsts ? (TypeRepTemplate)new ClassRepTemplate() : (TypeRepTemplate)new EnumRepTemplate();
+ $enum_declaration::baseType = "System.Int32";
+ string javatype = "int";
}
:
'enum' identifier enum_base?
@@ -943,25 +948,48 @@ scope NSContext;
eenum.Uses = this.CollectUses;
eenum.Aliases = this.CollectAliases;
eenum.Imports = new string[] {NSPrefix(ParentNameSpace) + $identifier.text};
+ if (Cfg.EnumsAsNumericConsts) {
+ if (!String.IsNullOrEmpty($enum_base.thetext)) {
+ $enum_declaration::baseType = $enum_base.thetext;
+ javatype = $enum_base.javatype;
+ }
+ eenum.Java = javatype;
+ eenum.Inherits = new String[] { "System.EnumAsNumber" };
+ }
}
enum_body ';'? ;
-enum_base:
- ':' integral_type ;
+enum_base returns [string thetext, string javatype]:
+ ':' integral_type { $thetext = $integral_type.thetext; $javatype = $integral_type.javatype; } ;
enum_body:
'{' (enum_member_declarations ','?)? '}' ;
enum_member_declarations:
enum_member_declaration (',' enum_member_declaration)* ;
enum_member_declaration:
attributes? identifier ('=' expression)?
- { ((EnumRepTemplate)$NSContext::currentTypeRep).Members.Add(new EnumMemberRepTemplate($identifier.text, $expression.text)); } // todo: are arbitrary expressions really allowed
+ { if (Cfg.EnumsAsNumericConsts) {
+ ((ClassRepTemplate)$NSContext::currentTypeRep).Fields.Add(new FieldRepTemplate($enum_declaration::baseType, $identifier.text));
+ }
+ else {
+ ((EnumRepTemplate)$NSContext::currentTypeRep).Members.Add(new EnumMemberRepTemplate($identifier.text, $expression.text));
+ }
+ }
{ DebugDetail("Processing enum member: " + $identifier.text); }
;
//enum_modifiers:
// enum_modifier+ ;
//enum_modifier:
// 'new' | 'public' | 'protected' | 'internal' | 'private' ;
-integral_type:
- 'sbyte' | 'byte' | 'short' | 'ushort' | 'int' | 'uint' | 'long' | 'ulong' | 'char' ;
+integral_type returns [string thetext, string javatype]:
+ 'byte' { $thetext = "System.Byte"; $javatype = "byte"; }
+ | 'char' { $thetext = "System.Char"; $javatype = "char"; }
+ | 'int' { $thetext = "System.Int32"; $javatype = "int"; }
+ | 'long' { $thetext = "System.Int64"; $javatype = "long"; }
+ | 'sbyte' { $thetext = "System.SByte"; $javatype = "byte"; }
+ | 'short' { $thetext = "System.Int16"; $javatype = "short"; }
+ | 'uint' { $thetext = "System.UInt32"; $javatype = "int"; }
+ | 'ulong' { $thetext = "System.UInt64"; $javatype = "long"; }
+ | 'ushort' { $thetext = "System.UInt16"; $javatype = "short"; }
+ ;
// B.2.12 Delegates
delegate_declaration