123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- module Data.SExpression.General where
- import Control.Applicative
- import Data.Attoparsec.Text
- import Data.Map.String (Map)
- import qualified Data.Map.String as M
- type ReaderMacroMap atom = Map Char (Reader atom)
- type Reader atom = (Parser (SExpr atom) -> Parser (SExpr atom))
- type Serializer atom = atom -> Text
- -- | A 'SExprSpec' describes a parser and emitter for a particular
- -- variant of S-Expressions. The @atom@ type corresponds to a
- -- Haskell type used to represent the atoms, and the @carrier@
- -- type corresponds to the parsed S-Expression structure. This
- -- is deliberately opaque so that it must be constructed and
- -- modified with other helper functions.
- data SExprSpec atom carrier = SExprSpec
- { sesPAtom :: Parser atom
- , sesSAtom :: Serializer atom
- , rmMap :: ReaderMacroMap atom
- , postparse :: SExpr atom -> Either String carrier
- , preserial :: carrier -> SExpr atom
- }
- -- | This creates a basic 'SExprSpec' when given a parser and serializer
- -- for an atom type.
- mkSpec :: Parser atom -> Serializer atom -> SExprSpec atom (SExpr atom)
- mkSpec p s = SExprSpec
- { sesPAtom = p
- , sesSAtom = s
- , rmMap = M.empty
- , postparse = return
- , preserial = id
- }
- -- | This is used to modify the carrier type for a 'SExprSpec'. This is
- -- used internally to convert between various 'SExpr' representations,
- -- but could also be used externally to add an extra conversion layer
- -- onto a 'SExprSpec', e.g. for a custom Lisp-like language:
- --
- -- > mySpec :: SExprSpec MyAtomType MyAST
- -- > mySpec = convertSpec sexprToMyAST myASTToSexpr spec
- -- > where spec = mkSpec myParser mySerializer
- convertSpec :: (b -> Either String c) -> (c -> b) -> SExprSpec a b -> SExprSpec a c
- convertSpec f g spec = spec
- { postparse = postparse spec >=> f
- , preserial = g . preserial spec
- }
- addReader :: Char -> Reader a -> SExprSpec a c -> SExprSpec a c
- addReader c reader spec = spec { rmMap = insert c reader (rmMap spec) }
- quote :: atom -> Reader atom
- quote q parse = go <$> parse
- where go v = SCons q (SCons v SNil)
- toRich :: SExprSpec a (SExpr b) -> SExprSpec a (RichSExpr b)
- toRich = convertSpec (return . toRich) fromRich
- toWellFormed :: SExprSpec a (SExpr b) -> SExprSpec a (WellFormedSExpr b)
- toWellFormed = convertSpec toWellFormed fromWellFormed
- parseGenericSExpr :: Parser atom -> ReaderMacroMap atom -> Parser (SExpr atom)
- -- |
- parseSExpr :: SExprSpec atom carrier -> Text -> Either String carrier
- parseSExpr spec = undefined
- -- | blah
- serializeSExpr :: SExprSpec atom carrier -> carrier -> Text
- serializeSExpr spec = serializeGenericSExpr ses . preserial
|