Basic.hs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. {-# LANGUAGE PatternSynonyms #-}
  2. module Data.SCargot.Repr.Basic
  3. ( -- * Basic 'SExpr' representation
  4. R.SExpr(..)
  5. -- * Shorthand Patterns
  6. , pattern (:::)
  7. , pattern A
  8. , pattern Nil
  9. -- * Lenses
  10. , _car
  11. , _cdr
  12. -- * Useful processing functions
  13. , fromPair
  14. , fromList
  15. , fromAtom
  16. , asPair
  17. , asList
  18. , isAtom
  19. , asAtom
  20. , asAssoc
  21. ) where
  22. import Control.Applicative ((<$>), (<*>), pure)
  23. import Data.SCargot.Repr as R
  24. -- | A traversal with access to the first element of a pair.
  25. _car :: Applicative f => (SExpr a -> f (SExpr a)) -> SExpr a -> f (SExpr a)
  26. _car f (x ::: xs) = (:::) <$> f x <*> pure xs
  27. _car _ (A a) = pure (A a)
  28. _car _ Nil = pure Nil
  29. -- | A traversal with access to the second element of a pair.
  30. _cdr :: Applicative f => (SExpr a -> f (SExpr a)) -> SExpr a -> f (SExpr a)
  31. _cdr f (x ::: xs) = (:::) <$> pure x <*> f xs
  32. _cdr _ (A a) = pure (A a)
  33. _cdr _ Nil = pure Nil
  34. infixr 5 :::
  35. -- | A shorter infix alias for `SCons`
  36. pattern x ::: xs = SCons x xs
  37. -- | A shorter alias for `SAtom`
  38. pattern A x = SAtom x
  39. -- | A (slightly) shorter alias for `SNil`
  40. pattern Nil = SNil
  41. -- | Utility function for parsing a pair of things.
  42. fromPair :: (SExpr t -> Either String a)
  43. -> (SExpr t -> Either String b)
  44. -> SExpr t -> Either String (a, b)
  45. fromPair pl pr (l ::: r ::: Nil) = (,) <$> pl l <*> pr r
  46. fromPair _ _ sx = Left ("Expected two-element list")
  47. -- | Utility function for parsing a list of things.
  48. fromList :: (SExpr t -> Either String a) -> SExpr t -> Either String [a]
  49. fromList p (s ::: ss) = (:) <$> p s <*> fromList p ss
  50. fromList p Nil = pure []
  51. fromList _ sx = Left ("Expected list")
  52. -- | Utility function for parsing a single atom
  53. fromAtom :: SExpr t -> Either String t
  54. fromAtom (A a) = return a
  55. fromAtom _ = Left "Expected atom; found list"
  56. gatherList :: SExpr t -> Either String [SExpr t]
  57. gatherList (x ::: xs) = (:) <$> pure x <*> gatherList xs
  58. gatherList Nil = pure []
  59. gatherList sx = Left ("Expected list")
  60. -- | Parse a two-element list (NOT a dotted pair) using the
  61. -- provided function.
  62. asPair :: ((SExpr t, SExpr t) -> Either String a)
  63. -> SExpr t -> Either String a
  64. asPair f (l ::: r ::: SNil) = f (l, r)
  65. asPair _ sx = Left ("Expected two-element list")
  66. -- | Parse an arbitrary-length list using the provided function.
  67. asList :: ([SExpr t] -> Either String a) -> SExpr t -> Either String a
  68. asList f ls = gatherList ls >>= f
  69. -- | Match a given literal atom, failing otherwise.
  70. isAtom :: Eq t => t -> SExpr t -> Either String ()
  71. isAtom s (A s')
  72. | s == s' = return ()
  73. | otherwise = Left ".."
  74. isAtom _ _ = Left ".."
  75. -- | Parse an atom using the provided function.
  76. asAtom :: (t -> Either String a) -> SExpr t -> Either String a
  77. asAtom f (A s) = f s
  78. asAtom _ sx = Left ("Expected symbol")
  79. -- | Parse an assoc-list using the provided function.
  80. asAssoc :: ([(SExpr t, SExpr t)] -> Either String a)
  81. -> SExpr t -> Either String a
  82. asAssoc f ss = gatherList ss >>= mapM go >>= f
  83. where go (a ::: b ::: Nil) = return (a, b)
  84. go sx = Left ("Expected two-element list")