{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Misc where
import Prelude hiding ((.), id)
import Control.Category
import qualified Data.ByteString.Lazy.Char8 as B8
import qualified Language.Sexp as Sexp
import Language.SexpGrammar
import Language.SexpGrammar.Generic
import GHC.Generics
newtype Ident = Ident String
deriving (Show, Generic)
data Pair a b = Pair a b
deriving (Show, Generic)
data Person = Person
{ pName :: String
, pAddress :: String
, pAge :: Maybe Int
} deriving (Show, Generic)
instance (SexpIso a, SexpIso b) => SexpIso (Pair a b) where
sexpIso =
-- Combinator 'with' matches the single constructor of a datatype to a grammar
with $ \_Pair -> -- pops b, pops a, applies a to Pair,
-- apply b to (Pair a): (Pair a b :- t)
list ( -- begin list
el sexpIso >>> -- consume and push first element to stack: (a :- t)
el sexpIso -- consume and push second element to stack: (b :- a :- t)
) >>> _Pair
instance SexpIso Person where
sexpIso = with $ \_Person ->
_Person .
list (
el (sym "person") >>>
el string' >>>
props (
Kw "address" .: string' >>>
Kw "age" .:? int))
data FooBar a
= Foo Int Double
| Bar a
deriving (Show, Generic)
foobarSexp :: SexpG (FooBar Int)
foobarSexp =
match $
With (\foo -> foo . list (el int >>> el double)) $
With (\bar -> bar . int) $
End
test :: String -> SexpG a -> (a, String)
test str g = either error id $ do
e <- decodeWith g (B8.pack str)
sexp' <- genSexp g e
return (e, B8.unpack (Sexp.encode sexp'))