protobuf-simple-0.1.0.0: 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.Monoid ((<>))
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
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