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