-;;; notmuch-parser.el --- streaming S-expression parser
+;;; notmuch-parser.el --- streaming S-expression parser -*- lexical-binding: t -*-
;;
;; Copyright © Austin Clements
;;
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
-;; along with Notmuch. If not, see <http://www.gnu.org/licenses/>.
+;; along with Notmuch. If not, see <https://www.gnu.org/licenses/>.
;;
;; Authors: Austin Clements <aclements@csail.mit.edu>
;;; Code:
-(require 'cl)
+(require 'cl-lib)
+(require 'pcase)
+(require 'subr-x)
(defun notmuch-sexp-create-parser ()
"Return a new streaming S-expression parser.
The parser always consumes input from point in the current
buffer. Hence, the caller is allowed to delete any data before
point and may resynchronize after an error by moving point."
-
(vector 'notmuch-sexp-parser
- ;; List depth
- 0
- ;; Partial parse position marker
- nil
- ;; Partial parse state
- nil))
+ 0 ; List depth
+ nil ; Partial parse position marker
+ nil)) ; Partial parse state
(defmacro notmuch-sexp--depth (sp) `(aref ,sp 1))
(defmacro notmuch-sexp--partial-pos (sp) `(aref ,sp 2))
list, this moves point just past the terminator and returns 'end.
Otherwise, this moves point to just past the end of the value and
returns the value."
-
(skip-chars-forward " \n\r\t")
(cond ((eobp) 'retry)
((= (char-after) ?\))
;; error to be consistent with all other code paths.
(read (current-buffer))
;; Go up a level and return an end token
- (decf (notmuch-sexp--depth sp))
+ (cl-decf (notmuch-sexp--depth sp))
(forward-char)
'end))
((= (char-after) ?\()
;; parse, extend the partial parse to figure out when we
;; have a complete list.
(catch 'return
- (when (null (notmuch-sexp--partial-state sp))
+ (unless (notmuch-sexp--partial-state sp)
(let ((start (point)))
(condition-case nil
(throw 'return (read (current-buffer)))
(notmuch-sexp--partial-state sp)))
;; A complete value is available if we've
;; reached depth 0.
- (depth (first new-state)))
- (assert (>= depth 0))
+ (depth (car new-state)))
+ (cl-assert (>= depth 0))
(if (= depth 0)
;; Reset partial parse state
(setf (notmuch-sexp--partial-state sp) nil
returns t. Later calls to `notmuch-sexp-read' will return the
elements inside the list. If the input in buffer is not the
beginning of a list, throw invalid-read-syntax."
-
(skip-chars-forward " \n\r\t")
(cond ((eobp) 'retry)
((= (char-after) ?\()
(forward-char)
- (incf (notmuch-sexp--depth sp))
+ (cl-incf (notmuch-sexp--depth sp))
t)
(t
;; Skip over the bad character like `read' does
(forward-char)
(signal 'invalid-read-syntax (list (string (char-before)))))))
-(defun notmuch-sexp-eof (sp)
- "Signal an error if there is more data in SP's buffer.
-
-Moves point to the beginning of any trailing data or to the end
-of the buffer if there is only trailing whitespace."
-
- (skip-chars-forward " \n\r\t")
- (unless (eobp)
- (error "Trailing garbage following expression")))
-
(defvar notmuch-sexp--parser nil
"The buffer-local notmuch-sexp-parser instance.
be called whenever the input buffer has been extended with
additional data. The caller just needs to ensure it does not
move point in the input buffer."
-
;; Set up the initial state
(unless (local-variable-p 'notmuch-sexp--parser)
- (set (make-local-variable 'notmuch-sexp--parser)
- (notmuch-sexp-create-parser))
- (set (make-local-variable 'notmuch-sexp--state) 'begin))
+ (setq-local notmuch-sexp--parser (notmuch-sexp-create-parser))
+ (setq-local notmuch-sexp--state 'begin))
(let (done)
(while (not done)
- (case notmuch-sexp--state
+ (cl-case notmuch-sexp--state
(begin
;; Enter the list
(if (eq (notmuch-sexp-begin-list notmuch-sexp--parser) 'retry)
(result
;; Parse a result
(let ((result (notmuch-sexp-read notmuch-sexp--parser)))
- (case result
+ (cl-case result
(retry (setq done t))
(end (setq notmuch-sexp--state 'end))
(t (with-current-buffer result-buffer
(funcall result-function result))))))
(end
- ;; Any trailing data is unexpected
- (notmuch-sexp-eof notmuch-sexp--parser)
+ ;; Skip over trailing whitespace.
+ (skip-chars-forward " \n\r\t")
+ ;; Any trailing data is unexpected.
+ (unless (eobp)
+ (error "Trailing garbage following expression"))
(setq done t)))))
;; Clear out what we've parsed
(delete-region (point-min) (point)))
(provide 'notmuch-parser)
-;; Local Variables:
-;; byte-compile-warnings: (not cl-functions)
-;; End:
-
;;; notmuch-parser.el ends here