(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)))