Как развернуть макросы в пространстве имен cljs.core ClojureScript

Мне было любопытно, что делают определенные макросы, и я попытался позвонить (macroexpand-1), чтобы получить дополнительную информацию. Однако я немного запутался в том, как расширить встроенные макросы в ClojureScript, особенно макросы в пространстве имен cljs.core. Согласно документации, макросы ClojureScript написаны на Clojure и, следовательно, должны быть протестированы в Clojure REPL (вместо ClojureScript REPL), откуда я пробовал это.

Запустив lein repl из каталога моего проекта ClojureScript, я пробовал это:

=> (require 'cljs.compiler)
=> (require 'cljs.core)
=> (macroexpand-1 '(cljs.core/int 99.9))
(macroexpand-1 '(cljs.core/int 99.9))
(cljs.core/int 99.9)

Почему возвращается (cljs.core/int 99.9)? На основе источника ClojureScript не следует Разве этот макрос не расширяется до чего-то вроде (bit-or ~x 0)?

Когда я раскрываю макросы, не относящиеся к ClojureScript, например (macroexpand-1 '(when (even? 2) (println "2 is even"))), расширение работает нормально.

Похоже, я что-то концептуально упускаю ...


person Mason Stewart    schedule 05.07.2013    source источник


Ответы (2)


Скорее всего, вы используете версию ClojureScript, предшествующую этой фиксации, которая вводит макрос int. Попробуйте добавить [org.clojure/clojurescript "0.0-1835"] в свой :dependencies.

Кроме того, хотя здесь это не имеет значения, в целом вы должны использовать ClojureScript macroexpand-1, а не Clojure для таких тестов:

(require '[cljs.compiler :as comp]) ; must be required before cljs.core
(require '[cljs.core :as core])     ; the macros live here
(require '[cljs.analyzer :as ana])  ; macroexpand-1 lives here

;; ClojureScript's macroexpand-1 takes an environment as its first
;; argument; here's a useful initial environment:
(ana/macroexpand-1 {:locals {} :context :expr :ns 'cljs.user} '(int 5))
;= (cljs.core/bit-or 5 0)
person Michał Marczyk    schedule 05.07.2013
comment
Ах, теперь имеет смысл! Спасибо! - person Mason Stewart; 06.07.2013
comment
Интересно, что я не ожидал, что у ClojureScript будет собственный macroexpand-1, поскольку у него нет своего defmacro. - person Mason Stewart; 06.07.2013
comment
Просто понял, что Clojure macroexpand-1 действительно должен работать для вас здесь, см. Мой комментарий к ответу dnolen. Поскольку фиксация, представляющая макрос int, датирована 22 февраля 2013 г., вы можете просто использовать более старый выпуск; с 0.0-1835 (последний на этот раз) вы должны увидеть ожидаемый результат. По-прежнему верно, что macroexpand-1 от ClojureScript нужен в целом, поскольку среда ClojureScript может быть актуальной в более сложных случаях. - person Michał Marczyk; 06.07.2013
comment
Отредактировал ответ, чтобы включить приведенный выше комментарий. Что касается ClojureScript, имеющего свой собственный macroexpand-1: он необходим, потому что ClojureScript нуждается в собственной логике для поиска расширителей (см. cljs.analyzer/get-expander). Он также убеждает расширитель в том, что текущее пространство имен на самом деле вызывается независимо от того, как вызывается текущее пространство имен ClojureScript, чтобы он в некоторой степени осведомлен о фактической среде ClojureScript, в которую он выводит код. - person Michał Marczyk; 06.07.2013
comment
Попался. Теперь все это имеет гораздо больший смысл. Пытаясь понять, почему я не вижу макрос int, я обновил свою зависимость ClojureScript непосредственно перед тем, как вы опубликовали свой исходный ответ. Это совпадение показало, что мне пришлось использовать macroexpand-1 от ClojureScript, но вы правы: по крайней мере, для int это был просто случай отсутствия достаточно свежей банки. - person Mason Stewart; 06.07.2013

Макрос компилятора для int is all отсутствует.

person dnolen    schedule 05.07.2013
comment
Вообще-то есть, просто надо использовать правильный macroexpand-1. - person Michał Marczyk; 05.07.2013
comment
Хм, на самом деле обычный macroexpand-1 также должен работать в этом случае (среда ClojureScript здесь не имеет значения, за исключением наличия макроса bit-or, но это определено ранее в cljs/core.clj). Если OP этого не видит, вероятно, он использует версию, предшествующую введению макроса intэтот коммит). Так что этот ответ вполне верен для старых выпусков. Извините за путаницу. - person Michał Marczyk; 06.07.2013