Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Userland macros receives RCF env as &env instead of standard clojure &env value #74

Open
ggeoffrey opened this issue Jan 29, 2023 · 6 comments

Comments

@ggeoffrey
Copy link
Member

Reported by @didibus

A minimal repro is welcome

@ggeoffrey
Copy link
Member Author

Minimal repro:

(defmacro my-test-macro [a]
  (prn &env)
  `[~a])

;; No RCF
(let [a 1]
  (my-test-macro a))
;; => {a #object[clojure.lang.Compiler$LocalBinding 0x58d44b9f "clojure.lang.Compiler$LocalBinding@58d44b9f"]}
;; => [1]

;; From inside RCF
(tests
  (let [a 1]
    (my-test-macro a)) := [1])
;; => {a {:op :binding, :name a, :init {:op :const, :env {:locals {}, :namespaces {}, :ns hyperfiddle.rcf-test}, :form 1}, :form a, :local :let, :children [:init]}}
;; => ✅

@ggeoffrey
Copy link
Member Author

ggeoffrey commented Jan 29, 2023

It is not clear to me if one can construct a valid instances of LocalBinding.
If it is possible then maybe RCF could reconstruct the clojure &env from its own environment.

I tried to produce an instance of LocalBinding, but got an IllegalAccessError failed to access class clojure.lang.Compiler$Expr which has package level visibility.

@dustingetz
Copy link
Member

  • can we monkey-patch the Expr class visibility from userland
  • can we reify something duck typed that matches most userland calls?
  • what is cljs impact

@dustingetz
Copy link
Member

dustingetz commented Jan 29, 2023

@didibus
Copy link

didibus commented Jan 30, 2023

I'm using &env to get all current locals, their primitive type, and their attached metadata.

In my macro, I do the following:

(map (fn[[_k v]] (meta (.-sym v))) &env)

To get all local symbols from &env.

I also do this:

(try
    (when-some [java-class (.getJavaClass expr-ast)]
      {:class java-class
       :primitive? (.isPrimitive java-class)})
    (catch Exception _e))

On each LocalBinding returned from &env to get the type of the local and it is a primitive or not.

I believe this is the type for what &env returns: https://www.javadoc.io/doc/org.clojure/clojure/1.11.1/clojure/lang/Compiler.LocalBinding.html

@didibus
Copy link

didibus commented Feb 1, 2023

So I saw that riddley macro-expander I think seems to create LocalBindings as it macro-expands: https://github.com/ztellman/riddley/blob/master/src/riddley/compiler.clj#L55 and https://github.com/ztellman/riddley/blob/master/src/riddley/Util.java#L8 which you could also do in Clojure I guess.

It does seem you have to somewhat update the Compiler about it, or the creation of the LocalBinding will throw an IllegalAccessError or something of that sort.

Might be a lead?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants