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