Skip to content

Commit 35e4a18

Browse files
committed
Support env argument in macroexpand-1 and store ctx during macro invocation
macroexpand-1 now accepts an optional env map as first argument (like cljs.analyzer/macroexpand-1). Locals in the env shadow macro names, matching CLJS behavior. During macro invocation, the current analysis context is now stored via ctx-store, so that macroexpand-1 called from within macro bodies sees the correct bindings. This enables riddley's macroexpand-all to discover outer locals in bb, similar to how it reads Compiler/LOCAL_ENV on JVM.
1 parent 10298f2 commit 35e4a18

File tree

4 files changed

+27
-7
lines changed

4 files changed

+27
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ SCI is used in [babashka](https://github.com/babashka/babashka),
1616
- `case` now macroexpands to JVM-compatible `case*` format, enabling tools like riddley and cloverage to work with SCI
1717
- Fix `.method` on class objects (e.g. `(.getDeclaredField String "value")`) routing to static instead of instance method path
1818
- `macroexpand-1` of `(.method ClassName)` now wraps class targets in `identity`, matching Clojure behavior
19+
- `macroexpand-1` now accepts an optional env map as first argument, like `cljs.analyzer/macroexpand-1`
20+
- Store current analysis context during macro invocation, enabling tools like riddley to access outer locals
1921
- Support [#564](https://github.com/babashka/sci/issues/564): `this-as` in ClojureScript
2022

2123
## 0.12.51 (2025-02-07)

src/sci/impl/analyzer.cljc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
[ana-macros constant? macro? rethrow-with-location-of-node
2424
set-namespace! recur special-syms]]
2525
[sci.impl.vars :as vars]
26+
[sci.ctx-store :as store]
2627
[sci.lang])
2728
#?(:cljs
2829
(:require-macros
@@ -1625,7 +1626,8 @@
16251626
@f
16261627
f)
16271628
f (or (.-afn ^js f) f)])
1628-
v (apply f expr (:bindings ctx) (rest expr))
1629+
v (store/with-ctx ctx
1630+
(apply f expr (:bindings ctx) (rest expr)))
16291631
v (if (seq? v)
16301632
(with-meta v (merge m (meta v)))
16311633
v)

src/sci/impl/namespaces.cljc

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -790,11 +790,21 @@
790790

791791
;;;; Macroexpand
792792

793-
(defn macroexpand* [expr]
794-
(mexpand/macroexpand (store/get-ctx) expr))
795-
796-
(defn macroexpand-1* [expr]
797-
(mexpand/macroexpand-1 (store/get-ctx) expr))
793+
(defn macroexpand*
794+
([expr]
795+
(mexpand/macroexpand (store/get-ctx) expr))
796+
([env expr]
797+
(mexpand/macroexpand (cond-> (store/get-ctx)
798+
env (update :bindings merge env))
799+
expr)))
800+
801+
(defn macroexpand-1*
802+
([expr]
803+
(mexpand/macroexpand-1 (store/get-ctx) expr))
804+
([env expr]
805+
(mexpand/macroexpand-1 (cond-> (store/get-ctx)
806+
env (update :bindings merge env))
807+
expr)))
798808

799809
;;;;
800810

test/sci/core_test.cljc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,13 @@
11211121
(is (= '(. (clojure.core/identity String) getDeclaredFields)
11221122
(eval* "(macroexpand-1 '(.getDeclaredFields String))")))
11231123
(is (= '(. "foo" length)
1124-
(eval* "(macroexpand-1 '(.length \"foo\"))"))))))
1124+
(eval* "(macroexpand-1 '(.length \"foo\"))")))))
1125+
#?(:clj (testing "macroexpand-1 accepts env as first argument"
1126+
(is (= '(if 1 1 (clojure.core/cond))
1127+
(eval* "(macroexpand-1 {'a 1} '(cond 1 1))")))
1128+
(is (= '(cond 1 1)
1129+
(eval* "(macroexpand-1 {'cond 1} '(cond 1 1))"))
1130+
"local shadows macro"))))
11251131

11261132
(deftest macroexpand-call-test
11271133
(is (= [1 1] (eval* "(defmacro foo [x] `(bar ~x)) (defmacro bar [x] [x x]) (macroexpand '(foo 1))")))

0 commit comments

Comments
 (0)