Mark fare-matcher as replaced by optima.
authorFrancois-Rene Rideau <tunes@google.com>
Sat, 3 Nov 2012 16:52:17 +0000 (12:52 -0400)
committerFrancois-Rene Rideau <tunes@google.com>
Sat, 3 Nov 2012 16:52:17 +0000 (12:52 -0400)
Split fare-quasiquote from fare-matcher.

README [new file with mode: 0644]
README.quasiquote [deleted file]
build.xcvb
fare-matcher.asd
fare-quasiquote-readtable.asd [deleted file]
packages.lisp
pp-quasiquote.lisp [deleted file]
quasiquote-readtable.lisp [deleted file]
quasiquote.lisp [deleted file]

diff --git a/README b/README
new file mode 100644 (file)
index 0000000..3defce0
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+I've decided to consolidate pattern matching libraries.
+Optima is a much better library than fare-matcher,
+which was a proof of concept, really.
+
+I'll be working with the authors of Optima to make sure
+that optima is superior in every possible aspect to fare-matcher,
+and will recommend users who use fare-matcher to migrate to optima.
+
+https://github.com/m2ym/optima
+
+See you there soon!
+
+Faré, 2012-10-24
diff --git a/README.quasiquote b/README.quasiquote
deleted file mode 100644 (file)
index c3d8b29..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-fare-matcher friendly implementation of Quasiquote
-Copyright (c) 2002-2010 Fahree Reedaw <fare@tunes.org>
-
-
-PURPOSE
-
-The main purpose of this n+2nd reimplementation of quasiquote,
-is enable matching of quasiquoted patterns with fare-matcher.
-
-Now, developing this implementation is also a challenge in understanding
-the ins and outs of quasiquotation, and in exploring the way it interacts
-with extended support for constant-building syntactic constructs.
-And this, at least to me is as much fun as it is an intellectual challenge. :-)
-
-
-INTERACTION WITH FARE-MATCHER
-
-This implementation of quasiquote requires the FARE-MATCHER system.
-
-It enables quasiquotation inside FARE-MATCHER patterns.
-However, as a limitation to such use, note that as long as
-the pattern-matcher isn't extended to match APPEND patterns,
-which typically requires backtracking, then those quasiquote templates
-that expand into something using APPEND can't be used as patterns to match.
-This mostly restricts the use of ,@ or ,. to the end of a list.
-
-This implementation also uses FARE-MATCHER internally,
-which allows to tremendously simplify the simplifier
-used to normalize quasiquote-using expressions.
-This simplifier in turn is necessary to simplify APPEND patterns
-into CONS LIST* and LIST patterns for use with FARE-MATCHER.
-
-
-REFERENCES
-
-Essential documents consulted while implementing this file:
-Alan Bawden's paper: http://www.bawden.org/ftp/pepm99.ps.gz
-CLtL2: http://www.supelec.fr/docs/cltl/clm/node367.html
-CLHS: http://www.lisp.org/HyperSpec/Body/sec_2-4-6.html
-Slate reference manual section 2.6.2 on quoting and unquoting:
-    http://slate.tunes.org/doc/progman/node12.html#SECTION00046200000000000000
-Common Lisp backquote implementation, written in Common Lisp. (public domain)
-  Author: Guy L. Steele Jr.     Date: 27 December 1985
-  To be used with patch by Alex Plotnick 2010 regarding the simplification pass.
-SBCL backquote implementation (derived from CMUCL).
-
-
-NOTES
-
-* We provide for a read-time quasiquote expander as well as
- a macro-expansion-time quasiquote expander.
- The read-time expander handles #() syntax correctly
- but mightn't be as efficient as the built-in reader in the common case,
- whereas the macro-expansion-time sees #() too late (see BUGS).
- To use the macro-expansion-time one, uncomment the line that declares
- feature :quasiquote-at-macro-expansion-time.
-
-
-TO DO
-
-* The CLHS doesn't tell anything about multi-dimensional arrays;
- however, this is the opportunity to define a MUP: Meta Unquote Protocol.
- The MUP would allow to extend the quasiquote mechanism with support
- for new constant-building syntactic constructs as such constructs are defined.
- Maybe we will end up with a full-fledge declarative infrastructure
- for a Parser-Preprocessor-Pretty-Printer, like camlp4 only more declarative.
-
-* Can we improve performance?
- Statically compile and optimize the patterns for the simplifier?
-
-* Implement the MUP with an abstract API for new readers;
- as examples, provide readers for existing syntax that can be toggled
- as either unquote-aware or not: #(), #A, etc.
-
-* Implement tagged (and multiple-valued?) quasiquotes, unquotes and quotes.
-
-
-BUGS:
-
-* It looks like there are nasty bugs in the simplifier.
- Maybe start again afresh with a MUP for CONS?
- We should start from the known-working algorithm described in CLtL2,
- that keeps the data in simplified form at all time incrementally,
- instead of trying a global simplification after-the-fact.
-
-* This version works inside simple vectors, so as to support
- unquoting inside the #(...) syntax as the standard mandates.
- However, doing that at macro-expansion time means that we disturb
- any SIMPLE-VECTOR that appears in the source code, even if it comes
- from forms other than #(...), such as #1A(...) or #.(VECTOR ...).
- This phenomenon has been documented before in the following message:
-       http://groups.google.com/groups?q=author:kaz%40ashi.footprints.net&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=cf333042.0303141409.bbf02e9%40posting.google.com&rnum=4
-
-* Interestingly, I haven't seen the following problem stated, to know which is
- correct of `#2(1 ,@'(2 3)) or `#3(1 ,@'(2 3)). In other words, does the read
- argument to #() mean something at read-time or at vector-creation-time?
- Of course, in the original intended usage, outside of any quasiquoting,
- read-time and vector-creation-time are one and the same.
- But what when quasiquote breaks up that identity?
-
-* Note that we do not handle unquoting inside structures
- or arrays more complex than simple vectors.
-
-* Note that in the case of the macro-expansion-time expander,
- we do not check for lone unquote syntax before macro expansion,
- which may lead this implementation to accept hacks
- that are not valid according to the standard, such as
- macros that produce unbalanced unquote syntax markers.
-
-* Certainly, the implementation of quasiquote should be "opened"
- so as to allow new syntactic features to take advantage of it.
- Then, maybe we can redefine our own proper reader behaviour for #(...)
- and each MUP-supporting piece of syntax, on top of the MUP?
-
- Note that copying and modifying read-tables is expensive, that dynamically
- modifying and restoring read-tables might interfere with #. syntax, and that
- caching modified read-tables will interfere with any subsequent modification
- of a cached read-table, comparison not being possible.
- This means that if we wanted the MUP to adapt to existing extensions
- without modifying existing code, we would have to intercept the definition
- of syntax reading functions before they are fed to either SET-MACRO-CHARACTER
- or SET-DISPATCH-MACRO-CHARACTER. Spooky.
- Now, this also requires that the current depth of quasiquoting be consulted
- any time any of the MUP-enabled constructors is read.
-
-* The principle of the MUP is that
- = structure readers that don't want to support unquote MUST be wrapped into
-  something that dynamically binds *quasiquote-level* to 0.
- = structure readers #C(ARGSYNTAX) that do want to support unquote
-  MUST accumulate formal arguments to a structure constructor
-  into a list ARGUMENTS, then, if *quasiquote-level* is 0, behave like
-  #.(apply `#CONSTRUCTOR `#ARGUMENTS)
-  otherwise, behave like
-  ,(apply `#CONSTRUCTOR `#ARGUMENTS)
-  where #CONSTRUCTOR is the name of the constructor for given structure,
-  and #ARGUMENTS is whichever arguments have been deduced from the syntax,
-  which may include as many levels of unquotations as *quasiquote-level* says.
-  Note that in a strong sense, "#." is like "," assuming an infinite tower of
-  read-time evaluators a la 3-LISP.
-
-* Note that the above is obscured because we're trying to discuss
- the behaviour of quasiquote-containing programs without having
- a meta-level quasiquoting facility that could distinguish
- between what is constant or variable at the meta-level independently from
-  what is constant or variable at the base level:
- #CONSTRUCTOR and #ARGUMENTS would be better specified
- through a special meta-level unquotation, the above expressions
- being in a corresponding special quasiquotation.
- A feature that would allow for clear separation of levels of meta-language
- would be a tagged quasiquote feature, as in Slate (http://slate-language.org/).
-
-* This version is not safe with respect to quasiquoting expressions
- where appear some marker symbols interned in the FARE-QUASIQUOTE package --
- such expressions may lead to confusion between the body of expressions
- being quasiquoted and the internal quasiquote infrastructure.
- Any objects used as markers instead of these interned symbols
- would lead to the same "bug" if somehow used inside quasiquoted expressions;
- but at least, non-interned symbols or gensyms would allow to avoid this bug
- in expressions being READ. The "perfect" solution would be to use
- objects GENSYMed at the moment a given QUASIQUOTE is read,
- and kept in a lexical variable to prevent introspective cheat by #. syntax.
- Then, after simplifying expressions, we could pass the read expression
- through functions that would SUBSTitute proper symbols for the markers,
- from the quasiquote package if pretty-printing is to be supported,
- or otherwise from the CL package.
- Note that this would have to be interleaved with support for working
- inside vectors and other syntax. This is all very tricky
- and until further notice is left as an exercise to the intrepid reader.
- Thus, while the behaviour of our implementation isn't strictly correct,
- we don't go through the hassle of modifying it into something
- much less readable just for the sake of preventing code that would
- deliberately confuse the quasiquote engine.
- Now, if we imagine that some code were dynamically generated
- based on system introspection, that could contain some of our magic markers,
- then this code would have to be made safe for interaction with QUASIQUOTE;
- this might (or might not?) require making QUASIQUOTE 100% fool-proof.
-
-* This implementation simplifies quasiquoting of literals
- and other self-evaluating objects into the object itself,
- instead of a `(QUOTE ,object) expression.
- This is also the behaviour of the simplifier in CMUCL and SBCL,
- but some people have expressed concerns that it might not be
- strictly allowed in letter or spirit by the Common Lisp standards.
- We believe that our behaviour is correct in both letter and spirit;
- but in any case, a more literally correct (pun intended) behaviour
- with respect to the CL standards can be achieved by defining
- the feature QUASIQUOTE-QUOTES-LITERALS (untested).
-
-* The idea of making circular data-structures work within quasiquotation
- makes my head ache with overarching pain. I make no attempt to try that,
- and most conspicuously not in the simplifier. You're crazier than I am
- if you do it and do it right.
-
-PS: If you're able to follow this discussion, you impress me.
-Come join the TUNES project!
-
index 31824be..f725481 100644 (file)
@@ -3,7 +3,6 @@
  (:fullname "fare-matcher"
   :depends-on
   ("packages" "matcher"
-   "quasiquote" "pp-quasiquote" "quasiquote-readtable"
    "clos-match" "mrd-extensions")
   :build-depends-on ("/xcvb/xcvb-utils")
-  :supersedes-asdf ("fare-matcher" "fare-quasiquote-readtable")))
+  :supersedes-asdf ("fare-matcher")))
index d7112b2..2f2c3fe 100644 (file)
@@ -9,9 +9,6 @@ and to define your own extensions."
   :components
   ((:file "packages")
    (:file "matcher")
-   #-gcl ; it currently fails. quasiquote necessitates a big revamp anyway
-   (:file "quasiquote")
-   (:file "pp-quasiquote")
    ;;#-gcl ; 2.7.0-64.1 cannot defgeneric in a eval-now
    (:file "clos-match")
    (:file "mrd-extensions")))
diff --git a/fare-quasiquote-readtable.asd b/fare-quasiquote-readtable.asd
deleted file mode 100644 (file)
index f7a0be0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-;;; -*- Lisp -*-
-
-(asdf:defsystem :fare-quasiquote-readtable
-  :depends-on (:named-readtables :fare-matcher)
-  :components ((:file "quasiquote-readtable")))
index 6a4409d..5cd4a36 100644 (file)
    "Lisp2-style Erlang/ML-like Pattern-Matcher for Common LISP")
   (:export))
 
-(defpackage #:fare-quasiquote
-  (:use #:fare-matcher #:fare-utils #:common-lisp)
-  (:shadow #:list #:append #:nconc #:list* #:cons #:quote
-           #:kwote #:quotep #:vector #:make-vector)
-  (:documentation
-   "Quasiquote implementation with and for pattern-matching")
-  (:export #:quasiquote-expand #:quasiquote #:unquote #:unquote-splicing
-          #:enable-quasiquote
-           #:call-with-quasiquote-reader
-           #:call-with-unquote-reader
-           #:call-with-unquote-splicing-reader
-           #:call-with-unquote-nsplicing-reader))
-
 (defpackage #:fare-clos-match
   #+openmcl (:shadowing-import-from #:ccl #:quit)
   (:use #:common-lisp #:fare-utils #:fare-matcher
diff --git a/pp-quasiquote.lisp b/pp-quasiquote.lisp
deleted file mode 100644 (file)
index 1fa0de2..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-;;;; pretty-printing of backquote expansions
-
-#+xcvb (module (:depends-on ("quasiquote")))
-
-;;;; This software is derived from the CMU CL system via SBCL.
-;;;; CMU CL was written at Carnegie Mellon University and released into
-;;;; the public domain. The software is in the public domain and is
-;;;; provided with absolutely no warranty.
-
-(in-package :fare-quasiquote)
-
-(defun unparse-quasiquote-1 (form splicing)
-  (ecase splicing
-    ((nil)
-     (list 'unquote form))
-    (:append
-     (list (list 'unquote-splicing form)))
-    (:nconc
-     (list (list 'unquote-nsplicing form)))))
-
-(defun unparse-quasiquote (form &optional splicing)
-  "Given a lisp form containing the magic functions LIST, LIST*,
-  APPEND, etc. produced by the backquote reader macro, will return a
-  corresponding backquote input form. In this form, `,' `,@' and `,.' are
-  represented by lists whose cars are UNQUOTE, UNQUOTE-SPLICING, and
-  UNQUOTE-NSPLICING respectively, and whose cadrs are the form after the comma.
-  SPLICING indicates whether a comma-escape return should be modified for
-  splicing with other forms: a value of :APPEND or :NCONC meaning that an extra
-  level of parentheses should be added."
-  (cond
-   ((atom form)
-    (unparse-quasiquote-1 form splicing))
-   ((not (null (cdr (last form))))
-    ;; FIXME: this probably throws a recursive error
-    (error "found illegal dotted quasiquote form: ~S" form))
-   (t
-    (case (car form)
-      ((list cl:list)
-       (mapcar #'unparse-quasiquote (cdr form)))
-      ((list* cl:list*)
-       (do ((tail (cdr form) (cdr tail))
-            (accum nil))
-           ((null (cdr tail))
-            (nconc (nreverse accum)
-                   (unparse-quasiquote (car tail) :append)))
-         (push (unparse-quasiquote (car tail)) accum)))
-      ((append cl:append)
-       (apply #'cl:append
-              (mapcar (lambda (el) (unparse-quasiquote el :append))
-                      (cdr form))))
-      ((nconc cl:nconc)
-       (apply #'cl:append
-              (mapcar (lambda (el) (unparse-quasiquote el :nconc))
-                      (cdr form))))
-      ((cons cl:cons)
-       (cl:cons (unparse-quasiquote (cadr form) nil)
-                (unparse-quasiquote (caddr form) :append)))
-      ((vector cl:vector)
-       (coerce (unparse-quasiquote (cadr form)) 'cl:vector))
-      ((quote cl:quote)
-       (cond
-         ((atom (cadr form)) (cadr form))
-         ((and (consp (cadr form))
-               (member (caadr form) *quasiquote-tokens*))
-          (unparse-quasiquote-1 form splicing))
-         (t (cons (unparse-quasiquote (list 'cl:quote (caadr form)))
-                  (unparse-quasiquote (list 'cl:quote (cdadr form)))))))
-      (t
-       (unparse-quasiquote-1 form splicing))))))
-
-(defun pprint-quasiquote (stream form &rest noise)
-  (declare (ignore noise))
-  (write-char #\` stream)
-  (write (unparse-quasiquote form) :stream stream))
-
-(defun pprint-unquote (stream form &rest noise)
-  (declare (ignore noise))
-  (ecase (car form)
-    ((unquote)
-     (write-char #\, stream))
-    ((unquote-splicing)
-     (write-string ",@" stream))
-    ((unquote-nsplicing)
-     (write-string ",." stream)))
-  (let ((output (with-output-to-string (s)
-                  (write (cadr form) :stream s
-                         :level (min 1 (or *print-level* 1))
-                         :length (min 1 (or *print-length* 1))))))
-    (unless (= (length output) 0)
-      (when (and (eql (car form) 'unquote)
-                 (or (char= (char output 0) #\.)
-                     (char= (char output 0) #\@)))
-        (write-char #\Space stream))
-      (write (cadr form) :stream stream))))
-
-;;; This is called by !PPRINT-COLD-INIT, fairly late, because
-;;; SET-PPRINT-DISPATCH doesn't work until the compiler works.
-;;;
-;;; FIXME: It might be cleaner to just make these be toplevel forms and
-;;; enforce the delay by putting this file late in the build sequence.
-(defun !backq-pp-cold-init ()
-  (set-pprint-dispatch '(cons (eql list)) #'pprint-quasiquote)
-  (set-pprint-dispatch '(cons (eql list*)) #'pprint-quasiquote)
-  (set-pprint-dispatch '(cons (eql append)) #'pprint-quasiquote)
-  (set-pprint-dispatch '(cons (eql nconc)) #'pprint-quasiquote)
-  (set-pprint-dispatch '(cons (eql cons)) #'pprint-quasiquote)
-  (set-pprint-dispatch '(cons (eql vector)) #'pprint-quasiquote)
-
-  (set-pprint-dispatch '(cons (eql unquote)) #'pprint-unquote)
-  (set-pprint-dispatch '(cons (eql unquote-splicing)) #'pprint-unquote)
-  (set-pprint-dispatch '(cons (eql unquote-nsplicing)) #'pprint-unquote))
diff --git a/quasiquote-readtable.lisp b/quasiquote-readtable.lisp
deleted file mode 100644 (file)
index 495d055..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-;;; -*- Mode: Lisp ; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
-;;; named readtables for fare-quasiquote
-;;; Copyright (c) 2011-2011 Fahree Reedaw <fare@tunes.org>
-;;; See README.quasiquote
-
-#+xcvb (module (:depends-on ("quasiquote" (:asdf "named-readtables"))))
-
-(in-package :fare-quasiquote)
-
-(eval-now
-  (named-readtables:defreadtable :fare-quasiquote-mixin
-    (:macro-char #\` #'read-read-time-backquote)
-    (:macro-char #\, #'read-comma)
-    (:macro-char #\# :dispatch)
-    (:dispatch-macro-char #\# #\( #'read-hash-paren))
-
-  (named-readtables:defreadtable :fare-quasiquote
-    (:fuze :standard :fare-quasiquote-mixin)))
-
-;; (in-readtable :fare-quasiquote)
diff --git a/quasiquote.lisp b/quasiquote.lisp
deleted file mode 100644 (file)
index d0a36e2..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-;;; -*- Mode: Lisp ; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
-;;; fare-matcher friendly implementation of Quasiquote
-;;; Copyright (c) 2002-2011 Fahree Reedaw <fare@tunes.org>
-;;; See README.quasiquote
-
-#+xcvb (module (:depends-on ("packages" "matcher")))
-
-(in-package :fare-quasiquote)
-
-(declaim (optimize (speed 1) (safety 3) (debug 3)))
-
-(eval-when (:compile-toplevel :load-toplevel :execute)
-;;;; uncomment some of the lines below to disable according simplifications:
-;;(pushnew :quasiquote-quotes-literals *features*)
-;;(pushnew :quasiquote-at-macro-expansion-time *features*)
-
-;; the below instruction enables pattern-matching for the simplifier.
-(copy-function-matcher
- list  cl:list
- list* cl:list*
- cons  cl:cons
- quote cl:quote
- vector cl:vector)
-
-(defvar *quasiquote-tokens*
-  '(unquote unquote-splicing unquote-splicing
-    list list* append nconc cons vector n-vector knil))
-
-(make-single-arg-form quote kwote)
-(make-single-arg-form quasiquote)
-(make-single-arg-form unquote)
-(make-single-arg-form unquote-splicing)
-(make-single-arg-form unquote-nsplicing)
-(defun make-vector-form (&rest x) (list* 'vector x))
-(defun vector-form-p (x)
-  (and (listp x) #|(alexandria:proper-list-p x)|# (eq (car x) 'vector)))
-
-(defmacro quote (x) (list 'cl:quote x))
-(defmacro quasiquote (x) (quasiquote-expand x))
-(defmacro unquote (x)
-  (declare (ignore x))
-  (error "unquote only allowed within quasiquote"))
-(defmacro unquote-splicing (x)
-  (declare (ignore x))
-  (error "unquote-splicing disallowed outside quasiquote"))
-(defmacro unquote-nsplicing (x)
-  (declare (ignore x))
-  (error "unquote-nsplicing disallowed outside quasiquote"))
-
-(define-symbol-matcher knil
-  '#'(lambda (form)
-       (or (null form)
-          (and (quotep form) (null (single-arg form)))
-          (m%fail))))
-(defparameter knil
-  #+quasiquote-quotes-literals (kwote nil)
-  #-quasiquote-quotes-literals nil)
-
-(defparameter *quasiquote-level* 0
-  "current depth of quasiquote nesting")
-(defparameter *simplify* t
-  "should we simplify backquoted expressions")
-
-(defun unquote-xsplicing-p (x)
-  (or (unquote-splicing-p x) (unquote-nsplicing-p x)))
-
-(defun quasiquote-expand (x)
-  (let ((*quasiquote-level* 0))
-    (multiple-value-bind (top arg)
-        (quasiquote-expand-0 x)
-      (when (eq top 'unquote-splicing)
-        (error ",@ after backquote in ~S" x))
-      (when (eq top 'unquote-nsplicing)
-        (error ",. after backquote in ~S" x))
-      (quasiquote-expand-1 top arg))))
-
-(defun quasiquote-expand-0 (x)
-  "Given an expression x under a backquote, return two values:
-1- a token identifying a topmost function to apply on
-2- an argument
-When combining backquoted expressions, tokens are used for simplifications."
-  (cond
-   ((null x)
-    (values nil nil))
-   ((literalp x)
-    (values #+quasiquote-quotes-literals 'quote #-quasiquote-quotes-literals :literal x))
-   ((or (symbolp x) (quotep x))
-    (values 'quote x))
-   ((unquote-splicing-p x)
-    (values 'unquote-splicing (single-arg x)))
-   ((unquote-nsplicing-p x)
-    (values 'unquote-nsplicing (single-arg x)))
-   ((unquotep x)
-    (values 'unquote (single-arg x)))
-   ((vector-form-p x)
-    (multiple-value-bind (top contents) (quasiquote-expand-0 (cdr x))
-      (values 'vector (quasiquote-expand-1 top contents))))
-   ;;#+quasiquote-at-macro-expansion-time
-   ((simple-vector-p x)
-    (values 'vector (quasiquote-expand (coerce x 'cl:list))))
-   ((quasiquotep x)
-    ;; shouldn't be happening unless #+quasiquote-at-macro-expansion-time
-    (quasiquote-expand-0 (quasiquote-expand (single-arg x))))
-   ((consp x)
-    (multiple-value-bind (atop a) (quasiquote-expand-0 (car x))
-      (multiple-value-bind (dtop d) (quasiquote-expand-0 (cdr x))
-        (when (eq dtop 'unquote-splicing)
-          (error ",@ after dot"))
-        (when (eq dtop 'unquote-nsplicing)
-          (error ",. after dot"))
-        (cond
-          ((eq atop 'unquote-splicing)
-           (if (null dtop)
-               (if (unquote-xsplicing-p a)
-                   (values 'append (list a))
-                   (expand-unquote a))
-               (values 'append
-                       (cond ((eq dtop 'append)
-                              (cons a d))
-                             (t (list a (quasiquote-expand-1 dtop d)))))))
-          ((eq atop 'unquote-nsplicing)
-           (if (null dtop)
-               (if (unquote-xsplicing-p a)
-                   (values 'nconc (list a))
-                   (expand-unquote a))
-               (values 'nconc
-                       (cond ((eq dtop 'nconc)
-                              (cons a d))
-                             (t (list a (quasiquote-expand-1 dtop d)))))))
-          ((null dtop)
-           (if (member atop '(quote :literal nil))
-               (values 'quote (list a))
-               (values 'list (list (quasiquote-expand-1 atop a)))))
-          ((member dtop '(quote :literal))
-           (if (member atop '(quote :literal nil))
-               (values 'quote (cons a d))
-               (values 'list* (list (quasiquote-expand-1 atop a)
-                                    (quasiquote-expand-1 dtop d)))))
-          (t (let ((qa (quasiquote-expand-1 atop a)))
-               (if (member dtop '(list list*))
-                   (values dtop (cons qa d))
-                   (values 'list*
-                           (list qa (quasiquote-expand-1 dtop d))))))))))
-   (t
-    (error "unrecognized object in quasiquote"))))
-
-(defun expand-unquote (x)
-  (cond
-    ((null x)
-     (values nil nil))
-    ((literalp x)
-     (values :literal x))
-    ((symbolp x)
-     (values 'unquote x))
-    ((simple-vector-p x) ;; XXX - test this.
-     (values 'vector (quasiquote-expand (coerce x 'cl:list))))
-    ((not (consp x))
-     (error "unrecognized object in unquote"))
-    ((and (quotep x)
-          (not (unquote-xsplicing-p (single-arg x))))
-     (values 'quote (single-arg x)))
-    ((member (car x) '(append list list* nconc))
-     (values (car x) (cdr x)))
-    ((eq (car x) 'cons)
-     (values 'list* (cdr x)))
-    (t (values 'unquote x))))
-
-(defun quasiquote-expand-1 (top x)
-  "Given a top token and an expression, give the quasiquoting
-of the result of the top operation applied to the expression"
-  (cond
-    ((member top '(unquote :literal nil))
-     x)
-    ((eq top 'quote)
-     (kwote x))
-    ((eq top 'list*)
-     (cond ((and (null (cddr x))
-                 (not (unquote-xsplicing-p (car x)))
-                 (not (unquote-xsplicing-p (cadr x))))
-            (k-cons (car x) (cadr x)))
-           ((unquote-xsplicing-p (car (last x)))
-            (k-append
-             (apply 'k-list (butlast x))
-             (car (last x))))
-           (t
-            (apply 'k-list* x))))
-    ((eq top 'vector)
-     (k-vector x))
-    (t
-     (cons (ecase top
-             ((list) 'list)
-             ((append) 'append)
-             ((nconc) 'nconc))
-           x))))
-
-; we want our own tokens, but they must evaluate the usual way.
-(defsubst list (&rest r) (apply #'cl:list r))
-(defsubst append (&rest r) (apply #'cl:append r))
-(defsubst list* (&rest r) (apply #'cl:list* r))
-(defsubst nconc (&rest r) (apply #'cl:nconc r))
-(defsubst cons (x y) (cl:cons x y))
-(defsubst vector (&rest r) (apply #'cl:vector r))
-(defsubst make-vector (l) (coerce l 'simple-vector))
-(defsubst clobberable (x) x) ;; marks x as being unique and clobberable by nconc
-
-(defun k-vector (l) (list 'make-vector l))
-(defun k-list (&rest r) (cons 'list r))
-(defun k-append (&rest r) (cons 'append r))
-(defun k-list* (&rest r) (cons 'list* r))
-(defun k-cons (x y) (list 'cons x y))
-(defun insert (x) x)
-
-(defun list-extender (c)
-  (case c
-    ((cons list*) 'list*)
-    ((list) 'list)
-    (t (error "not a list constructor ~A" c))))
-
-(defun self-evaluating-p (x)
-  (or (literalp x)
-      (not (or (symbolp x) (combinationp x)
-               #|#+quasiquote-at-macro-expansion-time|# (simple-vector-p x)
-              ))))
-(defun constant-form-p (x)
-  (or #-quasiquote-quotes-literals (self-evaluating-p x)
-      (quotep x)))
-(defun all-constant-forms-p (l)
-  (every #'constant-form-p l))
-(defun unfold-constant-form (x)
-  (if (quotep x) (single-arg x) x))
-(defun unfold-constant-forms (l)
-  (mapcar #'unfold-constant-form l))
-(defun protect-constant-form (x)
-  (if (self-evaluating-p x) x (kwote x)))
-(defun protect-constant-forms (l)
-  (mapcar #'protect-constant-form l))
-
-
-(define-macro-matcher quasiquote
-  #'(lambda (x) (pattern-matcher (quasiquote-expand x))))
-
-;; Note: it would be a *very bad* idea to use quasiquote:quote
-;; in the expansion of the macro-character #\'
-
-(defun call-with-quasiquote-reader (thunk)
-  (let ((*quasiquote-level* (1+ *quasiquote-level*)))
-    (make-quasiquote (funcall thunk))))
-
-(defun call-with-unquote-reader (thunk)
-  (let ((*quasiquote-level* (1- *quasiquote-level*)))
-    (unless (>= *quasiquote-level* 0) (error "unquote outside quasiquote"))
-    (make-unquote (funcall thunk))))
-
-(defun call-with-unquote-splicing-reader (thunk)
-  (let ((*quasiquote-level* (1- *quasiquote-level*)))
-    (unless (>= *quasiquote-level* 0) (error "unquote-splicing outside quasiquote"))
-    (make-unquote-splicing (funcall thunk))))
-
-(defun call-with-unquote-nsplicing-reader (thunk)
-  (let ((*quasiquote-level* (1- *quasiquote-level*)))
-    (unless (>= *quasiquote-level* 0) (error "unquote-nsplicing outside quasiquote"))
-    (make-unquote-nsplicing (funcall thunk))))
-
-(defun read-quasiquote (stream)
-  (call-with-quasiquote-reader (lambda () (read stream t nil t))))
-
-(defun read-unquote (stream)
-  (call-with-unquote-reader (lambda () (read stream t nil t))))
-
-(defun read-unquote-splicing (stream)
-  (call-with-unquote-splicing-reader (lambda () (read stream t nil t))))
-
-(defun read-unquote-nsplicing (stream)
-  (call-with-unquote-nsplicing-reader (lambda () (read stream t nil t))))
-
-(defun n-vector (n contents)
-  (if (null n) (coerce contents 'simple-vector)
-    (let ((a (make-array n :element-type t)))
-      (when (and (null contents) (> n 0))
-       (error "non-zero length vector with empty contents"))
-      (loop for i below n with x
-       do (unless (null contents) (setq x (pop contents)))
-       do (setf (aref a i) x))
-      (when contents
-       (error "provided contents larger than declared vector length"))
-      a)))
-
-(defun read-vector (stream n)
-  ;; http://www.lisp.org/HyperSpec/Body/sec_2-4-8-3.html
-  (let ((contents (read-delimited-list #\) stream t)))
-    (if (> *quasiquote-level* 0)
-       (make-unquote (list 'n-vector n (quasiquote-expand contents)))
-       (n-vector n contents))))
-
-(defun read-read-time-backquote (stream char)
-  (declare (ignore char))
-  (values (macroexpand-1 (read-quasiquote stream))))
-(defun read-macroexpand-time-backquote (stream char)
-  (declare (ignore char))
-  (read-quasiquote stream))
-(defun read-backquote (stream char)
-  #-quasiquote-at-macro-expansion-time (read-read-time-backquote stream char)
-  #+quasiquote-at-macro-expansion-time (read-macroexpand-time-backquote stream char))
-(defun backquote-reader (expansion-time)
-  (ecase expansion-time
-    ((read) #'read-read-time-backquote)
-    ((macroexpand) #'read-macroexpand-time-backquote)
-    ((nil) #'read-backquote)))
-(defun read-comma (stream char)
-  (declare (ignore char))
-  (case (peek-char nil stream t nil t)
-    ((#\@)
-     (read-char stream t nil t)
-     (read-unquote-splicing stream))
-    ((#\.)
-     (read-char stream t nil t)
-     (read-unquote-nsplicing stream))
-    (otherwise (read-unquote stream))))
-(defun read-hash-paren (stream subchar arg)
-  (declare (ignore subchar))
-  (read-vector stream arg))
-
-(defun enable-quasiquote (&key expansion-time (readtable *readtable*))
-  (set-macro-character #\` (backquote-reader expansion-time) nil readtable)
-  (set-macro-character #\, #'read-comma nil readtable)
-  (when (eq expansion-time 'read)
-    (set-dispatch-macro-character #\# #\( #'read-hash-paren readtable))
-  t)
-
-);eval-when
-
-;;(trace quasiquote-expand quasiquote-expand-0 quasiquote-expand-1 expand-unquote)
-