77 lines
2.2 KiB
Common Lisp
77 lines
2.2 KiB
Common Lisp
|
|
|
|
(in-package #:quasiquote-2.0)
|
|
|
|
(defun read-n-chars (stream char)
|
|
(let (new-char
|
|
(n 0))
|
|
(loop
|
|
(setf new-char (read-char stream nil :eof t))
|
|
(if (not (char= new-char char))
|
|
(progn (unread-char new-char stream)
|
|
(return n))
|
|
(incf n)))))
|
|
|
|
(defmacro define-dig-reader (name symbol)
|
|
`(defun ,name (stream char)
|
|
(let ((depth (1+ (read-n-chars stream char))))
|
|
(if (equal 1 depth)
|
|
(list ',symbol (read stream t nil t))
|
|
(list ',symbol
|
|
depth
|
|
(read stream t nil t))))))
|
|
|
|
(define-dig-reader dig-reader dig)
|
|
(define-dig-reader odig-reader odig)
|
|
|
|
(defun expect-char (char stream)
|
|
(let ((new-char (read-char stream t nil t)))
|
|
(if (char= char new-char)
|
|
t
|
|
(unread-char new-char stream))))
|
|
|
|
(defun guess-injector-name (opaque-p macro-p all-p splicing-p)
|
|
(intern (concatenate 'string
|
|
(if opaque-p "O" "")
|
|
(if macro-p "MACRO-" "")
|
|
(if splicing-p "SPLICE" "INJECT")
|
|
(if all-p "-ALL" ""))
|
|
"QUASIQUOTE-2.0"))
|
|
|
|
(defun inject-reader (stream char)
|
|
(let ((anti-depth (1+ (read-n-chars stream char)))
|
|
(extended-syntax (expect-char #\! stream)))
|
|
(let ((injector-name (if (not extended-syntax)
|
|
(guess-injector-name nil nil nil (expect-char #\@ stream))
|
|
(guess-injector-name (expect-char #\o stream)
|
|
(expect-char #\m stream)
|
|
(expect-char #\a stream)
|
|
(expect-char #\@ stream)))))
|
|
`(,injector-name ,@(if (not (equal 1 anti-depth)) `(,anti-depth))
|
|
,(read stream t nil t)))))
|
|
|
|
|
|
|
|
(defvar *previous-readtables* nil)
|
|
|
|
(defun %enable-quasiquote-2.0 ()
|
|
(push *readtable*
|
|
*previous-readtables*)
|
|
(setq *readtable* (copy-readtable))
|
|
(set-macro-character #\` #'dig-reader)
|
|
(set-macro-character #\, #'inject-reader)
|
|
(values))
|
|
|
|
(defun %disable-quasiquote-2.0 ()
|
|
(if *previous-readtables*
|
|
(setf *readtable* (pop *previous-readtables*))
|
|
(setf *readtable* (copy-readtable nil)))
|
|
(values))
|
|
|
|
(defmacro enable-quasiquote-2.0 ()
|
|
`(eval-when (:compile-toplevel :load-toplevel :execute)
|
|
(%enable-quasiquote-2.0)))
|
|
(defmacro disable-quasiquote-2.0 ()
|
|
`(eval-when (:compile-toplevel :load-toplevel :execute)
|
|
(%disable-quasiquote-2.0)))
|
|
|