sexp-grammar
============
Invertible syntax library for serializing and deserializing Haskell
structures into S-expressions. Just write a grammar once and get
both parser and pretty-printer, for free.
The package is heavily inspired by the paper
[Invertible syntax descriptions: Unifying parsing and pretty printing]
(http://www.informatik.uni-marburg.de/~rendel/unparse/) and a similar
implementation of invertible grammar approach for JSON, library by
Martijn van Steenbergen called
[JsonGrammar2](https://github.com/MedeaMelana/JsonGrammar2).
Let's take a look at example:
```haskell
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 proprety
```
So now we can use `personGrammar` to parse S-expessions to `Person`
record and pretty-print any `Person` back to S-expression:
```haskell
ghci> :m Control.Category Language.SexpGrammar
ghci> parseFromString personGrammar <$> getLine
(person "John Doe" :address "42 Whatever str." :age 25)
Right (Person {pName = "John Doe", pAddress = "42 Whatever str.", pAge = Just 25})
ghci> let (Right person) = it
ghci> prettyToText personGrammar person
(person
"John Doe"
:address
"42 Whatever str."
:age
25)
```
The grammars are described in terms of isomorphisms and stack
manipulations.
The simplest primitive grammars are atom grammars, which match `Sexp`
atoms with Haskell counterparts:
```haskell
-- grammar type | consumes | produces
-- --------------------------+--------------+-------------------
bool :: SexpG Bool -- or Grammar SexpGrammar (Sexp :- t) (Bool :- t)
integer :: SexpG Integer -- or Grammar SexpGrammar (Sexp :- t) (Integer :- t)
int :: SexpG Int -- or Grammar SexpGrammar (Sexp :- t) (Int :- t)
real :: SexpG Scientific -- or Grammar SexpGrammar (Sexp :- t) (Scientific :- t)
double :: SexpG Double -- or Grammar SexpGrammar (Sexp :- t) (Double :- t)
string :: SexpG Text -- or Grammar SexpGrammar (Sexp :- t) (Text :- t)
string' :: SexpG String -- or Grammar SexpGrammar (Sexp :- t) (String :- t)
symbol :: SexpG Text -- or Grammar SexpGrammar (Sexp :- t) (Text :- t)
symbol' :: SexpG String -- or Grammar SexpGrammar (Sexp :- t) (String :- t)
keyword :: SexpG Kw -- or Grammar SexpGrammar (Sexp :- t) (Kw :- t)
sym :: Text -> SexpG_ -- or Grammar SexpGrammar (Sexp :- t) t
kw :: Kw -> SexpG_ -- or Grammar SexpGrammar (Sexp :- t) t
```
Grammars matching lists and vectors can be defined using an auxiliary
grammar type `SeqGrammar`. The following primitives embed
`SeqGrammar`s into main `SexpGrammar` context:
```haskell
list :: Grammar SeqGrammar t t' -> Grammar SexpGrammar (Sexp :- t) t'
vect :: Grammar SeqGrammar t t' -> Grammar SexpGrammar (Sexp :- t) t'
```
Grammar type `SeqGrammar` basically describes the sequence of elements
in a `Sexp` list (or vector). Single element grammar is defined with
`el`, "match rest of the sequence as list" grammar could be defined
with `rest` combinator. If the rest of the sequence is a property
list, `props` combinator should be used.
```haskell
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
```
`props` combinator embeds properties grammar `PropGrammar` into a
`SeqGrammar` context. `PropGrammar` describes what keys and values to
match.
```haskell
(.:) :: 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)
```
Please refer to Haddock on [Hackage](http://hackage.haskell.org/package/sexp-grammar)
for API documentation.
Diagram of grammar contexts:
```
--------------------------------------
| AtomGrammar |
--------------------------------------
^
| atomic grammar combinators
v
------------------------------------------------------
| SexpGrammar |
------------------------------------------------------
| list, vect ^ ^
v | el, rest |
---------------------------------- |
| SeqGrammar | |
---------------------------------- | (.:)
| props | (.:?)
v |
-------------------------------------
| PropGrammar |
-------------------------------------
```