PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/local-lisp/slime/contrib/swank-kawa.scm

https://bitbucket.org/sakito/dot.emacs.d/
Scheme | 2174 lines | 1738 code | 251 blank | 185 comment | 2 complexity | d55a8867a508e1d528cdf1f8c1e0d728 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-4.0, GPL-2.0, Unlicense

Large files files are truncated, but you can click here to view the full file

  1. ;;;; swank-kawa.scm --- Swank server for Kawa
  2. ;;;
  3. ;;; Copyright (C) 2007 Helmut Eller
  4. ;;;
  5. ;;; This file is licensed under the terms of the GNU General Public
  6. ;;; License as distributed with Emacs (press C-h C-c for details).
  7. ;;;; Installation
  8. ;;
  9. ;; 1. You need Kawa (SVN version)
  10. ;; and a Sun JVM with debugger support.
  11. ;; 2. Compile this file with:
  12. ;; kawa -e '(compile-file "swank-kawa.scm" "swank-kawa")'
  13. ;; 3. Add something like this to your .emacs:
  14. #|
  15. ;; Kawa and the debugger classes (tools.jar) must be in the classpath.
  16. ;; You also need to start the debug agent.
  17. (setq slime-lisp-implementations
  18. '((kawa ("java"
  19. "-cp" "/opt/kawa/kawa-svn:/opt/java/jdk1.6.0/lib/tools.jar"
  20. "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n"
  21. "kawa.repl" "-s")
  22. :init kawa-slime-init)))
  23. (defun kawa-slime-init (file _)
  24. (setq slime-protocol-version 'ignore)
  25. (let ((zip ".../slime/contrib/swank-kawa.zip")) ; <-- insert the right path
  26. (format "%S\n"
  27. `(begin (load ,(expand-file-name zip)) (start-swank ,file)))))
  28. |#
  29. ;; 4. Start everything with M-- M-x slime kawa
  30. ;;
  31. ;;
  32. ;;;; Module declaration
  33. (module-export start-swank create-swank-server swank-java-source-path)
  34. (module-static #t)
  35. (module-compile-options
  36. warn-invoke-unknown-method: #t
  37. warn-undefined-variable: #t
  38. )
  39. (require 'hash-table)
  40. ;;;; Macros ()
  41. (define-syntax df
  42. (syntax-rules (=>)
  43. ((df name (args ... => return-type) body ...)
  44. (define (name args ...) :: return-type body ...))
  45. ((df name (args ...) body ...)
  46. (define (name args ...) body ...))))
  47. (define-syntax fun
  48. (syntax-rules ()
  49. ((fun (args ...) body ...)
  50. (lambda (args ...) body ...))))
  51. (define-syntax fin
  52. (syntax-rules ()
  53. ((fin body handler ...)
  54. (try-finally body (seq handler ...)))))
  55. (define-syntax seq
  56. (syntax-rules ()
  57. ((seq body ...)
  58. (begin body ...))))
  59. (define-syntax esc
  60. (syntax-rules ()
  61. ((esc abort body ...)
  62. (let* ((key (<symbol>))
  63. (abort (lambda (val) (throw key val))))
  64. (catch key
  65. (lambda () body ...)
  66. (lambda (key val) val))))))
  67. (define-syntax !
  68. (syntax-rules ()
  69. ((! name obj args ...)
  70. (invoke obj 'name args ...))))
  71. (define-syntax !!
  72. (syntax-rules ()
  73. ((!! name1 name2 obj args ...)
  74. (! name1 (! name2 obj args ...)))))
  75. (define-syntax @
  76. (syntax-rules ()
  77. ((@ name obj)
  78. (field obj 'name))))
  79. (define-syntax while
  80. (syntax-rules ()
  81. ((while exp body ...)
  82. (do () ((not exp)) body ...))))
  83. (define-syntax dotimes
  84. (syntax-rules ()
  85. ((dotimes (i n result) body ...)
  86. (let ((max :: <int> n))
  87. (do ((i :: <int> 0 (as <int> (+ i 1))))
  88. ((= i max) result)
  89. body ...)))
  90. ((dotimes (i n) body ...)
  91. (dotimes (i n #f) body ...))))
  92. (define-syntax dolist
  93. (syntax-rules ()
  94. ((dolist (e list) body ... )
  95. (for ((e list)) body ...))))
  96. (define-syntax for
  97. (syntax-rules ()
  98. ((for ((var iterable)) body ...)
  99. (let ((iter (! iterator iterable)))
  100. (while (! has-next iter)
  101. ((lambda (var) body ...)
  102. (! next iter)))))))
  103. (define-syntax packing
  104. (syntax-rules ()
  105. ((packing (var) body ...)
  106. (let ((var :: <list> '()))
  107. (let ((var (lambda (v) (set! var (cons v var)))))
  108. body ...)
  109. (reverse! var)))))
  110. ;;(define-syntax loop
  111. ;; (syntax-rules (for = then collect until)
  112. ;; ((loop for var = init then step until test collect exp)
  113. ;; (packing (pack)
  114. ;; (do ((var init step))
  115. ;; (test)
  116. ;; (pack exp))))
  117. ;; ((loop while test collect exp)
  118. ;; (packing (pack) (while test (pack exp))))))
  119. (define-syntax with
  120. (syntax-rules ()
  121. ((with (vars ... (f args ...)) body ...)
  122. (f args ... (lambda (vars ...) body ...)))))
  123. (define-syntax pushf
  124. (syntax-rules ()
  125. ((pushf value var)
  126. (set! var (cons value var)))))
  127. (define-syntax ==
  128. (syntax-rules ()
  129. ((== x y)
  130. (eq? x y))))
  131. (define-syntax set
  132. (syntax-rules ()
  133. ((set x y)
  134. (let ((tmp y))
  135. (set! x tmp)
  136. tmp))
  137. ((set x y more ...)
  138. (begin (set! x y) (set more ...)))))
  139. (define-syntax assert
  140. (syntax-rules ()
  141. ((assert test)
  142. (seq
  143. (when (not test)
  144. (error "Assertion failed" 'test))
  145. 'ok))
  146. ((assert test fstring args ...)
  147. (seq
  148. (when (not test)
  149. (error "Assertion failed" 'test (format #f fstring args ...)))
  150. 'ok))))
  151. (define-syntax mif
  152. (syntax-rules (quote unquote _)
  153. ((mif ('x value) then else)
  154. (if (equal? 'x value) then else))
  155. ((mif (,x value) then else)
  156. (if (eq? x value) then else))
  157. ((mif (() value) then else)
  158. (if (eq? value '()) then else))
  159. #| This variant produces no lambdas but breaks the compiler
  160. ((mif ((p . ps) value) then else)
  161. (let ((tmp value)
  162. (fail? :: <int> 0)
  163. (result #!null))
  164. (if (instance? tmp <pair>)
  165. (let ((tmp :: <pair> tmp))
  166. (mif (p (@ car tmp))
  167. (mif (ps (@ cdr tmp))
  168. (set! result then)
  169. (set! fail? -1))
  170. (set! fail? -1)))
  171. (set! fail? -1))
  172. (if (= fail? 0) result else)))
  173. |#
  174. ((mif ((p . ps) value) then else)
  175. (let ((fail (lambda () else))
  176. (tmp value))
  177. (if (instance? tmp <pair>)
  178. (let ((tmp :: <pair> tmp))
  179. (mif (p (@ car tmp))
  180. (mif (ps (@ cdr tmp))
  181. then
  182. (fail))
  183. (fail)))
  184. (fail))))
  185. ((mif (_ value) then else)
  186. then)
  187. ((mif (var value) then else)
  188. (let ((var value)) then))
  189. ((mif (pattern value) then)
  190. (mif (pattern value) then (values)))))
  191. (define-syntax mcase
  192. (syntax-rules ()
  193. ((mcase exp (pattern body ...) more ...)
  194. (let ((tmp exp))
  195. (mif (pattern tmp)
  196. (begin body ...)
  197. (mcase tmp more ...))))
  198. ((mcase exp) (ferror "mcase failed ~s\n~a" 'exp (pprint-to-string exp)))))
  199. (define-syntax mlet
  200. (syntax-rules ()
  201. ((mlet (pattern value) body ...)
  202. (let ((tmp value))
  203. (mif (pattern tmp)
  204. (begin body ...)
  205. (error "mlet failed" tmp))))))
  206. (define-syntax mlet*
  207. (syntax-rules ()
  208. ((mlet* () body ...) (begin body ...))
  209. ((mlet* ((pattern value) ms ...) body ...)
  210. (mlet (pattern value) (mlet* (ms ...) body ...)))))
  211. (define-syntax typecase
  212. (syntax-rules (::)
  213. ((typecase var (type body ...) ...)
  214. (cond ((instance? var type)
  215. (let ((var :: type var))
  216. body ...))
  217. ...
  218. (else (error "typecase failed" var
  219. (! getClass (as <object> var))))))))
  220. (define-syntax ignore-errors
  221. (syntax-rules ()
  222. ((ignore-errors body ...)
  223. (try-catch (begin body ...)
  224. (v <java.lang.Exception> #f)))))
  225. ;;(define-syntax dc
  226. ;; (syntax-rules ()
  227. ;; ((dc name () %% (props ...) prop more ...)
  228. ;; (dc name () %% (props ... (prop <object>)) more ...))
  229. ;; ;;((dc name () %% (props ...) (prop type) more ...)
  230. ;; ;; (dc name () %% (props ... (prop type)) more ...))
  231. ;; ((dc name () %% ((prop type) ...))
  232. ;; (define-simple-class name ()
  233. ;; ((*init* (prop :: type) ...)
  234. ;; (set (field (this) 'prop) prop) ...)
  235. ;; (prop :type type) ...))
  236. ;; ((dc name () props ...)
  237. ;; (dc name () %% () props ...))))
  238. ;;;; Aliases
  239. (define-alias <server-socket> <java.net.ServerSocket>)
  240. (define-alias <socket> <java.net.Socket>)
  241. (define-alias <in> <java.io.InputStreamReader>)
  242. (define-alias <out> <java.io.OutputStreamWriter>)
  243. (define-alias <file> <java.io.File>)
  244. (define-alias <str> <java.lang.String>)
  245. (define-alias <builder> <java.lang.StringBuilder>)
  246. (define-alias <throwable> <java.lang.Throwable>)
  247. (define-alias <source-error> <gnu.text.SourceError>)
  248. (define-alias <module-info> <gnu.expr.ModuleInfo>)
  249. (define-alias <iterable> <java.lang.Iterable>)
  250. (define-alias <thread> <java.lang.Thread>)
  251. (define-alias <queue> <java.util.concurrent.LinkedBlockingQueue>)
  252. (define-alias <exchanger> <java.util.concurrent.Exchanger>)
  253. (define-alias <timeunit> <java.util.concurrent.TimeUnit>)
  254. (define-alias <vm> <com.sun.jdi.VirtualMachine>)
  255. (define-alias <mirror> <com.sun.jdi.Mirror>)
  256. (define-alias <value> <com.sun.jdi.Value>)
  257. (define-alias <thread-ref> <com.sun.jdi.ThreadReference>)
  258. (define-alias <obj-ref> <com.sun.jdi.ObjectReference>)
  259. (define-alias <array-ref> <com.sun.jdi.ArrayReference>)
  260. (define-alias <str-ref> <com.sun.jdi.StringReference>)
  261. (define-alias <meth-ref> <com.sun.jdi.Method>)
  262. (define-alias <class-ref> <com.sun.jdi.ClassType>)
  263. (define-alias <frame> <com.sun.jdi.StackFrame>)
  264. (define-alias <field> <com.sun.jdi.Field>)
  265. (define-alias <local-var> <com.sun.jdi.LocalVariable>)
  266. (define-alias <location> <com.sun.jdi.Location>)
  267. (define-alias <absent-exc> <com.sun.jdi.AbsentInformationException>)
  268. (define-alias <ref-type> <com.sun.jdi.ReferenceType>)
  269. (define-alias <event> <com.sun.jdi.event.Event>)
  270. (define-alias <exception-event> <com.sun.jdi.event.ExceptionEvent>)
  271. (define-alias <step-event> <com.sun.jdi.event.StepEvent>)
  272. (define-alias <env> <gnu.mapping.Environment>)
  273. (define-simple-class <chan> ()
  274. (owner :: <thread> init: (java.lang.Thread:currentThread))
  275. (peer :: <chan>)
  276. (queue :: <queue> init: (<queue>))
  277. (lock init: (<object>)))
  278. ;;;; Entry Points
  279. (df create-swank-server (port-number)
  280. (setup-server port-number announce-port))
  281. (df start-swank (port-file)
  282. (let ((announce (fun ((socket <server-socket>))
  283. (with (f (call-with-output-file port-file))
  284. (format f "~d\n" (! get-local-port socket))))))
  285. (spawn (fun ()
  286. (setup-server 0 announce)))))
  287. (df setup-server ((port-number <int>) announce)
  288. (! set-name (current-thread) "swank")
  289. (let ((s (<server-socket> port-number)))
  290. (announce s)
  291. (let ((c (! accept s)))
  292. (! close s)
  293. (log "connection: ~s\n" c)
  294. (fin (dispatch-events c)
  295. (log "closing socket: ~a\n" s)
  296. (! close c)))))
  297. (df announce-port ((socket <server-socket>))
  298. (log "Listening on port: ~d\n" (! get-local-port socket)))
  299. ;;;; Event dispatcher
  300. (define-variable *the-vm* #f)
  301. (define-variable *last-exception* #f)
  302. (define-variable *last-stacktrace* #f)
  303. ;; FIXME: this needs factorization. But I guess the whole idea of
  304. ;; using bidirectional channels just sucks. Mailboxes owned by a
  305. ;; single thread to which everybody can send are much easier to use.
  306. (df dispatch-events ((s <socket>))
  307. (mlet* ((charset "iso-8859-1")
  308. (ins (<in> (! getInputStream s) charset))
  309. (outs (<out> (! getOutputStream s) charset))
  310. ((in . _) (spawn/chan/catch (fun (c) (reader ins c))))
  311. ((out . _) (spawn/chan/catch (fun (c) (writer outs c))))
  312. ((dbg . _) (spawn/chan/catch vm-monitor))
  313. (user-env (interaction-environment))
  314. (x (seq
  315. (! set-flag user-env #t #|<env>:THREAD_SAFE|# 8)
  316. (! set-flag user-env #f #|<env>:DIRECT_INHERITED_ON_SET|# 16)))
  317. ((listener . _)
  318. (spawn/chan (fun (c) (listener c user-env))))
  319. (inspector #f)
  320. (threads '())
  321. (repl-thread #f)
  322. (extra '())
  323. (vm (let ((vm #f)) (fun () (or vm (rpc dbg `(get-vm)))))))
  324. (while #t
  325. (mlet ((c . event) (recv* (append (list in out dbg listener)
  326. (if inspector (list inspector) '())
  327. (map car threads)
  328. extra)))
  329. ;;(log "event: ~s\n" event)
  330. (mcase (list c event)
  331. ((_ (':emacs-rex ('|swank:debugger-info-for-emacs| from to)
  332. pkg thread id))
  333. (send dbg `(debug-info ,thread ,from ,to ,id)))
  334. ((_ (':emacs-rex ('|swank:throw-to-toplevel|) pkg thread id))
  335. (send dbg `(throw-to-toplevel ,thread ,id)))
  336. ((_ (':emacs-rex ('|swank:sldb-continue|) pkg thread id))
  337. (send dbg `(thread-continue ,thread ,id)))
  338. ((_ (':emacs-rex ('|swank:frame-source-location| frame)
  339. pkg thread id))
  340. (send dbg `(frame-src-loc ,thread ,frame ,id)))
  341. ((_ (':emacs-rex ('|swank:frame-locals-and-catch-tags| frame)
  342. pkg thread id))
  343. (send dbg `(frame-details ,thread ,frame ,id)))
  344. ((_ (':emacs-rex ('|swank:sldb-disassemble| frame)
  345. pkg thread id))
  346. (send dbg `(disassemble-frame ,thread ,frame ,id)))
  347. ((_ (':emacs-rex ('|swank:backtrace| from to) pkg thread id))
  348. (send dbg `(thread-frames ,thread ,from ,to ,id)))
  349. ((_ (':emacs-rex ('|swank:list-threads|) pkg thread id))
  350. (send dbg `(list-threads ,id)))
  351. ((_ (':emacs-rex ('|swank:debug-nth-thread| n) _ _ _))
  352. (send dbg `(debug-nth-thread ,n)))
  353. ((_ (':emacs-rex ('|swank:quit-thread-browser|) _ _ id))
  354. (send dbg `(quit-thread-browser ,id)))
  355. ((_ (':emacs-rex ('|swank:init-inspector| str . _) pkg _ id))
  356. (set inspector (make-inspector user-env (vm)))
  357. (send inspector `(init ,str ,id)))
  358. ((_ (':emacs-rex ('|swank:inspect-frame-var| frame var)
  359. pkg thread id))
  360. (mlet ((im . ex) (chan))
  361. (set inspector (make-inspector user-env (vm)))
  362. (send dbg `(get-local ,ex ,thread ,frame ,var))
  363. (send inspector `(init-mirror ,im ,id))))
  364. ((_ (':emacs-rex ('|swank:inspect-current-condition|) pkg thread id))
  365. (mlet ((im . ex) (chan))
  366. (set inspector (make-inspector user-env (vm)))
  367. (send dbg `(get-exception ,ex ,thread))
  368. (send inspector `(init-mirror ,im ,id))))
  369. ((_ (':emacs-rex ('|swank:inspect-nth-part| n) pkg _ id))
  370. (send inspector `(inspect-part ,n ,id)))
  371. ((_ (':emacs-rex ('|swank:inspector-pop|) pkg _ id))
  372. (send inspector `(pop ,id)))
  373. ((_ (':emacs-rex ('|swank:quit-inspector|) pkg _ id))
  374. (send inspector `(quit ,id)))
  375. ((_ (':emacs-interrupt id))
  376. (let* ((vm (vm))
  377. (t (find-thread id (map cdr threads) repl-thread vm)))
  378. (send dbg `(debug-thread ,t))))
  379. ((_ (':emacs-rex form _ _ id))
  380. (send listener `(,form ,id)))
  381. ((_ ('get-vm c))
  382. (send dbg `(get-vm ,c)))
  383. ((_ ('get-channel c))
  384. (mlet ((im . ex) (chan))
  385. (pushf im extra)
  386. (send c ex)))
  387. ((_ ('forward x))
  388. (send out x))
  389. ((_ ('set-listener x))
  390. (set repl-thread x))
  391. ((_ ('publish-vm vm))
  392. (set *the-vm* vm))
  393. )))))
  394. (df find-thread (id threads listener (vm <vm>))
  395. (cond ((== id ':repl-thread) listener)
  396. ((== id 't) listener
  397. ;;(if (null? threads)
  398. ;; listener
  399. ;; (vm-mirror vm (car threads)))
  400. )
  401. (#t
  402. (let ((f (find-if threads
  403. (fun (t :: <thread>)
  404. (= id (! uniqueID
  405. (as <thread-ref> (vm-mirror vm t)))))
  406. #f)))
  407. (cond (f (vm-mirror vm f))
  408. (#t listener))))))
  409. ;;;; Reader thread
  410. (df reader ((in <in>) (c <chan>))
  411. (! set-name (current-thread) "swank-net-reader")
  412. (let ((rt (gnu.kawa.lispexpr.ReadTable:createInitial))) ; ':' not special
  413. (while #t
  414. (send c (decode-message in rt)))))
  415. (df decode-message ((in <in>) (rt <gnu.kawa.lispexpr.ReadTable>) => <list>)
  416. (let* ((header (read-chunk in 6))
  417. (len (java.lang.Integer:parseInt header 16)))
  418. (call-with-input-string (read-chunk in len)
  419. (fun ((port <input-port>))
  420. (%read port rt)))))
  421. (df read-chunk ((in <in>) (len <int>) => <str>)
  422. (let ((chars (<char[]> length: len)))
  423. (let loop ((offset :: <int> 0))
  424. (cond ((= offset len) (<str> chars))
  425. (#t (let ((count (! read in chars offset (- len offset))))
  426. (assert (not (= count -1)) "partial packet")
  427. (loop (+ offset count))))))))
  428. ;;; FIXME: not thread safe
  429. (df %read ((port <gnu.mapping.InPort>) (table <gnu.kawa.lispexpr.ReadTable>))
  430. (let ((old (gnu.kawa.lispexpr.ReadTable:getCurrent)))
  431. (try-finally
  432. (seq (gnu.kawa.lispexpr.ReadTable:setCurrent table)
  433. (read port))
  434. (gnu.kawa.lispexpr.ReadTable:setCurrent old))))
  435. ;;;; Writer thread
  436. (df writer ((out <out>) (c <chan>))
  437. (! set-name (current-thread) "swank-net-writer")
  438. (while #t
  439. (encode-message out (recv c))))
  440. (df encode-message ((out <out>) (message <list>))
  441. (let ((builder (<builder> (as <int> 512))))
  442. (print-for-emacs message builder)
  443. (! write out (! toString (format "~6,'0x" (! length builder))))
  444. (! write out builder)
  445. (! flush out)))
  446. (df print-for-emacs (obj (out <builder>))
  447. (let ((pr (fun (o) (! append out (! toString (format "~s" o)))))
  448. (++ (fun ((s <string>)) (! append out (! toString s)))))
  449. (cond ((null? obj) (++ "nil"))
  450. ((string? obj) (pr obj))
  451. ((number? obj) (pr obj))
  452. ;;((keyword? obj) (++ ":") (! append out (to-str obj)))
  453. ((symbol? obj) (pr obj))
  454. ((pair? obj)
  455. (++ "(")
  456. (let loop ((obj obj))
  457. (print-for-emacs (car obj) out)
  458. (let ((cdr (cdr obj)))
  459. (cond ((null? cdr) (++ ")"))
  460. ((pair? cdr) (++ " ") (loop cdr))
  461. (#t (++ " . ") (print-for-emacs cdr out) (++ ")"))))))
  462. (#t (error "Unprintable object" obj)))))
  463. ;;;; SLIME-EVAL
  464. (df eval-for-emacs ((form <list>) env (id <int>) (c <chan>))
  465. ;;(! set-uncaught-exception-handler (current-thread)
  466. ;; (<ucex-handler> (fun (t e) (reply-abort c id))))
  467. (reply c (%eval form env) id))
  468. (define-variable *slime-funs*)
  469. (set *slime-funs* (tab))
  470. (df %eval (form env)
  471. (apply (lookup-slimefun (car form) *slime-funs*) env (cdr form)))
  472. (df lookup-slimefun ((name <symbol>) tab)
  473. ;; name looks like '|swank:connection-info|
  474. (let* ((str (symbol->string name))
  475. (sub (substring str 6 (string-length str))))
  476. (or (get tab (string->symbol sub) #f)
  477. (ferror "~a not implemented" sub))))
  478. (define-syntax defslimefun
  479. (syntax-rules ()
  480. ((defslimefun name (args ...) body ...)
  481. (seq
  482. (df name (args ...) body ...)
  483. (put *slime-funs* 'name name)))))
  484. (defslimefun connection-info ((env <env>))
  485. (let ((prop java.lang.System:getProperty))
  486. `(:pid
  487. 0
  488. :style :spawn
  489. :lisp-implementation (:type "Kawa" :name "kawa"
  490. :version ,(scheme-implementation-version))
  491. :machine (:instance ,(prop "java.vm.name") :type ,(prop "os.name")
  492. :version ,(prop "java.runtime.version"))
  493. :features ()
  494. :package (:name "??" :prompt ,(! getName env)))))
  495. ;;;; Listener
  496. (df listener ((c <chan>) (env <env>))
  497. (! set-name (current-thread) "swank-listener")
  498. (log "listener: ~s ~s ~s ~s\n"
  499. (current-thread) ((current-thread):hashCode) c env)
  500. (let ((out (make-swank-outport (rpc c `(get-channel)))))
  501. ;;(set (current-output-port) out)
  502. (let ((vm (as <vm> (rpc c `(get-vm)))))
  503. (send c `(set-listener ,(vm-mirror vm (current-thread))))
  504. (enable-uncaught-exception-events vm))
  505. (rpc c `(get-vm))
  506. (listener-loop c env out)))
  507. (df listener-loop ((c <chan>) (env <env>) port)
  508. (while (not (nul? c))
  509. ;;(log "listener-loop: ~s ~s\n" (current-thread) c)
  510. (mlet ((form id) (recv c))
  511. (let ((restart (fun ()
  512. (close-output-port port)
  513. (reply-abort c id)
  514. (send (car (spawn/chan
  515. (fun (cc)
  516. (listener (recv cc) env))))
  517. c)
  518. (set c #!null))))
  519. (! set-uncaught-exception-handler (current-thread)
  520. (<ucex-handler> (fun (t e) (restart))))
  521. (try-catch
  522. (let* ((val (%eval form env)))
  523. (force-output)
  524. (reply c val id))
  525. (ex <listener-abort>
  526. (let ((flag (java.lang.Thread:interrupted)))
  527. (log "listener-abort: ~s ~a\n" ex flag))
  528. (restart)))))))
  529. (defslimefun create-repl (env #!rest _)
  530. (list "user" "user"))
  531. (defslimefun interactive-eval (env str)
  532. (values-for-echo-area (eval (read-from-string str) env)))
  533. (defslimefun interactive-eval-region (env (s <string>))
  534. (with (port (call-with-input-string s))
  535. (values-for-echo-area
  536. (let next ((result (values)))
  537. (let ((form (read port)))
  538. (cond ((== form #!eof) result)
  539. (#t (next (eval form env)))))))))
  540. (defslimefun listener-eval (env string)
  541. (let* ((form (read-from-string string))
  542. (list (values-to-list (eval form env))))
  543. `(:values ,@(map pprint-to-string list))))
  544. (defslimefun pprint-eval (env string)
  545. (let* ((form (read-from-string string))
  546. (l (values-to-list (eval form env))))
  547. (apply cat (map pprint-to-string l))))
  548. (df call-with-abort (f)
  549. (try-catch (f) (ex <throwable> (exception-message ex))))
  550. (df exception-message ((ex <throwable>))
  551. (typecase ex
  552. (<kawa.lang.NamedException> (! to-string ex))
  553. (<throwable> (format "~a: ~a"
  554. (class-name-sans-package ex)
  555. (! getMessage ex)))))
  556. (df values-for-echo-area (values)
  557. (let ((values (values-to-list values)))
  558. (format "~:[=> ~{~s~^, ~}~;; No values~]" (null? values) values)))
  559. ;;;; Compilation
  560. (defslimefun compile-file-for-emacs (env (filename <str>) load?
  561. #!optional options)
  562. (let ((jar (cat (path-sans-extension (filepath filename)) ".jar")))
  563. (wrap-compilation
  564. (fun ((m <gnu.text.SourceMessages>))
  565. (kawa.lang.CompileFile:read filename m))
  566. jar (if (lisp-bool load?) env #f) #f)))
  567. (df wrap-compilation (f jar env delete?)
  568. (let ((start-time (current-time))
  569. (messages (<gnu.text.SourceMessages>)))
  570. (try-catch
  571. (let ((c (as <gnu.expr.Compilation> (f messages))))
  572. (set (@ explicit c) #t)
  573. (! compile-to-archive c (! get-module c) jar))
  574. (ex <throwable>
  575. (log "error during compilation: ~a\n~a" ex (! getStackTrace ex))
  576. (! error messages (as <char> #\f)
  577. (to-str (exception-message ex)) #!null)))
  578. (log "compilation done.\n")
  579. (let ((success? (zero? (! get-error-count messages))))
  580. (when (and env success?)
  581. (log "loading ...\n")
  582. (eval `(load ,jar) env)
  583. (log "loading ... done.\n"))
  584. (when delete?
  585. (ignore-errors (delete-file jar)))
  586. (let ((end-time (current-time)))
  587. (list ':compilation-result
  588. (compiler-notes-for-emacs messages)
  589. (if success? 't 'nil)
  590. (/ (- end-time start-time) 1000.0))))))
  591. (defslimefun compile-string-for-emacs (env string buffer offset dir)
  592. (wrap-compilation
  593. (fun ((m <gnu.text.SourceMessages>))
  594. (let ((c (as <gnu.expr.Compilation>
  595. (call-with-input-string
  596. string
  597. (fun ((p <gnu.mapping.InPort>))
  598. (! set-path p
  599. (format "~s"
  600. `(buffer ,buffer offset ,offset str ,string)))
  601. (kawa.lang.CompileFile:read p m))))))
  602. (let ((o (@ currentOptions c)))
  603. (! set o "warn-invoke-unknown-method" #t)
  604. (! set o "warn-undefined-variable" #t))
  605. (let ((m (! getModule c)))
  606. (! set-name m (format "<emacs>:~a/~a" buffer (current-time))))
  607. c))
  608. "/tmp/kawa-tmp.zip" env #t))
  609. (df compiler-notes-for-emacs ((messages <gnu.text.SourceMessages>))
  610. (packing (pack)
  611. (do ((e (! get-errors messages) (@ next e)))
  612. ((nul? e))
  613. (pack (source-error>elisp e)))))
  614. (df source-error>elisp ((e <source-error>) => <list>)
  615. (list ':message (to-string (@ message e))
  616. ':severity (case (integer->char (@ severity e))
  617. ((#\e #\f) ':error)
  618. ((#\w) ':warning)
  619. (else ':note))
  620. ':location (error-loc>elisp e)))
  621. (df error-loc>elisp ((e <source-error>))
  622. (cond ((nul? (@ filename e)) `(:error "No source location"))
  623. ((! starts-with (@ filename e) "(buffer ")
  624. (mlet (('buffer b 'offset o 'str s) (read-from-string (@ filename e)))
  625. `(:location (:buffer ,b)
  626. (:position ,(+ o (line>offset (1- (@ line e)) s)
  627. (1- (@ column e))))
  628. nil)))
  629. (#t
  630. `(:location (:file ,(to-string (@ filename e)))
  631. (:line ,(@ line e) ,(1- (@ column e)))
  632. nil))))
  633. (df line>offset ((line <int>) (s <str>) => <int>)
  634. (let ((offset :: <int> 0))
  635. (dotimes (i line)
  636. (set offset (! index-of s (as <char> #\newline) offset))
  637. (assert (>= offset 0))
  638. (set offset (as <int> (+ offset 1))))
  639. (log "line=~a offset=~a\n" line offset)
  640. offset))
  641. (defslimefun load-file (env filename)
  642. (format "Loaded: ~a => ~s" filename (eval `(load ,filename) env)))
  643. ;;;; Completion
  644. (defslimefun simple-completions (env (pattern <str>) _)
  645. (let* ((env (as <gnu.mapping.InheritingEnvironment> env))
  646. (matches (packing (pack)
  647. (let ((iter (! enumerate-all-locations env)))
  648. (while (! has-next iter)
  649. (let ((l (! next-location iter)))
  650. (typecase l
  651. (<gnu.mapping.NamedLocation>
  652. (let ((name (!! get-name get-key-symbol l)))
  653. (when (! starts-with name pattern)
  654. (pack name)))))))))))
  655. `(,matches ,(cond ((null? matches) pattern)
  656. (#t (fold+ common-prefix matches))))))
  657. (df common-prefix ((s1 <str>) (s2 <str>) => <str>)
  658. (let ((limit (min (! length s1) (! length s2))))
  659. (let loop ((i 0))
  660. (cond ((or (= i limit)
  661. (not (== (! char-at s1 i)
  662. (! char-at s2 i))))
  663. (! substring s1 0 i))
  664. (#t (loop (1+ i)))))))
  665. (df fold+ (f list)
  666. (let loop ((s (car list))
  667. (l (cdr list)))
  668. (cond ((null? l) s)
  669. (#t (loop (f s (car l)) (cdr l))))))
  670. ;;; Quit
  671. (defslimefun quit-lisp (env)
  672. (exit))
  673. ;;(defslimefun set-default-directory (env newdir))
  674. ;;;; Dummy defs
  675. (defslimefun buffer-first-change (#!rest y) '())
  676. (defslimefun swank-require (#!rest y) '())
  677. ;;;; arglist
  678. (defslimefun operator-arglist (env name #!rest _)
  679. (mcase (try-catch `(ok ,(eval (read-from-string name) env))
  680. (ex <throwable> 'nil))
  681. (('ok obj)
  682. (mcase (arglist obj)
  683. ('#f 'nil)
  684. ((args rtype)
  685. (format "(~a~{~^ ~a~})~a" name
  686. (map (fun (e)
  687. (if (equal (cadr e) "java.lang.Object") (car e) e))
  688. args)
  689. (if (equal rtype "java.lang.Object")
  690. ""
  691. (format " => ~a" rtype))))))
  692. (_ 'nil)))
  693. (df arglist (obj)
  694. (typecase obj
  695. (<gnu.expr.ModuleMethod>
  696. (let* ((mref (module-method>meth-ref obj)))
  697. (list (mapi (! arguments mref)
  698. (fun ((v <local-var>))
  699. (list (! name v) (! typeName v))))
  700. (! returnTypeName mref))))
  701. (<object> #f)))
  702. ;;;; M-.
  703. (defslimefun find-definitions-for-emacs (env name)
  704. (mcase (try-catch `(ok ,(eval (read-from-string name) env))
  705. (ex <throwable> `(error ,(exception-message ex))))
  706. (('ok obj) (mapi (all-definitions obj)
  707. (fun (d)
  708. `(,(format "~a" d) ,(src-loc>elisp (src-loc d))))))
  709. (('error msg) `((,name (:error ,msg))))))
  710. (define-simple-class <swank-location> (<location>)
  711. (file init: #f)
  712. (line init: #f)
  713. ((*init* file name)
  714. (set (@ file (this)) file)
  715. (set (@ line (this)) line))
  716. ((lineNumber) :: <int> (or line (absent)))
  717. ((lineNumber (s <str>)) :: int (! lineNumber (this)))
  718. ((method) :: <meth-ref> (absent))
  719. ((sourcePath) :: <str> (or file (absent)))
  720. ((sourcePath (s <str>)) :: <str> (! sourcePath (this)))
  721. ((sourceName) :: <str> (absent))
  722. ((sourceName (s <str>)) :: <str> (! sourceName (this)))
  723. ((declaringType) :: <ref-type> (absent))
  724. ((codeIndex) :: <long> -1)
  725. ((virtualMachine) :: <vm> *the-vm*)
  726. ((compareTo o) :: <int>
  727. (typecase o
  728. (<location> (- (! codeIndex (this)) (! codeIndex o))))))
  729. (df absent () (primitive-throw (<absent-exc>)))
  730. (df all-definitions (o)
  731. (typecase o
  732. (<gnu.expr.ModuleMethod> (list o))
  733. (<gnu.expr.GenericProc> (append (mappend all-definitions (gf-methods o))
  734. (let ((s (! get-setter o)))
  735. (if s (all-definitions s) '()))))
  736. (<java.lang.Class> (list o))
  737. (<gnu.mapping.Procedure> (all-definitions (! get-class o)))
  738. (<kawa.lang.Macro> (list o))
  739. (<gnu.bytecode.ObjectType> (all-definitions (! getReflectClass o)))
  740. (<java.lang.Object> '())
  741. ))
  742. (df gf-methods ((f <gnu.expr.GenericProc>))
  743. (let* ((o :: <obj-ref> (vm-mirror *the-vm* f))
  744. (f (! field-by-name (! reference-type o) "methods"))
  745. (ms (vm-demirror *the-vm* (! get-value o f))))
  746. (filter (array-to-list ms) (fun (x) (not (nul? x))))))
  747. (df src-loc (o => <location>)
  748. (typecase o
  749. (<gnu.expr.ModuleMethod> (module-method>src-loc o))
  750. (<gnu.expr.GenericProc> (<swank-location> #f #f))
  751. (<java.lang.Class> (class>src-loc o))
  752. (<kawa.lang.Macro> (<swank-location> #f #f))))
  753. (df module-method>src-loc ((f <gnu.expr.ModuleMethod>))
  754. (! location (module-method>meth-ref f)))
  755. (df module-method>meth-ref ((f <gnu.expr.ModuleMethod>) => <meth-ref>)
  756. (let ((module (! reference-type
  757. (as <obj-ref> (vm-mirror *the-vm* (@ module f)))))
  758. (name (mangled-name f)))
  759. (as <meth-ref> (1st (! methods-by-name module name)))))
  760. (df mangled-name ((f <gnu.expr.ModuleMethod>))
  761. (let ((name (gnu.expr.Compilation:mangleName (! get-name f))))
  762. (if (= (! maxArgs f) -1)
  763. (cat name "$V")
  764. name)))
  765. (df class>src-loc ((c <java.lang.Class>) => <location>)
  766. (let* ((type (! reflectedType (as <com.sun.jdi.ClassObjectReference>
  767. (vm-mirror *the-vm* c))))
  768. (locs (! all-line-locations type)))
  769. (cond ((not (! isEmpty locs)) (1st locs))
  770. (#t (<swank-location> (1st (! source-paths type #!null))
  771. #f)))))
  772. (df src-loc>elisp ((l <location>))
  773. (df src-loc>list ((l <location>))
  774. (list (ignore-errors (! source-name l))
  775. (ignore-errors (! source-path l))
  776. (ignore-errors (! line-number l))))
  777. (mcase (src-loc>list l)
  778. ((name path line)
  779. (cond ((not path)
  780. `(:error ,(call-with-abort (fun () (! source-path l)))))
  781. ((! starts-with (as <str> path) "(buffer ")
  782. (mlet (('buffer b 'offset o 'str s) (read-from-string path))
  783. `(:location (:buffer ,b)
  784. (:position ,(+ o (line>offset line s)))
  785. nil)))
  786. (#t
  787. `(:location ,(or (find-file-in-path name (source-path))
  788. (find-file-in-path path (source-path))
  789. (ferror "Can't find source-path: ~s ~s ~a"
  790. path name (source-path)))
  791. (:line ,(or line -1)) ()))))))
  792. (df src-loc>str ((l <location>))
  793. (cond ((nul? l) "<null-location>")
  794. (#t (format "~a ~a ~a"
  795. (or (ignore-errors (! source-path l))
  796. (ignore-errors (! source-name l))
  797. (ignore-errors (!! name declaring-type l)))
  798. (ignore-errors (!! name method l))
  799. (ignore-errors (! lineNumber l))))))
  800. (df ferror (fstring #!rest args)
  801. (primitive-throw (<java.lang.Error> (to-str (apply format fstring args)))))
  802. ;;;;;; class-path hacking
  803. (df find-file-in-path ((filename <str>) (path <list>))
  804. (let ((f (<file> filename)))
  805. (cond ((! isAbsolute f) `(:file ,filename))
  806. (#t (let ((result #f))
  807. (find-if path (fun (dir)
  808. (let ((x (find-file-in-dir f dir)))
  809. (set result x)))
  810. #f)
  811. result)))))
  812. (df find-file-in-dir ((file <file>) (dir <str>))
  813. (let ((filename (! getPath file)))
  814. (or (let ((child (<file> (<file> dir) filename)))
  815. (and (! exists child)
  816. `(:file ,(! getPath child))))
  817. (try-catch
  818. (and (not (nul? (! getEntry (<java.util.zip.ZipFile> dir) filename)))
  819. `(:zip ,dir ,filename))
  820. (ex <throwable> #f)))))
  821. (define swank-java-source-path
  822. (let ((jre-home (<java.lang.System>:getProperty "java.home")))
  823. (list (! get-path (<file> (! get-parent (<file> jre-home)) "src.zip"))
  824. )))
  825. (df source-path ()
  826. (mlet ((base) (search-path-prop "user.dir"))
  827. (append
  828. (list base)
  829. (map (fun ((s <str>))
  830. (let ((f (<file> s)))
  831. (cond ((! isAbsolute f) s)
  832. (#t (<file> (as <str> base) s):path))))
  833. (class-path))
  834. swank-java-source-path)))
  835. (df class-path ()
  836. (append (search-path-prop "java.class.path")
  837. (search-path-prop "sun.boot.class.path")))
  838. (df search-path-prop ((name <str>))
  839. (array-to-list (! split (java.lang.System:getProperty name)
  840. <file>:pathSeparator)))
  841. ;;;; Disassemble
  842. (defslimefun disassemble-form (env form)
  843. (mcase (read-from-string form)
  844. (('quote name)
  845. (let ((f (eval name env)))
  846. (typecase f
  847. (<gnu.expr.ModuleMethod>
  848. (disassemble (module-method>meth-ref f))))))))
  849. (df disassemble ((mr <meth-ref>) => <str>)
  850. (with-sink #f (fun (out) (disassemble-meth-ref mr out))))
  851. (df disassemble-meth-ref ((mr <meth-ref>) (out <java.io.PrintWriter>))
  852. (let* ((t (! declaring-type mr)))
  853. (disas-header mr out)
  854. (disas-code (! constant-pool t)
  855. (! constant-pool-count t)
  856. (! bytecodes mr)
  857. out)))
  858. (df disas-header ((mr <meth-ref>) (out <java.io.PrintWriter>))
  859. (let* ((++ (fun ((str <str>)) (! write out str)))
  860. (? (fun (flag str) (if flag (++ str)))))
  861. (? (! is-static mr) "static ")
  862. (? (! is-final mr) "final ")
  863. (? (! is-private mr) "private ")
  864. (? (! is-protected mr) "protected ")
  865. (? (! is-public mr) "public ")
  866. (++ (! name mr)) (++ (! signature mr)) (++ "\n")))
  867. (df disas-code ((cpool <byte[]>) (cpoolcount <int>) (bytecode <byte[]>)
  868. (out <java.io.PrintWriter>))
  869. (let* ((ct (<gnu.bytecode.ClassType> "foo"))
  870. (met (! addMethod ct "bar" 0))
  871. (ca (<gnu.bytecode.CodeAttr> met))
  872. (constants (let* ((bs (<java.io.ByteArrayOutputStream>))
  873. (s (<java.io.DataOutputStream> bs)))
  874. (! write-short s cpoolcount)
  875. (! write s cpool)
  876. (! flush s)
  877. (! toByteArray bs))))
  878. (vm-set-slot *the-vm* ct "constants"
  879. (<gnu.bytecode.ConstantPool>
  880. (<java.io.DataInputStream>
  881. (<java.io.ByteArrayInputStream>
  882. constants))))
  883. (! setCode ca bytecode)
  884. (let ((w (<gnu.bytecode.ClassTypeWriter> ct out 0)))
  885. (! print ca w)
  886. (! flush w))))
  887. (df with-sink (sink (f <function>))
  888. (cond ((instance? sink <java.io.PrintWriter>) (f sink))
  889. ((== sink #t) (f (as <java.io.PrintWriter> (current-output-port))))
  890. ((== sink #f)
  891. (let* ((buffer (<java.io.StringWriter>))
  892. (out (<java.io.PrintWriter> buffer)))
  893. (f out)
  894. (! flush out)
  895. (! toString buffer)))
  896. (#t (ferror "Invalid sink designator: ~s" sink))))
  897. (df test-disas ((c <str>) (m <str>))
  898. (let* ((vm (as <vm> *the-vm*))
  899. (c (as <ref-type> (1st (! classes-by-name vm c))))
  900. (m (as <meth-ref> (1st (! methods-by-name c m)))))
  901. (with-sink #f (fun (out) (disassemble-meth-ref m out)))))
  902. ;; (test-disas "java.lang.Class" "toString")
  903. ;;;; Macroexpansion
  904. (defslimefun swank-macroexpand-1 (env s) (%swank-macroexpand s))
  905. (defslimefun swank-macroexpand (env s) (%swank-macroexpand s))
  906. (defslimefun swank-macroexpand-all (env s) (%swank-macroexpand s))
  907. (df %swank-macroexpand (string)
  908. (pprint-to-string (%macroexpand (read-from-string string))))
  909. (df %macroexpand (sexp)
  910. (let ((tr :: kawa.lang.Translator (gnu.expr.Compilation:getCurrent)))
  911. (! rewrite tr `(begin ,sexp))))
  912. ;;;; Inspector
  913. (define-simple-class <inspector-state> ()
  914. (object init: #!null)
  915. (parts :: <java.util.ArrayList> init: (<java.util.ArrayList>) )
  916. (stack :: <list> init: '())
  917. (content :: <list> init: '()))
  918. (df make-inspector (env (vm <vm>) => <chan>)
  919. (car (spawn/chan (fun (c) (inspector c env vm)))))
  920. (df inspector ((c <chan>) env (vm <vm>))
  921. (! set-name (current-thread) "inspector")
  922. (let ((state :: <inspector-state> (<inspector-state>))
  923. (open #t))
  924. (while open
  925. (mcase (recv c)
  926. (('init str id)
  927. (set state (<inspector-state>))
  928. (let ((obj (try-catch (eval (read-from-string str) env)
  929. (ex <throwable> ex))))
  930. (reply c (inspect-object obj state vm) id)))
  931. (('init-mirror cc id)
  932. (set state (<inspector-state>))
  933. (let* ((mirror (recv cc))
  934. (obj (vm-demirror vm mirror)))
  935. (reply c (inspect-object obj state vm) id)))
  936. (('inspect-part n id)
  937. (let ((part (! get (@ parts state) n)))
  938. (reply c (inspect-object part state vm) id)))
  939. (('pop id)
  940. (reply c (inspector-pop state vm) id))
  941. (('quit id)
  942. (reply c 'nil id)
  943. (set open #f))))))
  944. (df inspect-object (obj (state <inspector-state>) (vm <vm>))
  945. (set (@ object state) obj)
  946. (set (@ parts state) (<java.util.ArrayList>))
  947. (pushf obj (@ stack state))
  948. (set (@ content state) (inspector-content
  949. `("class: " (:value ,(! getClass obj)) "\n"
  950. ,@(inspect obj vm))
  951. state))
  952. (cond ((nul? obj) (list ':title "#!null" ':id 0 ':content `()))
  953. (#t
  954. (list ':title (pprint-to-string obj)
  955. ':id (assign-index obj state)
  956. ':content (let ((c (@ content state)))
  957. (content-range c 0 (len c)))))))
  958. (df inspect (obj vm)
  959. (let* ((obj (as <obj-ref> (vm-mirror vm obj))))
  960. (packing (pack)
  961. (typecase obj
  962. (<array-ref>
  963. (let ((i 0))
  964. (iter (! getValues obj)
  965. (fun ((v <value>))
  966. (pack (format "~d: " i))
  967. (set i (1+ i))
  968. (pack `(:value ,(vm-demirror vm v)))
  969. (pack "\n")))))
  970. (<obj-ref>
  971. (let* ((type (! referenceType obj))
  972. (fields (! allFields type))
  973. (values (! getValues obj fields)))
  974. (iter fields
  975. (fun ((f <field>))
  976. (let ((val (as <value> (! get values f))))
  977. (when (! is-static f)
  978. (pack "static "))
  979. (pack (! name f)) (pack ": ")
  980. (pack `(:value ,(vm-demirror vm val)))
  981. (pack "\n"))))))))))
  982. (df inspector-content (content (state <inspector-state>))
  983. (map (fun (part)
  984. (mcase part
  985. ((':value val)
  986. `(:value ,(pprint-to-string val) ,(assign-index val state)))
  987. (x (to-string x))))
  988. content))
  989. (df assign-index (obj (state <inspector-state>) => <int>)
  990. (! add (@ parts state) obj)
  991. (1- (! size (@ parts state))))
  992. (df content-range (l start end)
  993. (let* ((len (length l)) (end (min len end)))
  994. (list (subseq l start end) len start end)))
  995. (df inspector-pop ((state <inspector-state>) vm)
  996. (cond ((<= 2 (len (@ stack state)))
  997. (let ((obj (cadr (@ stack state))))
  998. (set (@ stack state) (cddr (@ stack state)))
  999. (inspect-object obj state vm)))
  1000. (#t 'nil)))
  1001. ;;;; IO redirection
  1002. (define-simple-class <swank-writer> (<java.io.Writer>)
  1003. (q :: <queue> init: (<queue> (as <int> 100)))
  1004. ((*init*) (invoke-special <java.io.Writer> (this) '*init*))
  1005. ((write (buffer <char[]>) (from <int>) (to <int>)) :: <void>
  1006. (synchronized (this)
  1007. (assert (not (== q #!null)))
  1008. (! put q `(write ,(<str> buffer from to)))))
  1009. ((close) :: <void>
  1010. (synchronized (this)
  1011. (! put q 'close)
  1012. (set! q #!null)))
  1013. ((flush) :: <void>
  1014. (synchronized (this)
  1015. (assert (not (== q #!null)))
  1016. (let ((ex (<exchanger>)))
  1017. (! put q `(flush ,ex))
  1018. (! exchange ex #!null)))))
  1019. (df swank-writer ((in <chan>) (q <queue>))
  1020. (! set-name (current-thread) "swank-redirect-thread")
  1021. (let* ((out (as <chan> (recv in)))
  1022. (builder (<builder>))
  1023. (flush (fun ()
  1024. (unless (zero? (! length builder))
  1025. (send out `(forward (:write-string ,(<str> builder))))
  1026. (set! builder:length 0)))) ; pure magic
  1027. (closed #f))
  1028. (while (not closed)
  1029. (mcase (! poll q 200 <timeunit>:MILLISECONDS)
  1030. ('#!null (flush))
  1031. (('write s)
  1032. (! append builder (as <str> s))
  1033. (when (> (! length builder) 4000)
  1034. (flush)))
  1035. (('flush ex)
  1036. (flush)
  1037. (! exchange (as <exchanger> ex) #!null))
  1038. ('close
  1039. (set closed #t)
  1040. (flush))))))
  1041. (df make-swank-outport ((out <chan>))
  1042. (let ((w (<swank-writer>)))
  1043. (mlet ((in . _) (spawn/chan (fun (c) (swank-writer c (@ q w)))))
  1044. (send in out))
  1045. (<gnu.mapping.OutPort> w #t #t)))
  1046. ;;;; Monitor
  1047. (df vm-monitor ((c <chan>))
  1048. (! set-name (current-thread) "swank-vm-monitor")
  1049. (let ((vm (vm-attach)))
  1050. (log-vm-props vm)
  1051. ;;(enable-uncaught-exception-events vm)
  1052. (mlet* (((ev . _) (spawn/chan/catch
  1053. (fun (c)
  1054. (let ((q (! eventQueue vm)))
  1055. (while #t
  1056. (send c `(vm-event ,(to-list (! remove q)))))))))
  1057. (to-string (vm-to-string vm))
  1058. (state (tab)))
  1059. (send c `(publish-vm ,vm))
  1060. (while #t
  1061. (mcase (recv* (list c ev))
  1062. ((_ . ('get-vm cc))
  1063. (send cc vm))
  1064. ((,c . ('debug-info thread from to id))
  1065. (reply c (debug-info thread from to state) id))
  1066. ((,c . ('throw-to-toplevel thread id))
  1067. (set state (throw-to-toplevel thread id c state)))
  1068. ((,c . ('thread-continue thread id))
  1069. (set state (thread-continue thread id c state)))
  1070. ((,c . ('frame-src-loc thread frame id))
  1071. (reply c (frame-src-loc thread frame state) id))
  1072. ((,c . ('frame-details thread frame id))
  1073. (reply c (list (frame-locals thread frame state) '()) id))
  1074. ((,c . ('disassemble-frame thread frame id))
  1075. (reply c (disassemble-frame thread frame state) id))
  1076. ((,c . ('thread-frames thread from to id))
  1077. (reply c (thread-frames thread from to state) id))
  1078. ((,c . ('list-threads id))
  1079. (reply c (list-threads vm state) id))
  1080. ((,c . ('debug-thread ref))
  1081. (set state (debug-thread ref state c)))
  1082. ((,c . ('debug-nth-thread n))
  1083. (let ((t (nth (get state 'all-threads #f) n)))
  1084. ;;(log "thread ~d : ~a\n" n t)
  1085. (set state (debug-thread t state c))))
  1086. ((,c . ('quit-thread-browser id))
  1087. (reply c 't id)
  1088. (set state (del state 'all-threads)))
  1089. ((,ev . ('vm-event es))
  1090. ;;(log "vm-events: len=~a\n" (len es))
  1091. (for (((e <event>) (as <list> es)))
  1092. (set state (process-vm-event e c state))))
  1093. ((_ . ('get-exception from tid))
  1094. (mlet ((_ _ es) (get state tid #f))
  1095. (send from (let ((e (car es)))
  1096. (typecase e
  1097. (<exception-event> (! exception e))
  1098. (<event> e))))))
  1099. ((_ . ('get-local rc tid frame var))
  1100. (send rc (frame-local-var tid frame var state)))
  1101. )))))
  1102. (df reply ((c <chan>) value id)
  1103. (send c `(forward (:return (:ok ,value) ,id))))
  1104. (df reply-abort ((c <chan>) id)
  1105. (send c `(forward (:return (:abort) ,id))))
  1106. (df process-vm-event ((e <event>) (c <chan>) state)
  1107. (log "vm-event: ~s\n" e)
  1108. (typecase e
  1109. (<exception-event>
  1110. (log "exception-location: ~s\n" (src-loc>str (! location e)))
  1111. (log "exception-catch-location: ~s\n" (src-loc>str (! catch-location e)))
  1112. (let ((l (! catch-location e)))
  1113. (cond ((or (nul? l)
  1114. ;; (member (! source-path l) '("gnu/expr/ModuleExp.java"))
  1115. )
  1116. (process-exception e c state))
  1117. (#t
  1118. (let* ((t (! thread e))
  1119. (r (! request e))
  1120. (ex (! exception e)))
  1121. (unless (eq? *last-exception* ex)
  1122. (set *last-exception* ex)
  1123. (set *last-stacktrace* (copy-stack t)))
  1124. (! resume t))
  1125. state))))
  1126. (<step-event>
  1127. (let* ((r (! request e))
  1128. (k (! get-property r 'continuation)))
  1129. (! disable r)
  1130. (log "k: ~s\n" k)
  1131. (k e))
  1132. state)))
  1133. (df process-exception ((e <exception-event>) (c <chan>) state)
  1134. (let* ((tref (! thread e))
  1135. (tid (! uniqueID tref))
  1136. (s (get state tid #f)))
  1137. (mcase s
  1138. ('#f
  1139. ;; XXX redundant in debug-thread
  1140. (let* ((level 1)
  1141. (state (put state tid (list tref level (list e)))))
  1142. (send c `(forward (:debug ,tid ,level
  1143. ,@(debug-info tid 0 15 state))))
  1144. (send c `(forward (:debug-activate ,tid ,level)))
  1145. state))
  1146. ((_ level exs)
  1147. (send c `(forward (:debug-activate ,(! uniqueID tref) ,level)))
  1148. (put state tid (list tref (1+ level) (cons e exs)))))))
  1149. (define-simple-class <faked-frame> ()
  1150. (loc :: <location>)
  1151. (args)
  1152. (names)
  1153. (values :: <java.util.Map>)
  1154. (self)
  1155. ((*init* (loc <location>) args names (values <java.util.Map>) self)
  1156. (set (@ loc (this)) loc)
  1157. (set (@ args (this)) args)
  1158. (set (@ names (this)) names)
  1159. (set (@ values (this)) values)
  1160. (set (@ self (this)) self))
  1161. ((toString) :: <str>
  1162. (format "#<ff ~a>" (src-loc>str loc))))
  1163. (df copy-stack ((t <thread-ref>))
  1164. (packing (pack)
  1165. (iter (! frames t)
  1166. (fun ((f <frame>))
  1167. (let ((vars (ignore-errors (! visibleVariables f))))
  1168. (pack (<faked-frame>
  1169. (or (ignore-errors (! location f)) #!null)
  1170. (ignore-errors (! getArgumentValues f))
  1171. (or vars #!null)
  1172. (or (and vars (ignore-errors (! get-values f vars)))
  1173. #!null)
  1174. (ignore-errors (! thisObject f)))))))))
  1175. (define-simple-class <listener-abort> (<java.lang.Throwable>)
  1176. ((abort) :: void
  1177. (primitive-throw (this))
  1178. #!void))
  1179. (define-simple-class <break-event> (<com.sun.jdi.event.Event>)
  1180. (thread :: <thread-ref>)
  1181. ((*init* (thread :: <thread-ref>)) (set (@ thread (this)) thread))
  1182. ((request) :: <com.sun.jdi.request.EventRequest> #!null)
  1183. ((virtualMachine) :: <vm> (! virtualMachine thread)))
  1184. (df log-vm-props ((vm <vm>))
  1185. (letrec-syntax ((p (syntax-rules ()
  1186. ((p name) (log "~s: ~s\n" 'name (! name vm)))))
  1187. (p* (syntax-rules ()
  1188. ((p* n ...) (seq (p n) ...)))))
  1189. (p* canBeModified
  1190. canRedefineClasses
  1191. canAddMethod
  1192. canUnrestrictedlyRedefineClasses
  1193. canGetBytecodes
  1194. canGetConstantPool
  1195. canGetSyntheticAttribute
  1196. canGetSourceDebugExtension
  1197. canPopFrames
  1198. canForceEarlyReturn
  1199. canGetMethodReturnValues
  1200. canGetInstanceInfo
  1201. )))
  1202. ;;;;; Debugger
  1203. (df debug-thread ((tref <thread-ref>) state (c <chan>))
  1204. (! suspend tref)
  1205. (let* ((ev (<break-event> tref))
  1206. (id (! uniqueID tref))
  1207. (level 1)
  1208. (state (put state id (list tref level (list ev)))))
  1209. (send c `(forward (:debug ,id ,level ,@(debug-info id 0 10 state))))
  1210. (send c `(forward (:debug-activate ,id ,level)))
  1211. state))
  1212. (df debug-info ((tid <int>) (from <int>) to state)
  1213. (mlet ((thread-ref level evs) (get state tid #f))
  1214. (let* ((tref (as <thread-ref> thread-ref))
  1215. (vm (! virtualMachine tref))
  1216. (ev (as <event> (car evs)))
  1217. (ex (typecase ev
  1218. (<exception-event> (! exception ev))
  1219. (<break-event> (<java.lang.Exception> "Interrupt"))))
  1220. (desc (typecase ex
  1221. (<obj-ref>
  1222. ;;(log "ex: ~a ~a\n" ex (vm-demirror vm ex))
  1223. (! toString (vm-demirror vm ex)))
  1224. (<java.lang.Exception> (! toString ex))))
  1225. (type (format " [type ~a]"
  1226. (typecase ex
  1227. (<obj-ref> (! name (! referenceType ex)))
  1228. (<object> (!! getName getClass ex)))))
  1229. (bt (thread-frames tid from to state)))
  1230. `((,desc ,type nil) (("quit" "terminate current thread")) ,bt ()))))
  1231. (df thread-frames ((tid <int>) (from <int>) to state)
  1232. (mlet ((thread level evs) (get state tid #f))
  1233. (let* ((thread (as <thread-ref> thread))
  1234. (fcount (! frameCount thread))
  1235. (stacktrace (event-stacktrace (car evs)))

Large files files are truncated, but you can click here to view the full file