Refactor discarding into its own file
author |
Steve Losh <steve@stevelosh.com> |
date |
Fri, 14 Aug 2020 22:56:53 -0400 |
parents |
56f93a6f58b4
|
children |
6d9143f80df3
|
branches/tags |
(none) |
files |
jarl.asd src/basic.lisp src/discard.lisp |
Changes
--- 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")))))
--- 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
--- /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))