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 |
|