{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
module Language.Bond.Codegen.Java.Enum_java
( enum_java
) where
import Prelude
import Data.Text.Lazy (Text)
import Text.Shakespeare.Text
import Language.Bond.Syntax.Types
import Language.Bond.Util
import Language.Bond.Codegen.TypeMapping
import Language.Bond.Codegen.Util
import qualified Language.Bond.Codegen.Java.Util as Java
enum_java :: MappingContext -> Declaration -> Text
enum_java java declaration = [lt|
package #{javaPackage};
#{typeDefinition declaration}
|]
where
javaPackage = sepBy "." toText $ getNamespace java
typeDefinition Enum {..} = [lt|
#{Java.generatedClassAnnotations}
public final class #{declName} implements org.bondlib.BondEnum<#{declName}> {
public static final class Values {
private Values() {}
#{newlineSep 2 constantIntValueDecl enumConstantsWithInt}
}
private static final class EnumBondTypeImpl extends org.bondlib.EnumBondType<#{declName}> {
@Override
public java.lang.Class<#{declName}> getValueClass() { return #{declName}.class; }
@Override
public final #{declName} getEnumValue(int value) { return get(value); }
}
public static final org.bondlib.EnumBondType<#{declName}> BOND_TYPE = new EnumBondTypeImpl();
#{newlineSep 1 constantObjectDecl enumConstantsWithInt}
public final int value;
private final java.lang.String label;
private #{declName}(int value, java.lang.String label) { this.value = value; this.label = label; }
@Override
public final int getValue() { return this.value; }
@Override
public final java.lang.String getLabel() { return this.label; }
@Override
public final org.bondlib.EnumBondType<#{declName}> getBondType() { return BOND_TYPE; }
@Override
public final int compareTo(#{declName} o) { return this.value < o.value ? -1 : (this.value > o.value ? 1 : 0); }
@Override
public final boolean equals(java.lang.Object other) { return (other instanceof #{declName}) && (this.value == ((#{declName}) other).value); }
@Override
public final int hashCode() { return this.value; }
@Override
public final java.lang.String toString() { return this.label != null ? this.label : ("#{declName}(" + java.lang.String.valueOf(this.value) + ")"); }
public static #{declName} get(int value) {
switch (value) {
#{newlineSep 3 switchCaseConstantMapping enumConstantsWithIntDistinct}
default: return new #{declName}(value, null);
}
}
public static #{declName} valueOf(java.lang.String str) {
if (str == null) {
throw new java.lang.IllegalArgumentException("Argument 'str' must not be null.");
#{newlineSepEnd 2 parseCaseConstantMapping enumConstants}} else {
throw new java.lang.IllegalArgumentException("Invalid '#{declName}' enum value: '" + str + "'.");
}
}
}|]
where
constantObjectDecl c@Constant {..} =
[lt|public static final #{declName} #{constantName} = #{enumObjectAssigmentValue c};|]
constantIntValueDecl Constant {..} = let value x = [lt|#{x}|] in
[lt|public static final int #{constantName} = #{optional value constantValue};|]
switchCaseConstantMapping Constant {..} =
[lt|case Values.#{constantName}: return #{constantName};|]
parseCaseConstantMapping Constant {..} =
[lt|} else if (str.equals("#{constantName}")) {
return #{constantName};|]
enumConstantsWithInt = fixEnumWithInt 0 enumConstants []
fixEnumWithInt :: Int -> [Constant] -> [Constant] -> [Constant]
fixEnumWithInt _ [] result = reverse result
fixEnumWithInt nextInt (h:r) result = case constantValue h of
Just n -> let fixedN = (fromInteger (Java.twosComplement 32 (toInteger n))) in
fixEnumWithInt (fixedN + 1) r ((Constant (constantName h) (Just fixedN)):result)
Nothing -> fixEnumWithInt (nextInt + 1) r ((Constant (constantName h) (Just nextInt)):result)
enumConstantsWithIntDistinct = findEnumConstantsDistinct enumConstantsWithInt []
findEnumConstantsDistinct :: [Constant] -> [Maybe Int] -> [Constant]
findEnumConstantsDistinct [] _ = []
findEnumConstantsDistinct (h:r) keys = if elem (constantValue h) keys
then findEnumConstantsDistinct r keys
else h : findEnumConstantsDistinct r ((constantValue h):keys)
enumObjectAssigmentValue :: Constant -> Text
enumObjectAssigmentValue enumConstant =
let firstDeclaredEnumConstant = head (filter (\c -> (constantValue c) == (constantValue enumConstant)) enumConstantsWithIntDistinct) in
if firstDeclaredEnumConstant == enumConstant
then [lt|new #{declName}(Values.#{constantName enumConstant}, "#{constantName enumConstant}")|]
else [lt|#{constantName firstDeclaredEnumConstant}|]
typeDefinition _ = mempty