vvvvalvalval / scope-capture

Project your Clojure(Script) REPL into the same context as your code when it ran
MIT License
573 stars 14 forks source link

Customizable, dependency-free, potentially non-blocking breakpoints #10

Open vvvvalvalval opened 6 years ago

vvvvalvalval commented 6 years ago

In order to make breakpoints available to non-blocking execution environments such as ClojureScript, the macro-expansion of sc.api/brk needs to be customized by some green-threading mechanism.

Currently, the most popular / official green threading mechanism would be core.async's go and <!, i.e the macro-expansion of (sc.api/brk expr) would expand to something like:

(let [ch12 (cljs.core.async/chan)]
  (prompt-breakpoint ch12)
  (let [cmd13 (cljs.core.async/<! ch12)]
    (case (:op cmd13)
      :loose expr 
      :loose-with (:value cmd13)
      :loose-with-err (throw (:error cmd13)))
    ))

Of course, for this to work, the (brk ...) call should be placed inside a go block.

I'm reluctant to use this approach, for several reasons:

Another solution would be to let the client register and use their own strategies for green-threading, by registering a hook in brk. Such strategies could be registered for core.async, manifold, promesa, etc. Examples:

clojure.core promise / deliver / deref:

(defn promise-deliver-port 
  []
  (let [p (promise)]
    {:read-port p
     :write-to-port (fn [cmd] (deliver p cmd))}))

(sc.api.breakpoints/register-green-threading-strategy
  :promise-deliver
  {:make-port `promise-deliver-port
   :emit (fn [cmd-sym read-port body]
           `(let [~cmd-sym (deref ~read-port)]
              ~body))})

core.async go / <!

(defn core-async-port
  []
  (let [c (cljs.core.async/chan)]
    {:read-port c
     :write-to-port (fn [cmd] (a/put! c cmd))}))

(sc.api.breakpoints/register-green-threading-strategy
  :core-async-<!
  {:make-port `core-async-port
   :emit (fn [cmd-sym read-port body]
           `(let [~cmd-sym (cljs.core.async/<! ~read-port)]
              ~body))})

Promesa alet / await

(defn promesa-port
  []
  (let [a (atom nil)
        p (p/promise (fn [resolve reject]
                       (reset! a resolve)))]
    {:read-port p
     :write-to-port @a}))

(sc.api.breakpoints/register-green-threading-strategy
  :promesa-alet-await
  {:make-port `core-async-port
   :emit (fn [cmd-sym read-port body]
           `(p/await (p/alet [~cmd-sym (p/await ~read-port)]
                       ~body)))})
vvvvalvalval commented 6 years ago

Will need a lil more hammock time, in the meantime brk not supported in CLJS.

vvvvalvalval commented 6 years ago

There's not necessarily a big demand for scope-capture providing non-blocking breakpoints, as it's already provided by Dirac: https://github.com/binaryage/dirac