philoskim / debux

A trace-based debugging library for Clojure and ClojureScript.
468 stars 19 forks source link

Cannot use first-class dbgn fn within macro #10

Closed jeaye closed 6 years ago

jeaye commented 6 years ago

Version: [philoskim/debux "0.4.11"]

Here's the simplest example:

(dbgn
  (defn glug []
    ))

(defmacro bar [data]
  `(do
     ~(get data ::key glug)))

(defn -main []
  (bar {}))

The error:

Exception in thread "main" java.lang.ExceptionInInitializerError, compiling:(core.clj:13:1)
    at clojure.lang.Compiler$DefExpr.eval(Compiler.java:470)
    at clojure.lang.Compiler.eval(Compiler.java:7067)
    at clojure.lang.Compiler.load(Compiler.java:7514)
    at clojure.lang.RT.loadResourceScript(RT.java:379)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.load(RT.java:460)
    at clojure.lang.RT.load(RT.java:426)
    at clojure.core$load$fn__6548.invoke(core.clj:6046)
    at clojure.core$load.invokeStatic(core.clj:6045)
    at clojure.core$load.doInvoke(core.clj:6029)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invokeStatic(core.clj:5848)
    at clojure.core$load_one.invoke(core.clj:5843)
    at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
    at clojure.core$load_lib.invokeStatic(core.clj:5887)
    at clojure.core$load_lib.doInvoke(core.clj:5868)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invokeStatic(core.clj:659)
    at clojure.core$load_libs.invokeStatic(core.clj:5925)
    at clojure.core$load_libs.doInvoke(core.clj:5909)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invokeStatic(core.clj:659)
    at clojure.core$require.invokeStatic(core.clj:5947)
    at clojure.core$require.doInvoke(core.clj:5947)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at user$eval3111$fn__3115.invoke(form-init1748171861957467243.clj:1)
    at user$eval3111.invokeStatic(form-init1748171861957467243.clj:1)
    at user$eval3111.invoke(form-init1748171861957467243.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:7062)
    at clojure.lang.Compiler.eval(Compiler.java:7052)
    at clojure.lang.Compiler.load(Compiler.java:7514)
    at clojure.lang.Compiler.loadFile(Compiler.java:7452)
    at clojure.main$load_script.invokeStatic(main.clj:278)
    at clojure.main$init_opt.invokeStatic(main.clj:280)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invokeStatic(main.clj:311)
    at clojure.main$null_opt.invokeStatic(main.clj:345)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.invokeStatic(main.clj:424)
    at clojure.main$main.doInvoke(main.clj:387)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.lang.Var.applyTo(Var.java:702)
    at clojure.main.main(main.java:37)
Caused by: java.lang.ExceptionInInitializerError
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at clojure.lang.Compiler$ObjExpr.eval(Compiler.java:4989)
    at clojure.lang.Compiler$DefExpr.eval(Compiler.java:457)
    ... 42 more
Caused by: java.lang.IllegalArgumentException: No matching ctor found for class debux_meta.core$eval6680$glug__6681
    at clojure.lang.Reflector.invokeConstructor(Reflector.java:163)
    at clojure.lang.LispReader$EvalReader.invoke(LispReader.java:1303)
    at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:843)
    at clojure.lang.LispReader.read(LispReader.java:275)
    at clojure.lang.LispReader.read(LispReader.java:206)
    at clojure.lang.LispReader.read(LispReader.java:195)
    at clojure.lang.RT.readString(RT.java:1871)
    at clojure.lang.RT.readString(RT.java:1866)
    at debux_meta.core$_main.<clinit>(core.clj:13)
    ... 49 more
philoskim commented 6 years ago

I examined what you had issued and concluded that it's not the problem of debux.

dbgn wraps the given form in let like this after macro-expansion.

(dbgn
  (defn glug []))

;; after macroexpand-all the above form
(if (ut/debug-enabled? "debux.core")
  (let*
    [+debux-dbg-opts+ {:evals (atom {})} condition__14749__auto__ nil]
    (try
      (if (let*
            [or__4469__auto__ (nil? condition__14749__auto__)]
            (if or__4469__auto__
              or__4469__auto__
              condition__14749__auto__))
        (let*
          [title__14750__auto__
           (str
             "\ndbgn: "
             (ut/truncate (pr-str '(def glug (fn* ([])))))
             " =>")]
          (println title__14750__auto__)
          (def glug
           (fn*
             ([]
               (try
                 (reset! (:evals +debux-dbg-opts+) {})
                 (swap! ut/config* update :indent-level inc)
                 (ut/insert-blank-line)
                 (catch java.lang.Exception e (throw e))
                 (finally
                   (swap! ut/config* update :indent-level dec)))))))
        (def glug (fn* ([]))))
      (catch java.lang.Exception e (throw e))))
  (def glug (fn* ([]))))

It is inevitable to wrap the given form in let to debug its form in dbgn.

And then, look at the following code.

(let [a 10]
  (defn glug [] a))
;; => #'debux.core/glug

(defmacro bar [data]
  `(do
     ~(get data ::key glug)))
;; => #'debux.core/bar

(defn main []
  (bar {}))
;; 3. Unhandled clojure.lang.Compiler$CompilerException
;;    Error compiling form-init8224604637773231031.clj at (51:1)
;;
;;              Compiler.java:  464  clojure.lang.Compiler$DefExpr/eval
;;              Compiler.java: 6932  clojure.lang.Compiler/eval
;;              Compiler.java: 6890  clojure.lang.Compiler/eval
;;                   core.clj: 3105  clojure.core/eval
;;                   core.clj: 3101  clojure.core/eval
;;                   main.clj:  240  clojure.main/repl/read-eval-print/fn
;;                   main.clj:  240  clojure.main/repl/read-eval-print
;;                   main.clj:  258  clojure.main/repl/fn
;;                   main.clj:  258  clojure.main/repl
;;                   main.clj:  174  clojure.main/repl
;;                RestFn.java: 1523  clojure.lang.RestFn/invoke
;;     interruptible_eval.clj:   87  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
;;                   AFn.java:  152  clojure.lang.AFn/applyToHelper
;;                   AFn.java:  144  clojure.lang.AFn/applyTo
;;                   core.clj:  646  clojure.core/apply
;;                   core.clj: 1881  clojure.core/with-bindings*
;;                   core.clj: 1881  clojure.core/with-bindings*
;;                RestFn.java:  425  clojure.lang.RestFn/invoke
;;     interruptible_eval.clj:   85  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
;;     interruptible_eval.clj:   55  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
;;     interruptible_eval.clj:  222  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
;;     interruptible_eval.clj:  190  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
;;                   AFn.java:   22  clojure.lang.AFn/run
;;    ThreadPoolExecutor.java: 1149  java.util.concurrent.ThreadPoolExecutor/runWorker
;;    ThreadPoolExecutor.java:  624  java.util.concurrent.ThreadPoolExecutor$Worker/run
;;                Thread.java:  748  java.lang.Thread/run
;;
;; 2. Caused by java.lang.ExceptionInInitializerError
;;    (No message)
;;
;; NativeConstructorAccessorImpl.java:   -2  sun.reflect.NativeConstructorAccessorImpl/newInstance0
;; NativeConstructorAccessorImpl.java:   62  sun.reflect.NativeConstructorAccessorImpl/newInstance
;; DelegatingConstructorAccessorImpl.java:   45  sun.reflect.DelegatingConstructorAccessorImpl/newInstance
;;           Constructor.java:  423  java.lang.reflect.Constructor/newInstance
;;                 Class.java:  442  java.lang.Class/newInstance
;;              Compiler.java: 4913  clojure.lang.Compiler$ObjExpr/eval
;;              Compiler.java:  451  clojure.lang.Compiler$DefExpr/eval
;;              Compiler.java: 6932  clojure.lang.Compiler/eval
;;              Compiler.java: 6890  clojure.lang.Compiler/eval
;;                   core.clj: 3105  clojure.core/eval
;;                   core.clj: 3101  clojure.core/eval
;;                   main.clj:  240  clojure.main/repl/read-eval-print/fn
;;                   main.clj:  240  clojure.main/repl/read-eval-print
;;                   main.clj:  258  clojure.main/repl/fn
;;                   main.clj:  258  clojure.main/repl
;;                   main.clj:  174  clojure.main/repl
;;                RestFn.java: 1523  clojure.lang.RestFn/invoke
;;     interruptible_eval.clj:   87  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
;;                   AFn.java:  152  clojure.lang.AFn/applyToHelper
;;                   AFn.java:  144  clojure.lang.AFn/applyTo
;;                   core.clj:  646  clojure.core/apply
;;                   core.clj: 1881  clojure.core/with-bindings*
;;                   core.clj: 1881  clojure.core/with-bindings*
;;                RestFn.java:  425  clojure.lang.RestFn/invoke
;;     interruptible_eval.clj:   85  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
;;     interruptible_eval.clj:   55  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
;;     interruptible_eval.clj:  222  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
;;     interruptible_eval.clj:  190  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
;;                   AFn.java:   22  clojure.lang.AFn/run
;;    ThreadPoolExecutor.java: 1149  java.util.concurrent.ThreadPoolExecutor/runWorker
;;    ThreadPoolExecutor.java:  624  java.util.concurrent.ThreadPoolExecutor$Worker/run
;;                Thread.java:  748  java.lang.Thread/run
;;
;; 1. Caused by java.lang.IllegalArgumentException
;;    No matching ctor found for class debux.core$eval15315$glug__15316
;;
;;             Reflector.java:  163  clojure.lang.Reflector/invokeConstructor
;;            LispReader.java: 1120  clojure.lang.LispReader$EvalReader/invoke
;;            LispReader.java:  691  clojure.lang.LispReader$DispatchReader/invoke
;;            LispReader.java:  263  clojure.lang.LispReader/read
;;            LispReader.java:  196  clojure.lang.LispReader/read
;;            LispReader.java:  185  clojure.lang.LispReader/read
;;                    RT.java: 1835  clojure.lang.RT/readString
;;                    RT.java: 1830  clojure.lang.RT/readString
;;                       REPL:   51  debux.core/main
;; NativeConstructorAccessorImpl.java:   -2  sun.reflect.NativeConstructorAccessorImpl/newInstance0
;; NativeConstructorAccessorImpl.java:   62  sun.reflect.NativeConstructorAccessorImpl/newInstance
;; DelegatingConstructorAccessorImpl.java:   45  sun.reflect.DelegatingConstructorAccessorImpl/newInstance
;;           Constructor.java:  423  java.lang.reflect.Constructor/newInstance
;;                 Class.java:  442  java.lang.Class/newInstance
;;              Compiler.java: 4913  clojure.lang.Compiler$ObjExpr/eval
;;              Compiler.java:  451  clojure.lang.Compiler$DefExpr/eval
;;              Compiler.java: 6932  clojure.lang.Compiler/eval
;;              Compiler.java: 6890  clojure.lang.Compiler/eval
;;                   core.clj: 3105  clojure.core/eval
;;                   core.clj: 3101  clojure.core/eval
;;                   main.clj:  240  clojure.main/repl/read-eval-print/fn
;;                   main.clj:  240  clojure.main/repl/read-eval-print
;;                   main.clj:  258  clojure.main/repl/fn
;;                   main.clj:  258  clojure.main/repl
;;                   main.clj:  174  clojure.main/repl
;;                RestFn.java: 1523  clojure.lang.RestFn/invoke
;;     interruptible_eval.clj:   87  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
;;                   AFn.java:  152  clojure.lang.AFn/applyToHelper
;;                   AFn.java:  144  clojure.lang.AFn/applyTo
;;                   core.clj:  646  clojure.core/apply
;;                   core.clj: 1881  clojure.core/with-bindings*
;;                   core.clj: 1881  clojure.core/with-bindings*
;;                RestFn.java:  425  clojure.lang.RestFn/invoke
;;     interruptible_eval.clj:   85  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
;;     interruptible_eval.clj:   55  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
;;     interruptible_eval.clj:  222  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
;;     interruptible_eval.clj:  190  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
;;                   AFn.java:   22  clojure.lang.AFn/run
;;    ThreadPoolExecutor.java: 1149  java.util.concurrent.ThreadPoolExecutor/runWorker
;;    ThreadPoolExecutor.java:  624  java.util.concurrent.ThreadPoolExecutor$Worker/run
;;                Thread.java:  748  java.lang.Thread/run

The same exception occurs without dbgn macro.

In my opinion, when a defined function is wrapped in let and refers some bindings in let within the function, the same execption occurs. However, I don't know exactly why this occurs.

And refer to the following discussions as well.

https://groups.google.com/forum/#!msg/clojure/VVbKdvlnEG4/xIc5xqFPBgAJ

If I am wrong, please let me know about it.

Lastly, I recommend that you should do it like this, if you want to achieve what you want.

(dbgn
  (defn glug []))
;; => #'debux.core/glug

(defmacro bar [data]
  `(do
     ~(get data ::key 'glug)))
;; => #'debux.core/bar

(defn main []
  (bar {}))
; => #'debux.core/main

(main)
; => #function[debux.core/eval14809/glug--14810]
jeaye commented 6 years ago

Lastly, I recommend that you should do it like this, if you want to achieve what you want.

Thanks so much for looking into this and providing such a complete response! Your suggested change did the trick and now debux seems to be working well.