General.hs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. module Data.SCargot.General
  2. ( -- * SExprSpec
  3. SExprSpec
  4. , mkSpec
  5. , convertSpec
  6. , addReader
  7. , addCommentType
  8. , asRich
  9. , asWellFormed
  10. -- * A Few Standard Reader Macros
  11. , quote
  12. , vector
  13. -- * Using a SExprSpec
  14. , parseSExpr
  15. , serializeSExpr
  16. ) where
  17. import Control.Applicative
  18. import Data.Attoparsec.Text
  19. import Data.Map.String (Map)
  20. import qualified Data.Map.String as M
  21. import Data.SCargot.Repr
  22. type ReaderMacroMap atom = Map Char (Reader atom)
  23. type CommentMap = Map Char (Parser ())
  24. type Reader atom = (Parser (SExpr atom) -> Parser (SExpr atom))
  25. type Serializer atom = atom -> Text
  26. -- | A 'SExprSpec' describes a parser and emitter for a particular
  27. -- variant of S-Expressions. The @atom@ type corresponds to a
  28. -- Haskell type used to represent the atoms, and the @carrier@
  29. -- type corresponds to the parsed S-Expression structure. The
  30. -- 'SExprSpec' type is deliberately opaque so that it must be
  31. -- constructed and modified with other helper functions.
  32. data SExprSpec atom carrier = SExprSpec
  33. { sesPAtom :: Parser atom
  34. , sesSAtom :: Serializer atom
  35. , readerMap :: ReaderMacroMap atom
  36. , commentMap :: CommentMap
  37. , postparse :: SExpr atom -> Either String carrier
  38. , preserial :: carrier -> SExpr atom
  39. }
  40. -- | This creates a basic 'SExprSpec' when given a parser and serializer
  41. -- for an atom type.
  42. mkSpec :: Parser atom -> Serializer atom -> SExprSpec atom (SExpr atom)
  43. mkSpec p s = SExprSpec
  44. { sesPAtom = p
  45. , sesSAtom = s
  46. , rmMap = M.empty
  47. , postparse = return
  48. , preserial = id
  49. }
  50. -- | This is used to modify the carrier type for a 'SExprSpec'. This is
  51. -- used internally to convert between various 'SExpr' representations,
  52. -- but could also be used externally to add an extra conversion layer
  53. -- onto a 'SExprSpec', e.g. for a custom Lisp-like language:
  54. --
  55. -- > mySpec :: SExprSpec MyAtomType MyAST
  56. -- > mySpec = convertSpec sexprToMyAST myASTToSexpr spec
  57. -- > where spec = mkSpec myParser mySerializer
  58. convertSpec :: (b -> Either String c) -> (c -> b) -> SExprSpec a b -> SExprSpec a c
  59. convertSpec f g spec = spec
  60. { postparse = postparse spec >=> f
  61. , preserial = g . preserial spec
  62. }
  63. addReader :: Char -> Reader a -> SExprSpec a c -> SExprSpec a c
  64. addReader c reader spec = spec { rmMap = insert c reader (rmMap spec) }
  65. addCommentType :: Char -> Comment -> SExprSpec a c -> SExprSpec a c
  66. addCommentType c comment spec = spec { }
  67. quote :: atom -> Reader atom
  68. quote q parse = go <$> parse
  69. where go v = SCons q (SCons v SNil)
  70. asRich :: SExprSpec a (SExpr b) -> SExprSpec a (RichSExpr b)
  71. asRich = convertSpec (return . toRich) fromRich
  72. asWellFormed :: SExprSpec a (SExpr b) -> SExprSpec a (WellFormedSExpr b)
  73. asWellFormed = convertSpec toWellFormed fromWellFormed
  74. parseGenericSExpr :: Parser atom -> ReaderMacroMap atom -> CommentMap -> Parser (SExpr atom)
  75. parseGenericSExpr atom reader comment =
  76. char '(' *>
  77. -- |
  78. parseSExpr :: SExprSpec atom carrier -> Text -> Either String carrier
  79. parseSExpr spec = undefined
  80. -- | blah
  81. serializeSExpr :: SExprSpec atom carrier -> carrier -> Text
  82. serializeSExpr spec = serializeGenericSExpr ses . preserial