Refactor discarding into its own file
author |
Steve Losh <steve@stevelosh.com> |
date |
Fri, 14 Aug 2020 22:56:53 -0400 |
parents |
(none) |
children |
(none) |
(in-package :jarl)
;; Optimized reader for cases where you don't actually care about the value and
;; just need to parse over it without allocating anything.
(defun discard-literal (string input)
(loop :for next :across string
:for char = (r input)
:unless (eql next char)
:do (e nil input "expected ~S when parsing ~S but got ~S" next string char)))
(defun discard-array (input)
(r input) ; [
(incf-depth input)
(skip-whitespace input)
(if (eql (p input) #\])
(progn (decf-depth input)
(r input))
(loop (discard-any input)
(skip-whitespace input)
(let ((ch (r input)))
(case ch
(#\] (decf-depth input) (return))
(#\, (skip-whitespace input))
(t (e nil input "expected ~S or ~S but got ~S." #\] #\, ch)))))))
(defun discard-object (input)
(r input) ; {
(incf-depth input)
(skip-whitespace input)
(if (eql (p input) #\})
(progn (decf-depth input)
(r input))
(loop (discard-string input)
(parse-kv-separator nil input)
(discard-any input)
(skip-whitespace input)
(let ((ch (r input)))
(case ch
(#\} (decf-depth input) (return))
(#\, (skip-whitespace input))
(t (e nil input "expected ~S or ~S but got ~S" #\} #\, ch)))))))
(defun discard-string (input)
(let ((ch (r input)))
(unless (eql ch #\")
(e nil input "expected opening ~S but got ~S" #\" ch)))
(loop :for ch = (r input)
:do (cond
((eql ch :eof) (e nil input "got ~S" :eof))
((eql ch #\\) (parse-escaped-character input)) ; TODO: Optimize this too.
((eql ch #\") (return))
((requires-escape-p ch) (e nil input "bad unescaped character ~S" ch))
(t nil))))
(defun discard-number (input)
;; TODO: Optimize this too. Not a huge priority since fixnums don't cons.
(parse-number input))
(defun discard-any (input)
(case (p input)
(:eof (r input) (e nil input "got ~S" :eof))
(#\n (discard-literal "null" input))
(#\t (discard-literal "true" input))
(#\f (discard-literal "false" input))
(#\" (discard-string input))
(#\{ (discard-object input))
(#\[ (discard-array input))
((#\- #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) (discard-number input))
(t (e nil input "unexpected character ~S" (r input)))))
(defmethod read% ((class (eql 'nil)) contained-class input)
(skip-whitespace input)
(discard-any input)
(values))