summaryrefslogtreecommitdiff
path: root/generic-walking.lisp
blob: 11487cc395c56841a40f513ad3cf4dc52692c1ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
(in-package :agnostic-lizard)

(defmethod metaenv-macroexpand-all (form (env walker-metaenv))
  (let*
    ((replacement (funcall (metaenv-on-every-form-pre env) form env))
     (hardwiring-needed-p
       (and (consp replacement)
            (find (first replacement) *hardwired-operators*)))
     (expanded-raw (if hardwiring-needed-p replacement
                     (metaenv-macroexpand replacement env)))
     (expanded (funcall (metaenv-on-macroexpanded-form env) expanded-raw env))
     (function-like-p (and expanded (consp expanded)))
     (operator (and function-like-p (first expanded)))
     ; If the operator has a dual macro/special-operator implementation,
     ; it is already macroexpanded by that point.
     (specialp (special-operator-p operator))
     (function-replacement
       (if (or specialp hardwiring-needed-p)
         (funcall (metaenv-on-special-form-pre env) expanded env)
         (funcall (metaenv-on-function-form-pre env) expanded env)))
     (full-expansion
       (cond
         ((not function-like-p) expanded)
         (specialp (metaenv-macroexpand-all-special-form
                     operator function-replacement env))
         ; Default handler works fine for both progn and function call forms,
         ; we define the same handler once more for progn just for the sake of
         ; explicitness
         (t (metaenv-macroexpand-all-special-form
              operator function-replacement env))))
     (full-expansion-replacement
       (if (and function-like-p (not specialp))
         (funcall (metaenv-on-function-form env) full-expansion env)
         (funcall (metaenv-on-special-form env) full-expansion env)))
     (result (funcall (metaenv-on-every-form env) full-expansion-replacement env)))
    result))

(defun walk-form (form env &rest handler-definitions)
  "Walk the form inside the environment described by env using the handlers from handler-definitions.
Handlers get a form and a walker-metaenv environment description.
The return value of a handler is used instead of the form passed to the handler during further processing.

Handlers can be:
:on-every-form-pre — called before processing each form in an executable position
:on-macroexpanded-form — called for each form after macroexpanding its top operation; hardwired macros are passed unexpanded
:on-special-form-pre — called before processing a special form or a hardwired macro
:on-function-form-pre — called before processing a function call
:on-special-form — called after processing a special form or a hardwired macro
:on-function-form — called after processing a function call
:on-every-form — called after expanding each form in an executable position

env can be metaenv or walker-metaenv
"
  (metaenv-macroexpand-all
    form
    (apply
      'make-instance 'walker-metaenv
      (append
        handler-definitions
        (when (subtypep 'walker-metaenv (type-of env))
          (metaenv-clone-args env))))))