protobuf-simple-0.1.1.1: src/Parser/EnumGenerator.hs
-- |
-- Module: Parser.EnumGenerator
-- Copyright: (c) 2015-2016 Martijn Rijkeboer <mrr@sru-systems.com>
-- License: MIT
-- Maintainer: Martijn Rijkeboer <mrr@sru-systems.com>
--
-- Generate code for Enum types.
module Parser.EnumGenerator
( getEnumCode
) where
import Control.Monad.State (State)
import Data.List (foldl', groupBy, intersperse, sortOn)
import Data.Text.Lazy (Text)
import Data.Text.Lazy.Builder (Builder, fromString, toLazyText)
import Parser.EnumDesc (EnumDesc)
import Parser.EnumValueDesc (EnumValueDesc)
import Parser.FileDesc (FileDesc)
import Parser.GeneratorUtils
( GenState,
getComment,
getUnqualifiedImport,
getQualifiedAsImport,
empty,
nl,
tab
)
import qualified Parser.EnumDesc as EnumDesc
import qualified Parser.EnumValueDesc as EnumValueDesc
import qualified Parser.FileDesc as FileDesc
getEnumCode :: FileDesc -> EnumDesc -> State GenState Text
getEnumCode f ed = do
commentLine <- getComment
moduleLine <- getModule f ed
importLines <- getImports f ed
typeLines <- getType f ed
defaultInst <- getDefaultInst ed
mergeableInst <- getMergeableInst ed
wireEnumInst <- getWireEnumInst ed
return $ toLazyText $
commentLine <> nl <>
moduleLine <> nl <>
importLines <> nl <>
typeLines <> nl <>
defaultInst <> nl <>
mergeableInst <> nl <>
wireEnumInst <> nl
getModule :: FileDesc -> EnumDesc -> State GenState Builder
getModule f ed = do
modName <- getModuleName f ed
return $
fromString "module " <>
fromString modName <>
fromString " where" <> nl
getModuleName :: FileDesc -> EnumDesc -> State GenState String
getModuleName f ed = return $ case FileDesc.getPackage f of
Just package -> package ++ "." ++ enumName
Nothing -> fileName ++ "." ++ enumName
where
fileName = FileDesc.getName f
enumName = EnumDesc.getName ed
getImports :: FileDesc -> EnumDesc -> State GenState Builder
getImports _ _ = return $
getUnqualifiedImport "Prelude" "" <>
getQualifiedAsImport "Data.ProtoBufInt" "PB"
getType :: FileDesc -> EnumDesc -> State GenState Builder
getType f ed = do
enumValues <- getEnumValues f ed
return $
fromString "data " <>
fromString name <>
fromString " = " <>
enumValues <>
nl <>
tab <>
fromString "deriving (PB.Show, PB.Eq, PB.Ord)" <> nl
where name = EnumDesc.getName ed
getEnumValues :: FileDesc -> EnumDesc -> State GenState Builder
getEnumValues _ ed = fmap (foldl' (<>) empty) ivalues
where
ivalues = fmap (intersperse separator) fvalues
fvalues = mapM getEnumValue (EnumDesc.getValueDescs ed)
separator = fromString " | "
getEnumValue :: EnumValueDesc -> State GenState Builder
getEnumValue = return . fromString . EnumValueDesc.getName
getDefaultInst :: EnumDesc -> State GenState Builder
getDefaultInst ed = return $
fromString "instance PB.Default " <> fromString name <> fromString " where" <> nl <>
tab <> fromString "defaultVal = " <> fromString first <> nl
where
name = EnumDesc.getName ed
first = EnumValueDesc.getName $ head $ EnumDesc.getValueDescs ed
getMergeableInst :: EnumDesc -> State GenState Builder
getMergeableInst ed = return $
fromString "instance PB.Mergeable " <> fromString name <> fromString " where" <> nl
where
name = EnumDesc.getName ed
getWireEnumInst :: EnumDesc -> State GenState Builder
getWireEnumInst ed = return $
fromString "instance PB.WireEnum " <> fromString name <> fromString " where" <> nl <>
intToEnumLines <> nl <>
enumToIntLines <> nl
where
name = EnumDesc.getName ed
intToEnumLines = getIntToEnumLines (EnumDesc.getValueDescs ed)
enumToIntLines = getEnumToIntLines (EnumDesc.getValueDescs ed)
getIntToEnumLines :: [EnumValueDesc] -> Builder
getIntToEnumLines es =
foldl' (<>) empty (map getIntToEnumLine $ uniqEs es) <>
tab <> fromString "intToEnum _ = PB.defaultVal" <> nl
where
uniqEs = map head . groupBy areEq . sortOn EnumValueDesc.getNumber
areEq a b = EnumValueDesc.getNumber a == EnumValueDesc.getNumber b
getIntToEnumLine :: EnumValueDesc -> Builder
getIntToEnumLine e = tab <> fromString "intToEnum " <> number <> fromString " = " <> name <> nl
where
name = fromString $ EnumValueDesc.getName e
number = fromString $ show $ EnumValueDesc.getNumber e
getEnumToIntLines :: [EnumValueDesc] -> Builder
getEnumToIntLines es = foldl' (<>) empty (map getEnumToIntLine es)
getEnumToIntLine :: EnumValueDesc -> Builder
getEnumToIntLine e = tab <> fromString "enumToInt " <> name <> fromString " = " <> number <> nl
where
name = fromString $ EnumValueDesc.getName e
number = fromString $ show $ EnumValueDesc.getNumber e