Skip to content

Commit 951a6df

Browse files
committed
refactor variable storage, add nrepl support for debugging, fix #3
1 parent 6d32eb3 commit 951a6df

File tree

4 files changed

+321
-77
lines changed

4 files changed

+321
-77
lines changed

project.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
:dependencies [[cheshire/cheshire "6.0.0"]
66
[clj-stacktrace "0.2.8"]
77
[com.taoensso/timbre "6.7.1"]
8+
[nrepl "1.3.1"]
89
[org.clojure/clojure "1.12.1"]
910
[org.clojure/core.async "1.8.741"]
1011
[org.luaj/luaj-jse "3.0.1"]]
@@ -15,6 +16,7 @@
1516
:native-image {:opts ["--verbose"
1617
"--report-unsupported-elements-at-runtime"
1718
"--initialize-at-build-time"]}
18-
:profiles {:uberjar {:aot :all
19+
:profiles {:dev {:dependencies [[nubank/matcher-combinators "3.9.1"]]}
20+
:uberjar {:aot :all
1921
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}
2022
:native-image {:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})

src/mobdap/handler.clj

Lines changed: 190 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
[taoensso.timbre :as log]))
1111

1212
(def ^:private go-handler (atom nil))
13-
(def ^:private breakpoint-id-counter (atom 1))
14-
(def ^:private stackframe-id-counter (atom 1))
15-
(def ^:private vars-id-counter (atom 1))
16-
(def ^:private var-index (atom {}))
1713

1814
(defn- create-handler [adapter]
1915
{:adapter adapter
@@ -23,7 +19,11 @@
2319
:breakpoints {}
2420
:channels {:to-handler (chan)
2521
:to-debug-server nil}
26-
:stackframes (atom [])})
22+
:counter {:breakpoint (atom 0)
23+
:stackframe (atom 0)
24+
:vars (atom 0)}
25+
:stackframes (atom [])
26+
:var-index (atom {})})
2727

2828
(defn- to-int [value]
2929
(if (int? value)
@@ -65,10 +65,6 @@
6565
(first)))))
6666

6767
(defn- find-source-relative-file [handler filepath]
68-
(log/info "SOURCE DIRS" (:source-dirs handler))
69-
(log/info "ORIG FILE" filepath)
70-
(log/info "DIR" (find-source-dir handler filepath))
71-
(log/info "FILE" (find-source-file handler filepath))
7268
(let [source-dir (.getCanonicalPath (io/file (find-source-dir handler filepath)))
7369
filepath (.getCanonicalPath (io/file filepath))]
7470
(assert (some? source-dir))
@@ -157,36 +153,66 @@
157153
{:type (keyword type)
158154
:addr addr}))
159155

