Tensegritics / ClojureDart

Clojure dialect for Flutter and Dart
1.44k stars 91 forks source link

Macros defined in ClojureDart cannot reference previously defined functions in same namespace #324

Open dmg46664 opened 1 month ago

dmg46664 commented 1 month ago

Describe the bug

Clojure dart is not able to handle this scenario where a function is defined and used in a subsequent macro.

To Reproduce

(defn gensyms [amt]
  (vec (repeatedly amt gensym)))

(defmacro mk-comp-navs []
  ;; rest of fn altered for brevity...
  (gensyms 1)
  )
Syntax error compiling at (test.cljd:14:3).
Faulty form (defmacro mk-comp-navs [] (gensyms 1))

Expected behavior

This should work.

No doubt because of ClojureDart's two phase macro-expansion, it's not aware of the function defined a few lines above.

This is something that is possible in cljs, so presumably the two phases need to work more in parallel than in sequence, or effectively behave as such.

Assume you're aware of cljs quirks https://code.thheller.com/blog/shadow-cljs/2019/10/12/clojurescript-macros.html but these require defining aliases etc.

Additional context

I was trying to convert the specter library and came across a problem running the following code.

Pointing cljd at more clj code will highlight more differences with the language. More reason to champion the following suggestion ;-) https://clojurians.slack.com/archives/C03A6GE8D32/p1729680676173319

I suggest this difference go under the Completeness status of the project given the difference with Clojure core.

cgrand commented 1 month ago

Add ^:macro-support to the defn name

dmg46664 commented 1 month ago

@cgrand And for defn- and def (reading between the lines) 😆

dmg46664 commented 4 weeks ago

Hi @cgrand ,

I tried the following in core.cljd

(def
  ^{:macro true
    :macro-support true <------------ here
    :doc "Same as (def name (fn [params* ] exprs*)) or (def
    name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
    to the var metadata. prepost-map defines a map with optional keys
    :pre and :post that contain collections of pre or post conditions."
   :arglists '([name doc-string? attr-map? [params*] prepost-map? body]
                [name doc-string? attr-map? ([params*] prepost-map? body)+ attr-map?])}
 defn (fn defn [&form &env fname & fdecl]

but this didn't solve it. No doubt I'm bulldozing my way through, not understanding the larger framework. 🤔

So before I go down rabbit holes I thought I'd ask if there are resources that describe:

  1. An overview of how the compiler/core works. (I found the following super useful for cljs https://www.youtube.com/watch?v=kBKIGj1_WAo)
  2. Tools/flags/processes for getting debug output from the compiler when it gets to certain namespaces/sexps. No doubt you have tricks to get at contextual information (presuming that the compiler progresses in a clojurey immutable manner).

Perhaps a doc/working-on-the-compiler.md ?

Edit: Seems the same was asked here https://github.com/Tensegritics/ClojureDart/issues/16