The quasiquote-2.0 Reference Manual

Next: , Previous: , Up: (dir)   [Contents][Index]

The quasiquote-2.0 Reference Manual

This is the quasiquote-2.0 Reference Manual, version 0.3, generated automatically by Declt version 4.0 beta 2 "William Riker" on Wed Jun 15 05:39:06 2022 GMT+0.

Table of Contents


1 Introduction

quasiquote-2.0

Why should it be hard to write macros that write other macros? Well, it shouldn't!

quasiquote-2.0 defines slightly different rules for quasiquotation, that make writing macro-writing macros very smooth experience.

NOTE: quasiquote-2.0 does horrible things to shared structure!!! (it does a lot of COPY-TREE's, so shared-ness is destroyed). So, it's indeed a tool to construct code (where it does not matter much if the structure is shared or not) and not the data (or, at least, not the data with shared structure)

(quasiquote-2.0:enable-quasiquote-2.0)

(defmacro define-my-macro (name args &body body)
  `(defmacro ,name ,args
     `(sample-thing-to-expand-to
        ,,@body))) ; note the difference from usual way

(define-my-macro foo (x y)
  ,x ; now here injections of quotation constructs work
  ,y)

(define-my-macro bar (&body body)
  ,@body) ; splicing is also easy

The "injections" in macros FOO and BAR work as naively expected, as if I had written

(defmacro foo (x y)
  `(sample-thing-to-expand-to ,x ,y))

(defmacro bar (&body body)
  `(sample-thing-to-expand-to ,@body))

(macroexpand-1 '(foo a b))

  '(SAMPLE-THING-TO-EXPAND-TO A B)

(macroexpand-1 '(bar a b c))

  '(SAMPLE-THING-TO-EXPAND-TO A B C)

So, how is this effect achieved?

DIG, INJECT and SPLICE

The transformations of backquote occur at macroexpansion-time and not at read-time. It is totally possible not to use any special reader syntax, but just underlying macros directly!

At the core is a macro DIG, which expands to the code that generates the expression according to the rules, which are roughly these:

;; The example using macros, without special reader syntax

(dig ; depth is 1 here
  (a b
     (dig ; depth is 2 here
       ((inject c) ; this inject is not evaluated, because depth is nonzero
        (inject (d ;depth becomes 1 here again
                (inject e) ; and this inject is evaluated, because depth becomes zero
                ))
        (inject 2 f) ; this inject with level specification is evaluated, because it
                     ; decreases depth by 2
        ))))


;; the same example using ENABLE-QUASIQUOTE-2.0 syntax is written as
`(a b `(,c ,(d ,e) ,,f)) ; note double comma acts different than usually

The ENABLE-QUASIQUOTE-2.0 macro just installs reader that reads `FORM as (DIG FORM), ,FORM as (INJECT FORM) and ,@FORM as (SPLICE FORM). You can just as well type DIG's, INJECT's and SPLICE's directly, (in particular, when writing utility functions that generate macro-generating code) or roll your own convenient reader syntax (pull requests are welcome).

So, these two lines (with ENABLE-QUASIQUOTE-2.0) read the same

`(a (,b `,,c) d)

(dig (a ((inject b) (dig (inject 2 c))) d))

You may notice the (INJECT 2 ...) form appearing, which is described below.

At "level 1", i.e. when only ` , and ,@ are used, and not, say `` ,, ,', ,,@ ,',@ this behaves exactly as usual quasiquotation.

The optional N argument

All quasiquote-2.0 operators accept optional "depth" argument, which goes before the form for human readability.

Namely, (DIG N FORM) increases depth by N instead of one and (INJECT N FORM) decreases depth by N instead of one.

(DIG 2 (INJECT 2 A))

; gives the same result as

(DIG (INJECT A))

In fact, with ENABLE-QUASIQUOTE-2.0, say, ,,,,,FORM (5 quotes) reads as (INJECT 5 FORM) and ,,,,,@FORM as (SPLICE 5 FORM)

More examples

For fairly complicated example, which uses ,,,@ and OINJECT (see below), see DEFINE-BINOP-DEFINER macro in CG-LLVM (https://github.com/mabragor/cg-llvm/src/basics.lisp), desire to write which was the initial impulse for this project.

For macro, that is not a macro-writing macro, yet benefits from ability to inject using , and ,@, consider JOINING-WITH-COMMA-SPACE macro (also from CG-LLVM)

(defmacro joining-with-comma-space (&body body)
  ;; joinl just joins strings in the list with specified string
  `(joinl ", " (mapcar #'emit-text-repr
		       (remove-if-not #'identity  `(,,@body)))))

;; the macro can be then used uniformly over strings and lists of strings
(defun foo (x y &rest z)
  (joining-with-comma-space ,x ,y ,@z))

(foo "a" "b" "c" "d")
  ;; produces
  "a, b, c, d"

ODIG and OINJECT and OSPLICE

Sometimes you don't want DIG's macroexpansion to look further into the structure of some INJECT or SPLICE or DIG in its subform, if the depth does not match. In these cases you need "opaque" versions of DIG, INJECT and SPLICE, named, respectively, ODIG, OINJECT and OSPLICE.

;; here injection of B would occur
(defun foo (b)
  (dig (dig (inject (a (inject b))))))

;; and here not, because macroexpansion does not look into OINJECT form
(defun bar (b)
  (dig (dig (oinject (a (inject b))))))

(foo 1)

  '(DIG (INJECT (A 1)))

(bar 1)

  '(DIG (OINJECT (A (INJECT B))))

MACRO-INJECT and MACRO-SPLICE

Sometimes you just want to abstract-out some common injection patterns... That is, you want macros, that expand into common injection patterns. However, you want this only sometimes, and only in special circumstances. So it won't do, if INJECT and SPLICE just expanded something, whenever it turned out to be macro. For that, use MACRO-INJECT and MACRO-SPLICE.

;; with quasiquote-2.0 syntax turned on
(defmacro inject-n-times (form n)
  (make-list n :initial-element `(inject ,form)))

(let (x 0)
  `(dig (a (macro-inject (inject-n-times (incf x) 3)))))
;; yields
'(a (1 2 3))

;;and same with MACRO-SPLICE
(let (x 0)
  `(dig (a (macro-splice (inject-n-times (incf x) 3)))))
;; yields
'(a 1 2 3)

OMACRO-INJECT and OMACRO-SPLICE are, as usual, opaque variants of MACRO-INJECT and MACRO-SPLICE.

Both MACRO-INJECT and MACRO-SPLICE expand their subform exactly once (using MACROEXPAND-1), before plugging it into list. If you want to expand as much as it's possible, use MACRO-INJECT-ALL and MACRO-SPLICE-ALL, which expand using MACROEXPAND before injecting/splicing, respectively. That implies, that while subform of MACRO-INJECT and MACRO-SPLICE is checked to be macro-form, the subform of MACRO-INJECT-ALL is not.

Terse syntax of the ENABLE-QUASIQUOTE-2.0

Of course, typing all those MACRO-INJECT-ALL, or OMACRO-SPLICE-ALL or whatever explicitly every time you want this special things is kind of clumsy. For that, default reader of quasiquote-2.0 provides extended syntax

',,,,!oma@x

;; reads as
'(OMACRO-SPLICE-ALL 4 X)

That is, the regexp of the syntax is [,]+![o][m][a][@]

As usual, number of commas determine the anti-depth of the injector, exclamation mark turns on the syntax, if o is present, opaque version of injector will be used, if m is present, macro-expanding version of injector will be used and if a is present, macro-all version of injector will be used.

Note: it's possible to write ,!ax, which will read as (INJECT-ALL X), but this will not correspond to the actual macro name.

Note: it was necessary to introduce special escape-char for extended syntax, since usual idioms like ,args would otherwise be completely screwed.

TODO

P.S. Name "quasiquote-2.0" comes from "patronus 2.0" spell from www.hpmor.com and has nothing to do with being "the 2.0" version of quasiquote.


2 Systems

The main system appears first, followed by any subsystem dependency.


Previous: , Up: Systems   [Contents][Index]

2.1 quasiquote-2.0

Writing macros that write macros. Effortless.

Author

Alexandr Popolitov <popolit@gmail.com>

License

MIT

Version

0.3

Dependency

iterate (system).

Source

quasiquote-2.0.asd.

Child Components

3 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Previous: , Up: Files   [Contents][Index]

3.1 Lisp


Next: , Previous: , Up: Lisp   [Contents][Index]

3.1.1 quasiquote-2.0/quasiquote-2.0.asd

Source

quasiquote-2.0.asd.

Parent Component

quasiquote-2.0 (system).

ASDF Systems

quasiquote-2.0.

Packages

quasiquote-2.0-system.


3.1.2 quasiquote-2.0/package.lisp

Source

quasiquote-2.0.asd.

Parent Component

quasiquote-2.0 (system).

Packages

quasiquote-2.0.


3.1.3 quasiquote-2.0/quasiquote-2.0.lisp

Dependency

package.lisp (file).

Source

quasiquote-2.0.asd.

Parent Component

quasiquote-2.0 (system).

Public Interface
Internals

3.1.4 quasiquote-2.0/macros.lisp

Dependency

quasiquote-2.0.lisp (file).

Source

quasiquote-2.0.asd.

Parent Component

quasiquote-2.0 (system).

Public Interface
Internals

define-dig-like-macro (macro).


3.1.5 quasiquote-2.0/readers.lisp

Dependency

macros.lisp (file).

Source

quasiquote-2.0.asd.

Parent Component

quasiquote-2.0 (system).

Public Interface
Internals

4 Packages

Packages are listed by definition order.


Next: , Previous: , Up: Packages   [Contents][Index]

4.1 quasiquote-2.0

Source

package.lisp.

Use List
  • common-lisp.
  • iterate.
Public Interface
Internals

Previous: , Up: Packages   [Contents][Index]

4.2 quasiquote-2.0-system

Source

quasiquote-2.0.asd.

Use List
  • asdf/interface.
  • common-lisp.

5 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

5.1 Public Interface


5.1.1 Macros

Macro: dig (n-or-form &optional form)
Package

quasiquote-2.0.

Source

macros.lisp.

Macro: disable-quasiquote-2.0 ()
Package

quasiquote-2.0.

Source

readers.lisp.

Macro: enable-quasiquote-2.0 ()
Package

quasiquote-2.0.

Source

readers.lisp.

Macro: inject (n-or-form &optional form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Macro: macro-inject (n-or-form &optional form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Macro: odig (n-or-form &optional form)
Package

quasiquote-2.0.

Source

macros.lisp.

Macro: oinject (n-or-form &optional form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Macro: osplice (n-or-form &optional form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Macro: splice (n-or-form &optional form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.


Previous: , Up: Public Interface   [Contents][Index]

5.1.2 Ordinary functions

Function: %codewalk-dig-form (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: transform-dig-form (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.


5.2 Internals


Next: , Previous: , Up: Internals   [Contents][Index]

5.2.1 Special variables

Special Variable: *depth*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *env*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *injectors*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *known-diggers*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *known-injectors*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *known-macro-injectors*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *known-splicers*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *macro-handlers*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *opaque-injectors*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *previous-readtables*
Package

quasiquote-2.0.

Source

readers.lisp.

Special Variable: *void-elt*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Special Variable: *void-filter-needed*
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.


5.2.2 Macros

Macro: define-dig-like-macro (name)
Package

quasiquote-2.0.

Source

macros.lisp.

Macro: define-dig-reader (name symbol)
Package

quasiquote-2.0.

Source

readers.lisp.

Macro: define-nonsense-when-bare (name)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Macro: make-list-form (o!-n form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Macro: nonsense-error (str)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.


Previous: , Up: Internals   [Contents][Index]

5.2.3 Ordinary functions

Function: %disable-quasiquote-2.0 ()
Package

quasiquote-2.0.

Source

readers.lisp.

Function: %enable-quasiquote-2.0 ()
Package

quasiquote-2.0.

Source

readers.lisp.

Function: codewalk-dig-form (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: dig-form-p (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: dig-reader (stream char)
Package

quasiquote-2.0.

Source

readers.lisp.

Function: expect-char (char stream)
Package

quasiquote-2.0.

Source

readers.lisp.

Function: filter-out-voids (lst void-sym)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: get-macro-handler (sym)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: guess-injector-name (opaque-p macro-p all-p splicing-p)
Package

quasiquote-2.0.

Source

readers.lisp.

Function: handle-macro-1 (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: handle-macro-all (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: inject-reader (stream char)
Package

quasiquote-2.0.

Source

readers.lisp.

Function: injector-form-p (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: injector-level (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: injector-subform (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: look-into-dig (form path)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: look-into-injector (form path)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: macro-injector-p (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: macroexpand-macroinjector (place)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: mk-splicing-injector-let (x)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: mk-splicing-injector-setf (path g!-list g!-splicee)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: odig-reader (stream char)
Package

quasiquote-2.0.

Source

readers.lisp.

Function: path->setfable (path var)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: read-n-chars (stream char)
Package

quasiquote-2.0.

Source

readers.lisp.

Function: really-transform-dig-form (the-form site-paths)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: reset-injectors ()
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: search-all-active-sites (form path toplevel-p)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: splicing-injector (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: transparent-p (form)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.

Function: tree->cons-code (tree)
Package

quasiquote-2.0.

Source

quasiquote-2.0.lisp.


Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts


Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   %  
C   D   E   F   G   H   I   L   M   N   O   P   R   S   T  
Index Entry  Section

%
%codewalk-dig-form: Public ordinary functions
%disable-quasiquote-2.0: Private ordinary functions
%enable-quasiquote-2.0: Private ordinary functions

C
codewalk-dig-form: Private ordinary functions

D
define-dig-like-macro: Private macros
define-dig-reader: Private macros
define-nonsense-when-bare: Private macros
dig: Public macros
dig-form-p: Private ordinary functions
dig-reader: Private ordinary functions
disable-quasiquote-2.0: Public macros

E
enable-quasiquote-2.0: Public macros
expect-char: Private ordinary functions

F
filter-out-voids: Private ordinary functions
Function, %codewalk-dig-form: Public ordinary functions
Function, %disable-quasiquote-2.0: Private ordinary functions
Function, %enable-quasiquote-2.0: Private ordinary functions
Function, codewalk-dig-form: Private ordinary functions
Function, dig-form-p: Private ordinary functions
Function, dig-reader: Private ordinary functions
Function, expect-char: Private ordinary functions
Function, filter-out-voids: Private ordinary functions
Function, get-macro-handler: Private ordinary functions
Function, guess-injector-name: Private ordinary functions
Function, handle-macro-1: Private ordinary functions
Function, handle-macro-all: Private ordinary functions
Function, inject-reader: Private ordinary functions
Function, injector-form-p: Private ordinary functions
Function, injector-level: Private ordinary functions
Function, injector-subform: Private ordinary functions
Function, look-into-dig: Private ordinary functions
Function, look-into-injector: Private ordinary functions
Function, macro-injector-p: Private ordinary functions
Function, macroexpand-macroinjector: Private ordinary functions
Function, mk-splicing-injector-let: Private ordinary functions
Function, mk-splicing-injector-setf: Private ordinary functions
Function, odig-reader: Private ordinary functions
Function, path->setfable: Private ordinary functions
Function, read-n-chars: Private ordinary functions
Function, really-transform-dig-form: Private ordinary functions
Function, reset-injectors: Private ordinary functions
Function, search-all-active-sites: Private ordinary functions
Function, splicing-injector: Private ordinary functions
Function, transform-dig-form: Public ordinary functions
Function, transparent-p: Private ordinary functions
Function, tree->cons-code: Private ordinary functions

G
get-macro-handler: Private ordinary functions
guess-injector-name: Private ordinary functions

H
handle-macro-1: Private ordinary functions
handle-macro-all: Private ordinary functions

I
inject: Public macros
inject-reader: Private ordinary functions
injector-form-p: Private ordinary functions
injector-level: Private ordinary functions
injector-subform: Private ordinary functions

L
look-into-dig: Private ordinary functions
look-into-injector: Private ordinary functions

M
Macro, define-dig-like-macro: Private macros
Macro, define-dig-reader: Private macros
Macro, define-nonsense-when-bare: Private macros
Macro, dig: Public macros
Macro, disable-quasiquote-2.0: Public macros
Macro, enable-quasiquote-2.0: Public macros
Macro, inject: Public macros
Macro, macro-inject: Public macros
Macro, make-list-form: Private macros
Macro, nonsense-error: Private macros
Macro, odig: Public macros
Macro, oinject: Public macros
Macro, osplice: Public macros
Macro, splice: Public macros
macro-inject: Public macros
macro-injector-p: Private ordinary functions
macroexpand-macroinjector: Private ordinary functions
make-list-form: Private macros
mk-splicing-injector-let: Private ordinary functions
mk-splicing-injector-setf: Private ordinary functions

N
nonsense-error: Private macros

O
odig: Public macros
odig-reader: Private ordinary functions
oinject: Public macros
osplice: Public macros

P
path->setfable: Private ordinary functions

R
read-n-chars: Private ordinary functions
really-transform-dig-form: Private ordinary functions
reset-injectors: Private ordinary functions

S
search-all-active-sites: Private ordinary functions
splice: Public macros
splicing-injector: Private ordinary functions

T
transform-dig-form: Public ordinary functions
transparent-p: Private ordinary functions
tree->cons-code: Private ordinary functions

Jump to:   %  
C   D   E   F   G   H   I   L   M   N   O   P   R   S   T