160-
(defn- parse-value [_ packed-value]
156+
(defn- parse-inner-value [handler name value]
157+
(cond
158+
(vector? value)
159+
{:id (swap! (get-in handler [:counter :vars]) inc)
160+
:name name
161+
:type :table
162+
:addr nil
163+
:value (vec (map (partial parse-inner-value handler nil) value))}
164+
165+
(map? value)
166+
{:id (swap! (get-in handler [:counter :vars]) inc)
167+
:name name
168+
:type :table
169+
:addr nil
170+
:value (map-over-map (fn [k v] (parse-inner-value handler k v)) value)}
171+
172+
:else
173+
{:name name
174+
:type :constant
175+
:value value}))
176+
177+
(defn- parse-value [handler var-name packed-value]
161178
(case (count packed-value)
162-
1 {:id (swap! vars-id-counter inc)
179+
1 {:name var-name
163180
:type :constant
164181
:value nil}
165182
2 (let [[value ident] packed-value]
166183
(if-let [{type :type addr :addr} (parse-heap-value ident)]
167-
{:id (swap! vars-id-counter inc)
184+
{:id (swap! (get-in handler [:counter :vars]) inc)
185+
:name var-name
168186
:type type
169187
:addr addr
170-
:value value}
171-
{:id (swap! vars-id-counter inc)
188+
:value (case type
189+
:table (if (vector? value)
190+
(vec (map-indexed (partial parse-inner-value handler) value))
191+
(map-over-map (fn [k v] (parse-inner-value handler k v)) value))
192+
value)}
193+
{:name var-name
172194
:type :constant
173195
:value value}))
174196
(do (log/error "Could not unpack" packed-value)
175197
nil)))
176198

199+
(defn- register-vars [handler vars]
200+
(log/error "VARS?" vars)
201+
(doseq [[_ v] (if (map? vars) vars (zipmap (range (count vars)) vars))]
202+
(when (:id v)
203+
(swap! (:var-index handler) assoc (:id v) v))
204+
(when (= :table (:type v))
205+
(register-vars handler (:value v)))))
206+
177207
(defn- transform-stack-trace [handler stack-trace]
178208
(map-indexed
179209
(fn [_ [frame-info stack upvalues]]
180-
(let [stack (map-over-map parse-value stack)
181-
upvalues (map-over-map parse-value upvalues)]
182-
183-
; register vars from stack
184-
(doseq [[k v] stack]
185-
(swap! var-index assoc k v))
210+
(let [parse-value (partial parse-value handler)
211+
stack (map-over-map parse-value stack)
212+
upvalues (map-over-map parse-value upvalues)]
186213

187-
; register vars from upvalues
188-
(doseq [[k v] upvalues]
189-
(swap! var-index assoc k v))
214+
(register-vars handler stack)
215+
(register-vars handler upvalues)
190216

191217
(case (count frame-info)
192218
; example of the frame header (6):
@@ -196,15 +222,15 @@
196222
; 3: "Lua" - Lua (thats where it comes from ig)
197223
; 4: "field" - ??? this can also be "upvalue"
198224
; 5: "modules/tbl.lua" - file location again
199-
6 {:id (swap! stackframe-id-counter inc)
225+
6 {:id (swap! (get-in handler [:counter :stackframe]) inc)
200226
:name ""
201227
:source {:path (find-source-file handler (frame-info 0))}
202228
:line (parse-long (frame-info 2))
203229
:column 0
204230
:extras {:scope-start (parse-long (frame-info 1))
205-
:stack {:id (swap! vars-id-counter inc)
231+
:stack {:id (swap! (get-in handler [:counter :vars]) inc)
206232
:values stack}
207-
:upvalues {:id (swap! vars-id-counter inc)
233+
:upvalues {:id (swap! (get-in handler [:counter :vars]) inc)
208234
:values upvalues}
209235
:type (frame-info 4)}}
210236

@@ -216,15 +242,15 @@
216242
; 4: "Lua" - Lua (thats where it comes from ig)
217243
; 5: "field" - ??? this can also be "upvalue"
218244
; 6: "modules/tbl.lua" - file location again
219-
7 {:id (swap! stackframe-id-counter inc)
245+
7 {:id (swap! (get-in handler [:counter :stackframe]) inc)
220246
:name (or (frame-info 0) "")
221247
:source {:path (find-source-file handler (frame-info 1))}
222248
:line (parse-long (frame-info 3))
223249
:column 0
224250
:extras {:scope-start (parse-long (frame-info 2))
225-
:stack {:id (swap! vars-id-counter inc)
251+
:stack {:id (swap! (get-in handler [:counter :vars]) inc)
226252
:values stack}
227-
:upvalues {:id (swap! vars-id-counter inc)
253+
:upvalues {:id (swap! (get-in handler [:counter :vars]) inc)
228254
:values upvalues}
229255
:type (frame-info 5)}}
230256

@@ -311,7 +337,7 @@
311337
{:keys [source breakpoints]} (:arguments message)
312338
source-path (:path source)
313339
filename (find-source-relative-file handler source-path)
314-
breakpoints (mapv #(assoc % :verified true :id (swap! breakpoint-id-counter inc)) breakpoints)]
340+
breakpoints (mapv #(assoc % :verified true :id (swap! (get-in handler [:counter :breakpoint]) inc)) breakpoints)]
315341
(adapter/send-message! adapter (success (:seq message) "setBreakpoints" {:breakpoints breakpoints}))
316342
(-> handler
317343
(assoc-in [:breakpoints (str filename)] breakpoints))))
@@ -373,68 +399,156 @@
373399
(get-in m [:extras :upvalues]))))
374400
data))
375401

376-
(defn- table-remove-types-not-to-be-shown [table]
377-
(filter #(not (#{:function} (second %))) table))
378-
379402
(defn- float-to-string [n]
380403
(.replaceAll (format "%.16f" n) "\\.?0*$" ""))
381404

382-
(defn- create-variables [vars]
405+
(defn- var-name [n]
406+
(cond
407+
(keyword? n) (name n)
408+
(string? n) n
409+
(number? n) (str n)
410+
:else (str n)))
411+
412+
(defn- var-value [v]
413+
(cond
414+
(string? v) (str v)
415+
(int? v) (format "%i" v)
416+
(float? v) (float-to-string v)
417+
(number? v) (float-to-string v)
418+
(boolean? v) (str v)
419+
(vector? v) (format "[%s]" (string/join ", " (map #(var-value (:value %)) v)))
420+
(map? v) (format "{%s}" (string/join ", " (map (fn [[k v]] (str (var-name k) " = " (var-value (:value v)))) v)))
421+
:else (str v)))
422+
423+
(defn- var-type [v]
424+
(cond
425+
(string? v) "string"
426+
(int? v) "int"
427+
(float? v) "float"
428+
(number? v) "number"
429+
(boolean? v) "boolean"
430+
(nil? v) "null"
431+
:else nil))
432+
433+
(defn- var-value-table [v]
434+
(cond
435+
(vector? v)
436+
(format
437+
"[%s]"
438+
(string/join ", " (map #(var-value (:value %)) v)))
439+
440+
(map? v)
441+
(format
442+
"{%s}"
443+
(string/join ", " (map (fn [[k v]] (str (var-name k) " = " (var-value (:value v)))) v)))
444+
445+
(empty? v)
446+
"{}"
447+
448+
:else (throw (ex-info (str "expected vector or map, got: " (pr-str v)) {:value v}))))
449+
450+
(defn- create-scope-variables [vars]
383451
(map
384452
(fn [[k v]]
385453
(case (:type v)
386-
:constant {:name (name k)
387-
:value (cond
388-
(string? (:value v)) (:value v)
389-
(int? (:value v)) (format "%i" (:value v))
390-
(float? (:value v)) (float-to-string (:value v))
391-
(number? (:value v)) (float-to-string (:value v))
392-
(boolean? (:value v)) (str (:value v))
393-
:else (str (:value v)))
394-
:type (cond
395-
(string? (:value v)) "string"
396-
(int? (:value v)) "int"
397-
(float? (:value v)) "float"
398-
(number? (:value v)) "number"
399-
(boolean? (:value v)) "boolean"
400-
:else nil)
401-
:evaluateName (name k)
402-
:variablesReference (:id v)
454+
:constant {:name (var-name k)
455+
:value (var-value (:value v))
456+
:type (var-type (:value v))
457+
:evaluateName (var-name k)
458+
:variablesReference 0
403459
:namedVariables 0
404460
:indexedVariables 0
405461
:presentationHint {:kind "data"
406462
:attributes ["constant"]}}
407-
:table {:name (name k)
408-
:value
409-
(if (vector? (:value v))
410-
(format
411-
"[ %s ]"
412-
(string/join ", " (:value v)))
413-
(format
414-
"{ %s }"
415-
(string/join ", " (map (fn [[k v]] (str (name k) " = " v)) (table-remove-types-not-to-be-shown (:value v))))))
416-
:type
417-
(if (vector? (:value v)) "array" "object")
418-
:evaluateName (name k)
463+
464+
:table {:name (var-name k)
465+
:value (var-value-table (:value v))
466+
:type (if (vector? (:value v)) "array" "object")
467+
:evaluateName (var-name k)
419468
:variablesReference (:id v)
420-
:namedVariables (if (map? (:value v)) (count (table-remove-types-not-to-be-shown (:value v))) 0)
421-
:indexedVariables (if (vector? (:value v)) (count (:value v)) 0)
469+
:namedVariables (if (map? (:value v)) (count (:value v)) 0)
470+
:indexedVariables (if (vector? (:value v)) (count (:value v)) 0)
422471
:presentationHint {:kind "data"
423472
:attributes (if (vector? (:value v)) "array" "rawObject")}}
424-
:function nil
425-
(do (log/error "Unknown variable type:" (:type v) v)
426-
nil)))
473+
474+
:function {:name (var-name k)
475+
:value (format "function: %s" (:addr v))
476+
:type "function"
477+
:variablesReference 0
478+
:presentationHint {:kind "method"}}
479+
480+
(do (log/warn "Unknown variable type found:" k v)
481+
{:name (var-name k)
482+
:value (format "%s: %s" (var-name (:type v)) (:addr v))
483+
:variablesReference 0
484+
:type "unknown"})))
427485
vars))
428486

487+
(defn- make-var [pname indexed? n value]
488+
(let [fstr (str (var-name pname) (if indexed? "[%s]" ".%s"))
489+
v (:value value)]
490+
(log/info "MAKE VARS HAPPEN" n v (:id v))
491+
(cond
492+
(vector? v)
493+
{:name (var-name n)
494+
:value (var-value-table v)
495+
:type "array"
496+
:evaluateName (format fstr n)
497+
:variablesReference (:id value)
498+
:presentationHint {:kind "data"
499+
:attributes ["array"]}}
500+
501+
(map? v)
502+
{:name (var-name n)
503+
:value (var-value-table v)
504+
:type "object"
505+
:evaluateName (format fstr n)
506+
:variablesReference (:id value)
507+
:presentationHint {:kind "data"
508+
:attributes ["rawObject"]}}
509+
510+
:else
511+
{:name (var-name n)
512+
:value (var-value v)
513+
:type (var-type v)
514+
:evaluateName (format fstr n)
515+
:variablesReference 0
516+
:presentationHint {:kind "data"}})))
517+
518+
(defn- create-variables [vars]
519+
(log/info "CREATE VARS?" vars)
520+
(case (:type vars)
521+
:table (map-indexed
522+
(if (vector? (:value vars))
523+
(fn [idx v] (make-var (:name vars) true (str idx) v))
524+
(fn [_ [k v]] (make-var (:name vars) false (var-name k) v)))
525+
(:value vars))
526+
[nil]))
527+
528+
(defn- find-var-by-id [handler var-id]
529+
(let [scope (:values (find-vars-scope-by-id @(:stackframes handler) var-id))
530+
vars (@(:var-index handler) var-id)]
531+
(cond
532+
scope [scope :scope]
533+
vars [vars :vars]
534+
:else [nil nil])))
535+
429536
(defn handle-variables [handler message]
430-
(let [vars-id (get-in message [:arguments :variablesReference])
431-
vars (or (:values (find-vars-scope-by-id @(:stackframes handler) vars-id))
432-
(@var-index vars-id))]
433-
(adapter/send-message!
434-
(:adapter handler)
435-
(success (:seq message)
436-
"variables"
437-
{:variables (filter some? (create-variables vars))}))
537+
(let [vars-id (get-in message [:arguments :variablesReference])
538+
[vars type] (find-var-by-id handler vars-id)]
539+
(assert (and (some? vars) (some? type)))
540+
541+
(let [variables
542+
(filter some? (case type
543+
:scope (create-scope-variables vars)
544+
:vars (create-variables vars)
545+
:else []))]
546+
547+
(adapter/send-message!
548+
(:adapter handler)
549+
(success (:seq message)
550+
"variables"
551+
{:variables variables})))
438552
handler))
439553

440554
(defn handle-continue [handler message]

src/mobdap/main.clj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
(:require
33
[clojure.java.io :as io]
44
[mobdap.handler :as handler]
5+
[nrepl.server :as nrepl]
56
[taoensso.timbre :as log]
67
[taoensso.timbre.appenders.core :as appenders])
78
(:gen-class))
89

10+
(defonce nrepl-server (nrepl/start-server :port (or (System/getenv "NREPL_PORT") 45999)))
11+
912
(defn- cache-dir []
1013
(or
1114
(System/getenv "XDG_CACHE_HOME")

0 commit comments

Comments
 (0)