| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Language.SexpGrammar
Contents
Description
Write your grammar once and get both parser and pretty-printer, for free.
data Person = Person
{ pName :: String
, pAddress :: String
, pAge :: Maybe Int
} deriving (Show)
personGrammar :: SexpG Person
personGrammar =
$(grammarFor 'Person) . -- construct Person from
list ( -- a list with
el (sym "person") >>> -- symbol "person",
el string' >>> -- some string,
props ( -- and properties
Kw "address" .: string' >>> -- :address with string value,
Kw "age" .:? int )) -- and optional :age int propretySo now we can use personGrammar to parse S-expessions to Person
record and pretty-print any Person back to S-expression.
(person "John Doe" :address "42 Whatever str." :age 25)
will parse into:
Person {pName = "John Doe", pAddress = "42 Whatever str.", pAge = Just 25}and the record will pretty-print back into:
(person "John Doe" :address "42 Whatever str." :age 25)
Grammar types diagram:
--------------------------------------
| AtomGrammar |
--------------------------------------
^
| atomic grammar combinators
v
------------------------------------------------------
| SexpGrammar |
------------------------------------------------------
| list, vect ^ ^
v | el, rest |
---------------------------------- |
| SeqGrammar | |
---------------------------------- | (.:)
| props | (.:?)
v |
-------------------------------------
| PropGrammar |
-------------------------------------- data Grammar g t t'
- type SexpG a = forall t. Grammar SexpGrammar (Sexp :- t) (a :- t)
- type SexpG_ = forall t. Grammar SexpGrammar (Sexp :- t) t
- iso :: (a -> b) -> (b -> a) -> Grammar g (a :- t) (b :- t)
- embedPrism :: StackPrism a b -> Grammar g (a :- t) (b :- t)
- embedParsePrism :: String -> StackPrism b a -> Grammar g (a :- t) (b :- t)
- push :: Eq a => a -> Grammar g t (a :- t)
- pushForget :: a -> Grammar g t (a :- t)
- bool :: SexpG Bool
- integer :: SexpG Integer
- int :: SexpG Int
- real :: SexpG Scientific
- double :: SexpG Double
- string :: SexpG Text
- symbol :: SexpG Text
- keyword :: SexpG Kw
- string' :: SexpG String
- symbol' :: SexpG String
- enum :: (Enum a, Bounded a, Eq a, Data a) => SexpG a
- sym :: Text -> SexpG_
- kw :: Kw -> SexpG_
- list :: Grammar SeqGrammar t t' -> Grammar SexpGrammar (Sexp :- t) t'
- vect :: Grammar SeqGrammar t t' -> Grammar SexpGrammar (Sexp :- t) t'
- el :: Grammar SexpGrammar (Sexp :- a) b -> Grammar SeqGrammar a b
- rest :: Grammar SexpGrammar (Sexp :- a) (b :- a) -> Grammar SeqGrammar a ([b] :- a)
- props :: Grammar PropGrammar a b -> Grammar SeqGrammar a b
- (.:) :: Kw -> Grammar SexpGrammar (Sexp :- t) (a :- t) -> Grammar PropGrammar t (a :- t)
- (.:?) :: Kw -> Grammar SexpGrammar (Sexp :- t) (a :- t) -> Grammar PropGrammar t (Maybe a :- t)
- pair :: Grammar g (b :- (a :- t)) ((a, b) :- t)
- unpair :: Grammar g ((a, b) :- t) (b :- (a :- t))
- swap :: Grammar g (b :- (a :- t)) (a :- (b :- t))
- coproduct :: [Grammar g a b] -> Grammar g a b
- grammarFor :: Name -> ExpQ
- data SexpGrammar a b
- data AtomGrammar a b
- data SeqGrammar a b
- data PropGrammar a b
- parseFromString :: SexpG a -> String -> Either String a
- parseFromFile :: SexpG a -> FilePath -> IO (Either String a)
- prettyToText :: SexpG a -> a -> Either String Text
- prettyToFile :: FilePath -> SexpG a -> a -> IO (Either String ())
- parse :: (Functor m, MonadPlus m, MonadError String m, InvertibleGrammar m g) => Grammar g (Sexp :- ()) (a :- ()) -> Sexp -> m a
- gen :: (Functor m, MonadPlus m, MonadError String m, InvertibleGrammar m g) => Grammar g (Sexp :- ()) (a :- ()) -> a -> m Sexp
- class SexpIso a where
- type StackPrism a b = forall p f. (Choice p, Applicative f) => p a (f a) -> p b (f b)
- data h :- t :: * -> * -> * = h :- t
Documentation
type SexpG a = forall t. Grammar SexpGrammar (Sexp :- t) (a :- t) Source
Grammar which matches Sexp to a value of type a and vice versa.
type SexpG_ = forall t. Grammar SexpGrammar (Sexp :- t) t Source
Grammar which pattern matches Sexp and produces nothing, or consumes nothing but generates some Sexp.
Combinators
Primitive grammars
iso :: (a -> b) -> (b -> a) -> Grammar g (a :- t) (b :- t) Source
Make a grammar from a total isomorphism on top element of stack
embedPrism :: StackPrism a b -> Grammar g (a :- t) (b :- t) Source
Make a grammar from a prism which can fail during generation
embedParsePrism :: String -> StackPrism b a -> Grammar g (a :- t) (b :- t) Source
Make a grammar from a prism which can fail during parsing
push :: Eq a => a -> Grammar g t (a :- t) Source
Unconditionally push given value on stack, i.e. it does not consume anything on parsing. However such grammar expects the same value as given one on stack during generation.
pushForget :: a -> Grammar g t (a :- t) Source
Same as push except it does not check the value on stack during
generation. Potentially unsafe as it "forgets" some data.
Atom grammars
real :: SexpG Scientific Source
Define an atomic real number (Scientific) grammar
Define an atomic double precision floating point number (Double) grammar
enum :: (Enum a, Bounded a, Eq a, Data a) => SexpG a Source
Define a grammar for an enumeration type. Automatically derives all symbol names from data constructor names and "lispifies" them.
Complex grammars
list :: Grammar SeqGrammar t t' -> Grammar SexpGrammar (Sexp :- t) t' Source
Define a sequence grammar inside a list
vect :: Grammar SeqGrammar t t' -> Grammar SexpGrammar (Sexp :- t) t' Source
Define a sequence grammar inside a vector
Sequence grammars
el :: Grammar SexpGrammar (Sexp :- a) b -> Grammar SeqGrammar a b Source
Define a sequence element grammar
rest :: Grammar SexpGrammar (Sexp :- a) (b :- a) -> Grammar SeqGrammar a ([b] :- a) Source
Define a grammar for rest of the sequence
props :: Grammar PropGrammar a b -> Grammar SeqGrammar a b Source
Define a property list grammar on the rest of the sequence. The remaining sequence must be empty or start with a keyword and its corresponding value and continue with the sequence built by the same rules.
E.g.
:kw1 <val1> :kw2 <val2> ... :kwN <valN>
Property grammars
(.:) :: Kw -> Grammar SexpGrammar (Sexp :- t) (a :- t) -> Grammar PropGrammar t (a :- t) Source
Define property pair grammar
(.:?) :: Kw -> Grammar SexpGrammar (Sexp :- t) (a :- t) -> Grammar PropGrammar t (Maybe a :- t) Source
Define optional property pair grammar
Utility grammars
unpair :: Grammar g ((a, b) :- t) (b :- (a :- t)) Source
Deconstruct pair into two top elements of stack
swap :: Grammar g (b :- (a :- t)) (a :- (b :- t)) Source
Swap two top elements of stack. Useful for defining grammars for data constructors with inconvenient field order.
E.g. consider a data type, which has field order different from what would like to display to user:
data Command = Command { args :: [String], executable :: FilePath }In S-expression executable should go first:
commandGrammar =
$(grammarFor 'Command) .
list ( el (sym "call") >>> -- symbol "call"
el string' >>> -- executable name
rest string' >>> -- arguments
swap )coproduct :: [Grammar g a b] -> Grammar g a b Source
Combine several alternative grammars into one grammar. Useful for defining grammars for sum types.
E.g. consider a data type:
data Maybe a = Nothing | Just a
A total grammar which would handle both cases should be constructed
with coproduct combinator or with Semigroup's instance.
maybeGrammar :: SexpG a -> SexpG (Maybe a)
maybeGrammar g =
coproduct
[ $(grammarFor 'Nothing) . kw (Kw "nil")
, $(grammarFor 'Just) . g
]TemplateHaskell helpers
grammarFor :: Name -> ExpQ Source
Build a prism and the corresponding grammar that will match on the given constructor and convert it to reverse sequence of :- stacks.
E.g. consider a data type:
data FooBar a b c = Foo a b c | Bar
For constructor Foo
fooGrammar = $(grammarFor 'Foo)
will expand into
fooGrammar = GenPrism "Foo" $
stackPrism
(\(c :- b :- a :- t) -> Foo a b c :- t)
(\case { Foo a b c :- t -> Just $ c :- b :- a :- t; _ -> Nothing })Note the order of elements on the stack:
ghci> :t fooGrammar fooGrammar :: Grammar g (c :- (b :- (a :- t))) (FooBar a b c :- t)
Grammar types
data SexpGrammar a b Source
data AtomGrammar a b Source
data SeqGrammar a b Source
data PropGrammar a b Source
Parsing and printing
Low-level printing and parsing
parse :: (Functor m, MonadPlus m, MonadError String m, InvertibleGrammar m g) => Grammar g (Sexp :- ()) (a :- ()) -> Sexp -> m a Source
gen :: (Functor m, MonadPlus m, MonadError String m, InvertibleGrammar m g) => Grammar g (Sexp :- ()) (a :- ()) -> a -> m Sexp Source
Typeclass for Sexp grammars
Minimal complete definition
Nothing
Instances
| SexpIso Bool Source | |
| SexpIso Double Source | |
| SexpIso Int Source | |
| SexpIso Integer Source | |
| SexpIso Scientific Source | |
| SexpIso Text Source | |
| SexpIso a => SexpIso [a] Source | |
| SexpIso a => SexpIso (Maybe a) Source | |
| (Ord a, SexpIso a) => SexpIso (Set a) Source | |
| SexpIso a => SexpIso (NonEmpty a) Source | |
| (SexpIso a, SexpIso b) => SexpIso (a, b) Source | |
| (Ord k, SexpIso k, SexpIso v) => SexpIso (Map k v) Source |
Re-exported from stack-prism
type StackPrism a b = forall p f. (Choice p, Applicative f) => p a (f a) -> p b (f b)