sexpr-parser-0.2.0.0: lib/Text/SExpression/Default.hs
{-# OPTIONS_GHC -Wall -Werror #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
#undef MEGAPARSEC_7_OR_LATER
#ifdef MIN_VERSION_GLASGOW_HASKELL
-- GHC >= 7.10.1.0
#if MIN_VERSION_GLASGOW_HASKELL(8,0,0,0)
-- GHC >= 8.0.0.0
#if MIN_VERSION_megaparsec(7,0,0)
#define MEGAPARSEC_7_OR_LATER
#endif
#endif
#endif
module Text.SExpression.Default
( LiteralParsers(..)
, LiteralParsersM
, mkLiteralParsers
, overrideStringP
, overrideNumberP
, overrideBoolP
, parseStringDef
, parseNumberDef
, parseBoolDef
) where
import Data.Semigroup (Last(..))
import Data.Default
import Text.SExpression.Types (SExpr(..), Parser)
import Control.Monad (void)
import Text.Megaparsec
( (<|>)
, many
, notFollowedBy
#ifdef MEGAPARSEC_7_OR_LATER
, noneOf
#endif
, some
)
import Text.Megaparsec.Char
( char
, digitChar
, string
, alphaNumChar
#ifndef MEGAPARSEC_7_OR_LATER
, noneOf
#endif
)
-- | Partial parser configuration
data LiteralParsersM = LiteralParsersM
{ parseStringM :: Maybe (Last (Parser SExpr))
, parseNumberM :: Maybe (Last (Parser SExpr))
, parseBoolM :: Maybe (Last (Parser SExpr))
}
-- | Fully defined parser configuration
data LiteralParsers = LiteralParsers
{ parseString :: Parser SExpr
, parseNumber :: Parser SExpr
, parseBool :: Parser SExpr
}
instance Semigroup LiteralParsersM where
(<>)
(LiteralParsersM ps pn pb)
(LiteralParsersM ps' pn' pb') =
LiteralParsersM (ps <> ps') (pn <> pn') (pb <> pb')
instance Default LiteralParsersM where
def = LiteralParsersM
{ parseStringM = Just $ Last parseStringDef
, parseNumberM = Just $ Last parseNumberDef
, parseBoolM = Just $ Last parseBoolDef
}
instance Default LiteralParsers where
def = mkLiteralParsers def
-- | Smart constructor for parser configuration
-- that allows overriding the default literal parsers
mkLiteralParsers ::
(LiteralParsersM -> LiteralParsersM) -- ^ Cumulative override function
-> LiteralParsers
mkLiteralParsers f =
case f def of
LiteralParsersM{..} ->
let Just (Last parseString) = parseStringM
Just (Last parseNumber) = parseNumberM
Just (Last parseBool) = parseBoolM in
LiteralParsers parseString parseNumber parseBool
-- | String parser override function
overrideStringP :: Parser SExpr -- ^ String parser
-> (LiteralParsersM -> LiteralParsersM)
overrideStringP sp lp = lp <>
LiteralParsersM
{ parseStringM = Just $ Last sp
, parseNumberM = Nothing
, parseBoolM = Nothing
}
-- | Number parser override function
overrideNumberP :: Parser SExpr -- ^ Number parser
-> (LiteralParsersM -> LiteralParsersM)
overrideNumberP np lp = lp <>
LiteralParsersM
{ parseStringM = Nothing
, parseNumberM = Just $ Last np
, parseBoolM = Nothing
}
-- | Boolean parser override function
overrideBoolP :: Parser SExpr -- ^ Bool parser
-> (LiteralParsersM -> LiteralParsersM)
overrideBoolP bp lp = lp <>
LiteralParsersM
{ parseStringM = Nothing
, parseNumberM = Nothing
, parseBoolM = Just $ Last bp
}
-- | Default parser for s-expression boolean literals
parseBoolDef ::
Parser SExpr
parseBoolDef = do
b <- string "#t" <* notFollowedBy alphaNumChar
<|> string "#f" <* notFollowedBy alphaNumChar
case b of
"#t" -> return $ Bool True
"#f" -> return $ Bool False
_ -> fail "Not a boolean"
-- | Default parser for s-expression numeric literals
parseNumberDef ::
Parser SExpr -- ^ parser
parseNumberDef = (Number . read) <$> some digitChar
-- | Default parser for s-expression string literals
parseStringDef ::
Parser SExpr -- ^ parser
parseStringDef = do
void $ char '"'
s <- many (noneOf "\"")
void $ char '"'
pure $ String s