module Data.SCargot.Repr.Rich
(
R.RichSExpr(..)
, R.toRich
, R.fromRich
, cons
, uncons
, pattern (:::)
, pattern A
, pattern L
, pattern DL
, pattern Nil
, _car
, _cdr
, fromPair
, fromList
, fromAtom
, asPair
, asList
, isAtom
, isNil
, asAtom
, asAssoc
, car
, cdr
) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative (Applicative, (<$>), (<*>), pure)
#endif
import Data.SCargot.Repr as R
_car :: Applicative f => (RichSExpr a -> f (RichSExpr a)) -> RichSExpr a -> f (RichSExpr a)
_car f (RSList (x:xs)) = (\ y -> L (y:xs)) `fmap` f x
_car f (RSDotted (x:xs) a) = (\ y -> DL (y:xs) a) `fmap` f x
_car _ (RSAtom a) = pure (A a)
_car _ (RSList []) = pure Nil
_car _ (RSDotted [] a) = pure (A a)
_cdr :: Applicative f => (RichSExpr a -> f (RichSExpr a)) -> RichSExpr a -> f (RichSExpr a)
_cdr f (RSList (x:xs)) =
let go (RSList []) = L [x]
go (RSAtom a) = DL [x] a
go (RSList xs') = L (x:xs')
go (RSDotted ys a') = DL (x:ys) a'
in go `fmap` f (L xs)
_cdr f (RSDotted [x] a) =
let go (RSList []) = L [x]
go (RSAtom a') = DL [x] a'
go (RSList xs) = L (x:xs)
go (RSDotted ys a') = DL (x:ys) a'
in go `fmap` f (A a)
_cdr f (RSDotted (x:xs) a) =
let go (RSList []) = L [x]
go (RSAtom a') = DL [x] a'
go (RSList ys) = L (x:ys)
go (RSDotted ys a') = DL (x:ys) a'
in go `fmap` f (DL xs a)
_cdr _ (RSAtom a) = pure (A a)
_cdr _ (RSList []) = pure Nil
_cdr _ (RSDotted [] a) = pure (A a)
uncons :: RichSExpr a -> Maybe (RichSExpr a, RichSExpr a)
uncons (R.RSList (x:xs)) = Just (x, R.RSList xs)
uncons (R.RSDotted (x:xs) a) = Just (x, R.RSDotted xs a)
uncons _ = Nothing
cons :: RichSExpr a -> RichSExpr a -> RichSExpr a
cons x (R.RSList xs) = R.RSList (x:xs)
cons x (R.RSDotted xs a) = R.RSDotted (x:xs) a
cons x (R.RSAtom a) = R.RSDotted [x] a
#if MIN_VERSION_base(4,8,0)
pattern (:::) :: RichSExpr a -> RichSExpr a -> RichSExpr a
#endif
pattern x ::: xs <- (uncons -> Just (x, xs))
#if MIN_VERSION_base(4,8,0)
where x ::: xs = cons x xs
#endif
#if MIN_VERSION_base(4,8,0)
pattern A :: a -> RichSExpr a
#endif
pattern A a = R.RSAtom a
#if MIN_VERSION_base(4,8,0)
pattern L :: [RichSExpr a] -> RichSExpr a
#endif
pattern L xs = R.RSList xs
#if MIN_VERSION_base(4,8,0)
pattern DL :: [RichSExpr a] -> a -> RichSExpr a
#endif
pattern DL xs x = R.RSDotted xs x
#if MIN_VERSION_base(4,8,0)
pattern Nil :: RichSExpr a
#endif
pattern Nil = R.RSList []
fromPair :: (RichSExpr t -> Either String a)
-> (RichSExpr t -> Either String b)
-> RichSExpr t -> Either String (a, b)
fromPair pl pr = asPair $ \(l,r) -> (,) <$> pl l <*> pr r
fromList :: (RichSExpr t -> Either String a) -> RichSExpr t -> Either String [a]
fromList p = asList $ \ss -> mapM p ss
fromAtom :: RichSExpr t -> Either String t
fromAtom (RSList _) = Left "fromAtom: expected atom; found list"
fromAtom (RSDotted _ _) = Left "fromAtom: expected atom; found dotted list"
fromAtom (RSAtom a) = return a
asPair :: ((RichSExpr t, RichSExpr t) -> Either String a)
-> RichSExpr t -> Either String a
asPair f (RSList [l, r]) = f (l, r)
asPair _ (RSList ls) = Left ("asPair: expected two-element list; found list of lenght " ++ show (length ls))
asPair _ RSDotted {} = Left ("asPair: expected two-element list; found dotted list")
asPair _ RSAtom {} = Left ("asPair: expected two-element list; found atom")
asList :: ([RichSExpr t] -> Either String a)
-> RichSExpr t -> Either String a
asList f (RSList ls) = f ls
asList _ RSDotted {} = Left ("asList: expected list; found dotted list")
asList _ RSAtom { } = Left ("asList: expected list; found dotted list")
isAtom :: Eq t => t -> RichSExpr t -> Either String ()
isAtom s (RSAtom s')
| s == s' = return ()
| otherwise = Left "isAtom: failed to match atom"
isAtom _ RSList {} = Left "isAtom: expected atom; found list"
isAtom _ RSDotted {} = Left "isAtom: expected atom; found dotted list"
isNil :: RichSExpr t -> Either String ()
isNil (RSList []) = return ()
isNil RSList {} = Left "isNil: expected nil; found non-nil list"
isNil RSDotted {} = Left "isNil: expected nil; found dotted list"
isNil RSAtom {} = Left "isNil: expected nil; found atom"
asAtom :: (t -> Either String a) -> RichSExpr t -> Either String a
asAtom f (RSAtom s) = f s
asAtom _ RSList {} = Left ("asAtom: expected atom; found list")
asAtom _ RSDotted {} = Left ("asAtom: expected atom; found dotted list")
asAssoc :: ([(RichSExpr t, RichSExpr t)] -> Either String a)
-> RichSExpr t -> Either String a
asAssoc f (RSList ss) = gatherPairs ss >>= f
where gatherPairs (RSList [a, b] : ts) = (:) <$> pure (a, b) <*> gatherPairs ts
gatherPairs [] = pure []
gatherPairs (RSAtom {} : _) = Left ("asAssoc: expected pair; found atom")
gatherPairs (RSDotted {} : _) = Left ("asAssoc: expected pair; found dotted list")
gatherPairs (RSList ls : _) = Left ("asAssoc: expected pair; found list of length " ++ show (length ls))
asAssoc _ RSDotted {} = Left "asAssoc: expected assoc list; found dotted list"
asAssoc _ RSAtom {} = Left "asAssoc: expected assoc list; found atom"
car :: (RichSExpr t -> Either String t') -> [RichSExpr t] -> Either String t'
car f (x:_) = f x
car _ [] = Left "car: Taking car of zero-element list"
cdr :: ([RichSExpr t] -> Either String t') -> [RichSExpr t] -> Either String t'
cdr f (_:xs) = f xs
cdr _ [] = Left "cdr: Taking cdr of zero-element list"