Skip to content

Commit 3e22f2d

Browse files
committed
A missed test in the publication repo
Also a missed commit to metatronic which now is slightly more configurable.
1 parent c9dadf5 commit 3e22f2d

File tree

3 files changed

+107
-30
lines changed

3 files changed

+107
-30
lines changed

README.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -1691,7 +1691,7 @@ Metatronic macros make a lot of this pain go away: just give the symbols you wan
16911691
,@forms)))
16921692
```
16931693

1694-
All that happens is that each symbol whose name looks like `<...>` is rewritten as a gensymized version of itself, with each identical symbol being rewritten to the same thing[^17]. As a special case, symbols whose names are `"<>"` are rewritten as unique gensymized symbols[^18].
1694+
All that happens is that each symbol whose name looks like `<...>` is rewritten as a gensymized version of itself, with each identical symbol being rewritten to the same thing[^17]. As a special case, symbols whose names are `"<>"` are rewritten as unique gensymized symbols[^18]. The pattern symbols must match is controlled by a 'rewriter' function which can be changed if you don't like the default: see below.
16951695

16961696
With the above definition
16971697

@@ -1721,9 +1721,7 @@ where, in this case, all the `#:<in>` symbols are the same symbol.
17211721
- `form` is the form to be rewritten;
17221722
- `rewrites`, if given, is a table of rewrites returned from a previous call to `metatronize`;
17231723
- `sharing`, if given, is a table with information on structure sharing from a previous call to `metatronize` which it will use to possibly share structure with the `form` argument to that previous call;
1724-
- `rewriter`, if given, is a function of one argument, a symbol, which should return either its argument and any value or a gensymized version of it and an indication of whether it should be stored in the rewrite table.
1725-
1726-
If the last argument is given then it is used instead of the builtin metatronizer, so you can define your own notion of what symbols should be gensymized.
1724+
- `rewriter`, if given, is a function of one argument, a symbol, which should return either its argument and any value or a gensymized version of it and an indication of whether it should be stored in the rewrite table. The default value is `*default-metatronize-rewriter*`.
17271725

17281726
`metatronize` returns four values:
17291727

@@ -1732,6 +1730,8 @@ If the last argument is given then it is used instead of the builtin metatronize
17321730
- a list of unique symbols, which are usually the symbols that symbols whose names are `<>`get rewritten to;
17331731
- a sharing table describing shared structure in the form.
17341732

1733+
**`*default-metatronize-symbol-rewriter*`** is bound to the default symbol rewriter used by `metatronize`. Changing it will change the behaviour of `metatronize` and therefore of `defmacro/m` and `macrolet/m`. Reloading `metatronic` will reset it if you break things.
1734+
17351735
### Notes
17361736
Macros written with `defmacro/m` and `macrolet/m` in fact metatronize symbols *twice*: once when the macro is defined, and then again when it is expanded, using lists of rewritten & unique symbols from the first metatronization to drive a `rewriter` function. This ensures that each expansion has a unique set of gensymized symbols: with the above definition of `with-file-lines`, then
17371737

@@ -2114,8 +2114,6 @@ I'm not completely convinced by the precision time code.
21142114

21152115
Logging to pathnames rather than explicitly-managed streams may be a little slower, but seems now to be pretty close.
21162116

2117-
`slog` will *certainly* turn into something which isn't a toy fairly soon: consider this an ephemeral version.
2118-
21192117
### Package, module
21202118
`slog` lives in and provides `:org.tfeb.hax.slog`.
21212119

metatronic.lisp

