letfn is a macro over a letfn* special form (Clojure semantics)
jolt modelled letfn as a special form directly, so (macroexpand-1 '(letfn …)) returned the form unchanged. Clojure's letfn is a macro that expands to letfn*, and macroexpansion tooling (tools.macro, tools.analyzer) depends on that — its special-form handlers key on letfn*, not letfn. Split it the Clojure way: - letfn* is now the special form (analyzer), taking flat name/fn-form pairs [name1 fn1 name2 fn2 …] — the letrec :let lowering is unchanged. - letfn is a macro (00-syntax) turning each (name [params] body*) spec into a name + (fn name [params] body*) binding, so it expands to letfn*. So (macroexpand-1 '(letfn [(f [x] x)] (f 1))) now yields (letfn* [f (fn f [x] x)] (f 1)), and clojure.tools.macro passes its whole suite (macrolet / symbol-macrolet / mexpand-all). Listed in docs + site. make test green (+1 corpus row, 0 new divergences), shakesmoke byte-identical. One re-mint (analyzer + the letfn macro); selfhost holds.
This commit is contained in:
parent
7891fa0d55
commit
21cd88deee
6 changed files with 341 additions and 330 deletions
|
|
@ -65,6 +65,8 @@ e.g. the [ring-app example](https://github.com/jolt-lang/examples/tree/main/ring
|
|||
byte arrays.
|
||||
* [data.priority-map](https://github.com/clojure/data.priority-map) — priority
|
||||
maps (incl. keyfn / custom comparator), with `subseq`/`rsubseq`.
|
||||
* [tools.macro](https://github.com/clojure/tools.macro) — local macros
|
||||
(`macrolet`/`symbol-macrolet`), `mexpand`/`mexpand-all`.
|
||||
* [test.check](https://github.com/clojure/test.check) — property-based testing
|
||||
(generators, `quick-check`, shrinking).
|
||||
* [tick](https://github.com/juxt/tick) — date/time over Jolt's `java.time`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue