(def match-json-string (j)
(if (is car.j #\")
(let (j a)
((afn (j a)
(if no.j (err "missing close quote"))
(if (is car.j #\")
(list cdr.j a)
(iflet (j c) (match-json-backslash j)
(self j (cons c a))
(self (cdr j) (cons (car j) a)))))
cdr.j nil)
(list j (coerce rev.a 'string)))))
this takes a list of characters, and either returns nil if it is passed something that doesn't start with a quote: ; 30
(match-json-string '(#\3 #\0))
nil
or it returns a two element list, the remainder of the input and the parsed string: ; "AB\u0043",3
(match-json-string '(#\" #\A #\B #\\ #\u #\0 #\0 #\4 #\3 #\" #\, #\3))
((#\, #\3) "ABC")
What the function does is pretty simple: if you see a "
scan through the input
error if no more input (missing close quote)
see another ", you're done, return the accumulated result
see a \, push the parsed backslash sequence onto the
accumulated result and continue
see any other char, push the char onto the accumulated
result and continue
But I haven't been able to figure out how to make the code simpler.I'm aware of the parser combinator library in Anarki, and I was able to get it to match things, but I wasn't able to figure out how to accumulate and return results with it. If you'd like to run it, here's the rest of the code, which implements the match-json-backslash called by the function... (def hexdigit (c)
(or (<= #\a c #\f) (<= #\A c #\F) digit.c))
(def json-unicode-digits (j)
(let u (firstn 4 j)
(unless (and (is (len u) 4) (all hexdigit u)) (err "need 4 hexadecimal digits after \\u"))
(coerce (int (coerce u 'string) 16) 'char)))
(def match-char (j c next)
(if (is car.j c)
(next cdr.j)))
(def match-json-unicode-escape (j)
(match-char j #\u
(fn (j)
(list (nthcdr 4 j) (json-unicode-digits j)))))
(def json-backslash-char (c)
(case c
#\" #\"
#\\ #\\
#\/ #\/
#\b #\backspace
#\f #\page
#\n #\newline
#\r #\return
#\t #\tab
(err "invalid JSON backslash char" c)))
(def match-json-backslash (j)
(match-char j #\\
(fn (j)
(if no.j (err "missing char after backslash"))
(or match-json-unicode-escape.j
(list cdr.j (json-backslash-char car.j))))))
|