| 68 | 68 |
functions.
|
| 69 | 69 |
|
| 70 | 70 |
~~~~.haskell
|
| 71 | |
*Data.SCargot.General> decode spec "(a b)"
|
| 71 |
> decode spec "(a b)"
|
| 72 | 72 |
Right [SCons (SAtom "a") (SCons (SAtom "b") SNil)]
|
| 73 | |
*Data.SCargot.General> decode (asRich spec) "(a b)"
|
| 73 |
> decode (asRich spec) "(a b)"
|
| 74 | 74 |
Right [RSList [RSAtom "a",RSAtom "b"]]
|
| 75 | |
*Data.SCargot.General> decode (asWellFormed spec) "(a b)"
|
| 75 |
> decode (asWellFormed spec) "(a b)"
|
| 76 | 76 |
Right [WFSList [WFSAtom "a",WFSAtom "b"]]
|
| 77 | |
*Data.SCargot.General> decode spec "(a . b)"
|
| 77 |
> decode spec "(a . b)"
|
| 78 | 78 |
Right [SCons (SAtom "a") (SAtom "b")]
|
| 79 | |
*Data.SCargot.General> decode (asRich spec) "(a . b)"
|
| 79 |
> decode (asRich spec) "(a . b)"
|
| 80 | 80 |
Right [RSDotted [RSAtom "a"] "b"]
|
| 81 | |
*Data.SCargot.General> decode (asWellFormed spec) "(a . b)"
|
| 81 |
> decode (asWellFormed spec) "(a . b)"
|
| 82 | 82 |
Left "Found atom in cdr position"
|
| 83 | 83 |
~~~~
|
| 84 | 84 |
|
|
| 90 | 90 |
you plan on working with:
|
| 91 | 91 |
|
| 92 | 92 |
~~~~.haskell
|
| 93 | |
*Data.SCargot.Repr.Basic> A 2 ::: A 3 ::: A 4 ::: Nil
|
| 93 |
> A 2 ::: A 3 ::: A 4 ::: Nil
|
| 94 | 94 |
SCons (SCons (SCons (SAtom 2) (SAtom 3)) (SAtom 4)) SNil
|
| 95 | 95 |
~~~~
|
| 96 | 96 |
|
| 97 | 97 |
~~~~.haskell
|
| 98 | |
*Data.SCargot.Repr.WellFormed> L [A 1,A 2,A 3]
|
| 98 |
> L [A 1,A 2,A 3]
|
| 99 | 99 |
WFSList [WFSAtom 1,WFSAtom 2,WFSAtom 3]
|
| 100 | |
*Data.SCargot.Repr.WellFormed> let sexprSum (L xs) = sum (map sexprSum xs); sexprSum (A n) = n
|
| 101 | |
*Data.SCargot.Repr Data.SCargot.Repr.WellFormed> :t sexprSum
|
| 100 |
> let sexprSum (L xs) = sum (map sexprSum xs); sexprSum (A n) = n
|
| 101 |
> :t sexprSum
|
| 102 | 102 |
sexprSum :: Num a => WellFormedSExpr a -> a
|
| 103 | |
*Data.SCargot.Repr.WellFormed> sexprSum (L [A 2, L [A 3, A 4]])
|
| 103 |
> sexprSum (L [A 2, L [A 3, A 4]])
|
| 104 | 104 |
9
|
| 105 | 105 |
~~~~
|
| 106 | 106 |
|
| 107 | 107 |
## Atom Types
|
| 108 | 108 |
|
| 109 | 109 |
Any type can serve as an underlying atom type provided that it has
|
| 110 | |
an AttoParsec parser and a serializer (i.e. a way of turning it
|
| 110 |
an Parsec parser and a serializer (i.e. a way of turning it
|
| 111 | 111 |
into `Text`.) For these examples, I'm going to use a very simple
|
| 112 | 112 |
serializer that is roughly like the one found in `Data.SCargot.Basic`,
|
| 113 | 113 |
which parses symbolic tokens of letters, numbers, and some
|
|
| 146 | 146 |
for both parsing and serialization:
|
| 147 | 147 |
|
| 148 | 148 |
~~~~.haskell
|
| 149 | |
*Data.SCargot.General T> decode mySpec "(foo 1)"
|
| 149 |
> decode mySpec "(foo 1)"
|
| 150 | 150 |
Right [SCons (SAtom (Ident "foo")) (SCons (SAtom (Num 1)) SNil)]
|
| 151 | |
*Data.SCargot.General T> encode mySpec [SCons (SAtom (Num 0)) SNil]
|
| 151 |
> encode mySpec [SCons (SAtom (Num 0)) SNil]
|
| 152 | 152 |
"(0)"
|
| 153 | 153 |
~~~~
|
| 154 | 154 |
|
|
| 187 | 187 |
the `SExprSpec`:
|
| 188 | 188 |
|
| 189 | 189 |
~~~~.haskell
|
| 190 | |
*Data.SCargot.General T> decode (convertSpec toExpr fromExpr (asRich spec)) "(+ 1 2)"
|
| 190 |
> decode (convertSpec toExpr fromExpr (asRich spec)) "(+ 1 2)"
|
| 191 | 191 |
Right [Add (Num 1) (Num 2)]
|
| 192 | |
*Data.SCargot.General T> decode (convertSpec toExpr fromExpr (asRich spec)) "(0 1 2)"
|
| 192 |
> decode (convertSpec toExpr fromExpr (asRich spec)) "(0 1 2)"
|
| 193 | 193 |
Left "Unrecognized s-expr"
|
| 194 | 194 |
~~~~
|
| 195 | 195 |
|
|
| 200 | 200 |
traditional Lisp line-oriented comments that begin with a semicolon:
|
| 201 | 201 |
|
| 202 | 202 |
~~~~.haskell
|
| 203 | |
*Data.SCargot.General> decode spec "(this ; has a comment\n inside)\n"
|
| 203 |
> decode spec "(this ; has a comment\n inside)\n"
|
| 204 | 204 |
Left "Failed reading: takeWhile1"
|
| 205 | |
*Data.SCargot.General> decode (withSemicolonComments spec) "(this ; has a comment\n inside)\n"
|
| 205 |
> decode (withSemicolonComments spec) "(this ; has a comment\n inside)\n"
|
| 206 | 206 |
Right [SCons (SAtom "this") (SCons (SAtom "inside") SNil)]
|
| 207 | 207 |
~~~~
|
| 208 | 208 |
|
| 209 | 209 |
Additionally, you can provide your own comment syntax in the form of an
|
| 210 | |
AttoParsec parser. Any AttoParsec parser can be used, so long as it meets
|
| 210 |
Parsec parser. Any Parsec parser can be used, so long as it meets
|
| 211 | 211 |
the following criteria:
|
| 212 | 212 |
- it is capable of failing (as is called until SCargot believes that there
|
| 213 | 213 |
are no more comments)
|
|
| 217 | 217 |
For example, the following adds C++-style comments to an S-expression format:
|
| 218 | 218 |
|
| 219 | 219 |
~~~~.haskell
|
| 220 | |
*Data.SCargot.General> let cppComment = string "//" >> takeWhile (/= '\n') >> return ()
|
| 221 | |
*Data.SCargot.General> decode (setComment cppComment spec) "(a //comment\n b)\n"
|
| 220 |
> let cppComment = string "//" >> takeWhile (/= '\n') >> return ()
|
| 221 |
> decode (setComment cppComment spec) "(a //comment\n b)\n"
|
| 222 | 222 |
Right [SCons (SAtom "a") (SCons (SAtom "b") SNil)]
|
| 223 | 223 |
~~~~
|
| 224 | 224 |
|
|
| 228 | 228 |
allows the _lexical_ syntax of a Lisp to be modified. The most commonly
|
| 229 | 229 |
seen reader macro is the quote, which allows the syntax `'expr` to stand
|
| 230 | 230 |
in for the s-expression `(quote expr)`. The S-Cargot library enables this
|
| 231 | |
by keeping a map of characters to AttoParsec parsers that can be used as
|
| 231 |
by keeping a map of characters to Parsec parsers that can be used as
|
| 232 | 232 |
readers. There is a special case for the aforementioned quote, but that
|
| 233 | 233 |
could easily be written by hand as
|
| 234 | 234 |
|
| 235 | 235 |
~~~~.haskell
|
| 236 | |
*Data.SCargot.General> let doQuote c = SCons (SAtom "quote") (SCons c SNil)
|
| 237 | |
*Data.SCargot.General> let qReader = addReader '\'' (\ p -> fmap doQuote p)
|
| 238 | |
*Data.SCargot.General> decode (qReader mySpec) "'foo"
|
| 236 |
> let quoteExpr c = SCons (SAtom "quote") (SCons c SNil)
|
| 237 |
> let withQuote = addReader '\'' (\ p -> fmap quoteExpr p)
|
| 238 |
> decode (withQuote mySpec) "'foo"
|
| 239 | 239 |
Right [SCons (SAtom "quote") (SCons (SAtom "foo") SNil)]
|
| 240 | 240 |
~~~~
|
| 241 | 241 |
|
|
| 246 | 246 |
parsing anything else and merely returns a new token:
|
| 247 | 247 |
|
| 248 | 248 |
~~~~.haskell
|
| 249 | |
*Data.SCargot.General> let qmReader = addReader '?' (\ _ -> pure (SAtom "huh"))
|
| 250 | |
*Data.SCargot.General> decode (qmReader mySpec) "(?1 2)"
|
| 249 |
> let qmReader = addReader '?' (\ _ -> pure (SAtom "huh"))
|
| 250 |
> decode (qmReader mySpec) "(?1 2)"
|
| 251 | 251 |
Right [SCons (SAtom "huh") (SCons (SAtom "1") (SCons (SAtom "2") SNil))]
|
| 252 | 252 |
~~~~
|
| 253 | 253 |
|
|
| 259 | 259 |
is reached:
|
| 260 | 260 |
|
| 261 | 261 |
~~~~.haskell
|
| 262 | |
*Data.SCargot.General> let pVec p = (char ']' *> pure SNil) <|> (SCons <$> p <*> pVec p)
|
| 263 | |
*Data.SCargot.General> let vec = addReader '[' pVec
|
| 264 | |
*Data.SCargot.General> decode (asRich (vec mySpec)) "(1 [2 3])"
|
| 262 |
> let pVec p = (char ']' *> pure SNil) <|> (SCons <$> p <*> pVec p)
|
| 263 |
> let vec = addReader '[' pVec
|
| 264 |
> decode (asRich (vec mySpec)) "(1 [2 3])"
|
| 265 | 265 |
Right [RSList [RSAtom "1",RSList [RSAtom "2",RSAtom "3"]]]
|
| 266 | 266 |
~~~~
|
| 267 | 267 |
|