+30-24
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,32 @@
1010
(:export
1111
#:defmacro/m
1212
#:macrolet/m
13-
#:metatronize))
13+
#:metatronize
14+
#:default-metatronize-symbol-rewriter))
1415

1516
(in-package :org.tfeb.hax.metatronic)
1617

1718
(provide :org.tfeb.hax.metatronic)
1819

20+
(defparameter *default-metatronize-symbol-rewriter* ;reload for sanity
21+
(lambda (s)
22+
(let* ((n (symbol-name s))
23+
(l (length n)))
24+
(if (and (>= l 2)
25+
(char= (char n 0) #\<)
26+
(char= (char n (1- l)) #\>))
27+
(values (make-symbol n)
28+
(/= l 2))
29+
(values s nil))))
30+
"The default symbol rewriter used by METATRONIZE
31+
32+
The initial value of this implements the bahviour described in the
33+
documentation: changing it will change the behaviour or DEFMACRO/M and
34+
MACROLET/M")
35+
1936
(defun metatronize (form &key
2037
(rewrites '()) (shares '())
21-
(rewriter nil))
38+
(rewriter *default-metatronize-symbol-rewriter*))
2239
;; This has hard-wired knowledge of what a metatronic variable looks
2340
;; like unless REWRITER is given
2441
"Return a metatronic version of FORM, the table of variables, a list
@@ -30,7 +47,8 @@ Arguments are FORM with keyword arguments
3047
- REWRITER, if given, should be a designator for a function of one
3148
argument, a symbol, which should either return the symbol or a
3249
metatronized symbol and an indication of whether it should be stored
33-
in the rewrite table.
50+
in the rewrite table. The default value of REWRITER is
51+
*DEFAULT-METATRONIZE-SYMBOL-REWRITER*.
3452
3553
This only looks at list structure. Sharing and circularity of list
3654
structure (only) is correctly copied."
@@ -43,27 +61,15 @@ structure (only) is correctly copied."
4361
(let ((r (assoc this rtab)))
4462
(if r
4563
(cdr r)
46-
(if rewriter
47-
(multiple-value-bind (new storep)
48-
(funcall rewriter this)
49-
(if (eq new this)
50-
this
51-
(progn
52-
(if storep
53-
(setf rtab (acons this new rtab))
54-
(push new anons))
55-
new)))
56-
(let* ((n (symbol-name this))
57-
(l (length n)))
58-
(if (and (>= l 2)
59-
(char= (char n 0) #\<)
60-
(char= (char n (1- l)) #\>))
61-
(let ((s (make-symbol n)))
62-
(if (/= l 2)
63-
(setf rtab (acons this s rtab))
64-
(push s anons))
65-
s)
66-
this))))))
64+
(multiple-value-bind (new storep)
65+
(funcall rewriter this)
66+
(if (eq new this)
67+
this
68+
(progn
69+
(if storep
70+
(setf rtab (acons this new rtab))
71+
(push new anons))
72+
new))))))
6773
(cons
6874
(let ((seen (assoc this stab)))
6975
(if seen

test/test-simple-loops.lisp

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
;;;; Simple loop tests
2+
;;;
3+
;;; Mostly these are to check the values stuff.
4+
;;;
5+
6+
#+org.tfeb.tools.require-module
7+
(org.tfeb.tools.require-module:needs
8+
(:org.tfeb.hax.simple-loops :compile t)
9+
#+Quicklisp
10+
("parachute" :fallback ql:quickload))
11+
12+
(defpackage :org.tfeb.hax.simple-loops/test
13+
(:use :cl :org.tfeb.hax.simple-loops :org.shirakumo.parachute))
14+
15+
(in-package :org.tfeb.hax.simple-loops/test)
16+
17+
(define-test "org.tfeb.hax.simple-loops")
18+
19+
(define-test ("org.tfeb.hax.simple-loops" "doing values")
20+
(is-values (doing ((i 0 (1+ i)))
21+
((> i 1)))
22+
(= 2))
23+
(is-values (doing ((i 0 (1+ i))
24+
(j 0))
25+
((> i 1)))
26+
(= 2)
27+
(= 0))
28+
(is-values (doing ((i 0 (1+ i)))
29+
((> i 1) 1))
30+
(= 1))
31+
(is-values (doing ((i 0 (1+ i)))
32+
((> i 1) 1 2))
33+
(= 1)
34+
(= 2))
35+
(is-values (doing ((i 0 (1+ i)))
36+
((> i 1) (values 1 2)))
37+
(= 1)
38+
(= 2))
39+
(is-values (doing ((i 0 (1+ i)))
40+
((> i 1) (values 1 2) 3))
41+
(= 1)
42+
(= 2)
43+
(= 3)))
44+
45+
(define-test ("org.tfeb.hax.simple-loops" "looping/values inits")
46+
(is-values (looping/values ((i j) (values 0 1))
47+
(return (values i j)))
48+
(= 0)
49+
(= 1))
50+
(is-values (looping/values ((i j) 0 1)
51+
(return (values i j)))
52+
(= 0)
53+
(= 1))
54+
(is-values (looping/values ((i j k) (values 0 1) 2)
55+
(return (values i j k)))
56+
(= 0)
57+
(= 1)
58+
(= 2)))
59+
60+
(define-test ("org.tfeb.hax.simple-loops" "looping/values* iterate")
61+
(is = (looping/values* (((i j) (values 0 1))
62+
((k) 0))
63+
(when (> k 3)
64+
(return k))
65+
(values i j (1+ k)))
66+
4))
67+
68+
(define-test ("org.tfeb.hax.simple-loops" "looping/values* sequential")
69+
(finish (looping/values* (((i j) 0 1)
70+
((k) i))
71+
(return t))))
72+
73+
(test "org.tfeb.hax.simple-loops" :report 'summary)

0 commit comments

Comments
 (0)