# HG changeset patch # User Steve Losh # Date 1597460213 14400 # Node ID 37cd2173940ef1d2618dbe41c90041e471658f19 # Parent 56f93a6f58b4856265014affa91372d2065809ff Refactor discarding into its own file diff -r 56f93a6f58b4 -r 37cd2173940e jarl.asd --- a/jarl.asd Fri Aug 14 00:40:27 2020 -0400 +++ b/jarl.asd Fri Aug 14 22:56:53 2020 -0400 @@ -14,6 +14,7 @@ :components ((:module "src" :serial t :components ((:file "package") (:file "basic") + (:file "discard") (:file "mop"))))) diff -r 56f93a6f58b4 -r 37cd2173940e src/basic.lisp --- a/src/basic.lisp Fri Aug 14 00:40:27 2020 -0400 +++ b/src/basic.lisp Fri Aug 14 22:56:53 2020 -0400 @@ -225,76 +225,6 @@ (defgeneric read% (class contained-class input)) -(defmethod read% ((class (eql 'nil)) contained-class input) - ;; Optimized reader for cases where you don't actually care about the value - ;; and just need to parse over it without allocating anything. - (labels - ((any% () - (case (p input) - (:eof (r input) (e nil input "got ~S" :eof)) - (#\n (literal% "null")) - (#\t (literal% "true")) - (#\f (literal% "false")) - (#\" (string%)) - (#\{ (object%)) - (#\[ (array%)) - ((#\- #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) (number%)) - (t (e nil input "unexpected character ~S" (r input))))) - (literal% (string) - (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))) - (array% () - (r input) ; [ - (incf-depth input) - (skip-whitespace input) - (if (eql (p input) #\]) - (progn (decf-depth input) - (r input)) - (loop (any%) - (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))))))) - (object% () - (r input) ; { - (incf-depth input) - (skip-whitespace input) - (if (eql (p input) #\}) - (progn - (decf-depth input) - (r input)) - (loop - (string%) - (parse-kv-separator nil input) - (any%) - (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))))))) - (number% () - ;; TODO: Optimize this too. Not a huge priority since fixnums don't cons. - (parse-number input)) - (string% () - (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))))) - (skip-whitespace input) - (any%) - (values))) - (defmethod read% ((class (eql 'keyword)) contained-class input) (let ((ch (r input))) (case ch diff -r 56f93a6f58b4 -r 37cd2173940e src/discard.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/discard.lisp Fri Aug 14 22:56:53 2020 -0400 @@ -0,0 +1,76 @@ +(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))