config-parser-0.1.0.0: Text/ConfigParser/Types.hs
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
module Text.ConfigParser.Types where
import Data.List (nub)
import Text.Parsec (string, spaces, char, (<?>))
import Text.Parsec.Text (Parser)
type Key = String
-- Key-value pair to parse from a config file.
data ConfigOption c = forall a. ConfigOption
{ key :: Key -- ^ Key name.
, parser :: Parser a -- ^ Parser for the given value type.
, action :: a -> c -> c -- ^ How the value should change the state @c@.
}
-- | Parameters for a parser that takes a config file and produces a @c@. Use
-- the 'configParser_' constructor if you want to specify your own 'lineParser'
-- or 'commentStart'. Otherwise, use the 'configParser' smart constructor.
data ConfigParser c = ConfigParser
{ keyValue :: forall a. Key -> Parser a -> Parser a
-- ^ Specifies how a key and a value parser should be represented in the
-- config file, e.g., @key = value@, or @key: value@.
, lineCommentInit :: [String]
-- Strings to start a line comment, such as @#@, @--@, or @//@. All
-- characters following this string up to the following newline or EOF
-- will be removed. You can use the string without starting a comment by
-- escaping it with a backslash, e.g. @\#@ or @\--@.
, defaults :: c
-- Initial @c@ to fold each 'ConfigOption's action over.
, options :: [ConfigOption c]
-- List of key-value pairs to parse from the config file. Any key in the
-- config file that doesn't appear here will result in parse error.
}
-- | Smart constructor to check that 'options' doesn't contain any duplicate
-- keys before creating a 'ConfigParser'.
configParser_ :: (forall a. Key -> Parser a -> Parser a)
-> [String] -> c -> [ConfigOption c] -> ConfigParser c
configParser_ kv cs ds os' = ConfigParser kv cs ds os
where
os = if length (nub $ fmap key os') == length os'
then os'
else error "duplicate option keys in ConfigParser"
-- | Smart constructor for a 'ConfigParser' that uses a default syntax like
-- @key = value@ and line comments starting with @#@.
configParser :: c -> [ConfigOption c] -> ConfigParser c
configParser = configParser_ defaultKeyValue defaultLineCommentInit
-- | Default syntax like @key = value@.
defaultKeyValue :: Key -> Parser a -> Parser a
defaultKeyValue k p = keyParser *> separator *> p
where
keyParser = string k <?> "option key"
separator = spaces *> char '=' <* spaces
-- | Default line comment like @# comment text@.
defaultLineCommentInit :: [String]
defaultLineCommentInit = ["#"]