Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

847 lines
29 KiB

4 years ago
  1. ;;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;*"; -*-
  2. ;;;
  3. ;;; swank-abcl.lisp --- Armedbear CL specific code for SLIME.
  4. ;;;
  5. ;;; Adapted from swank-acl.lisp, Andras Simon, 2004
  6. ;;;
  7. ;;; This code has been placed in the Public Domain. All warranties
  8. ;;; are disclaimed.
  9. ;;;
  10. (defpackage swank/abcl
  11. (:use cl swank/backend))
  12. (in-package swank/abcl)
  13. (eval-when (:compile-toplevel :load-toplevel :execute)
  14. (require :collect) ;just so that it doesn't spoil the flying letters
  15. (require :pprint)
  16. (require :gray-streams)
  17. (assert (>= (read-from-string (subseq (lisp-implementation-version) 0 4))
  18. 0.22)
  19. () "This file needs ABCL version 0.22 or newer"))
  20. (defimplementation gray-package-name ()
  21. "GRAY-STREAMS")
  22. ;; FIXME: switch to shared Gray stream implementation when bugs are
  23. ;; fixed in ABCL. See: http://abcl.org/trac/ticket/373.
  24. (progn
  25. (defimplementation make-output-stream (write-string)
  26. (ext:make-slime-output-stream write-string))
  27. (defimplementation make-input-stream (read-string)
  28. (ext:make-slime-input-stream read-string
  29. (make-synonym-stream '*standard-output*))))
  30. (defimplementation call-with-compilation-hooks (function)
  31. (funcall function))
  32. ;;; swank-mop
  33. ;;dummies and definition
  34. (defclass standard-slot-definition ()())
  35. ;(defun class-finalized-p (class) t)
  36. (defun slot-definition-documentation (slot)
  37. (declare (ignore slot))
  38. #+nil (documentation slot 't))
  39. (defun slot-definition-type (slot)
  40. (declare (ignore slot))
  41. t)
  42. (defun class-prototype (class)
  43. (declare (ignore class))
  44. nil)
  45. (defun generic-function-declarations (gf)
  46. (declare (ignore gf))
  47. nil)
  48. (defun specializer-direct-methods (spec)
  49. (mop:class-direct-methods spec))
  50. (defun slot-definition-name (slot)
  51. (mop:slot-definition-name slot))
  52. (defun class-slots (class)
  53. (mop:class-slots class))
  54. (defun method-generic-function (method)
  55. (mop:method-generic-function method))
  56. (defun method-function (method)
  57. (mop:method-function method))
  58. (defun slot-boundp-using-class (class object slotdef)
  59. (declare (ignore class))
  60. (system::slot-boundp object (slot-definition-name slotdef)))
  61. (defun slot-value-using-class (class object slotdef)
  62. (declare (ignore class))
  63. (system::slot-value object (slot-definition-name slotdef)))
  64. (import-to-swank-mop
  65. '( ;; classes
  66. cl:standard-generic-function
  67. standard-slot-definition ;;dummy
  68. cl:method
  69. cl:standard-class
  70. #+#.(swank/backend:with-symbol 'compute-applicable-methods-using-classes
  71. 'mop)
  72. mop:compute-applicable-methods-using-classes
  73. ;; standard-class readers
  74. mop:class-default-initargs
  75. mop:class-direct-default-initargs
  76. mop:class-direct-slots
  77. mop:class-direct-subclasses
  78. mop:class-direct-superclasses
  79. mop:eql-specializer
  80. mop:class-finalized-p
  81. mop:finalize-inheritance
  82. cl:class-name
  83. mop:class-precedence-list
  84. class-prototype ;;dummy
  85. class-slots
  86. specializer-direct-methods
  87. ;; eql-specializer accessors
  88. mop::eql-specializer-object
  89. ;; generic function readers
  90. mop:generic-function-argument-precedence-order
  91. generic-function-declarations ;;dummy
  92. mop:generic-function-lambda-list
  93. mop:generic-function-methods
  94. mop:generic-function-method-class
  95. mop:generic-function-method-combination
  96. mop:generic-function-name
  97. ;; method readers
  98. method-generic-function
  99. method-function
  100. mop:method-lambda-list
  101. mop:method-specializers
  102. mop:method-qualifiers
  103. ;; slot readers
  104. mop:slot-definition-allocation
  105. slot-definition-documentation ;;dummy
  106. mop:slot-definition-initargs
  107. mop:slot-definition-initform
  108. mop:slot-definition-initfunction
  109. slot-definition-name
  110. slot-definition-type ;;dummy
  111. mop:slot-definition-readers
  112. mop:slot-definition-writers
  113. slot-boundp-using-class
  114. slot-value-using-class
  115. mop:slot-makunbound-using-class))
  116. ;;;; TCP Server
  117. (defimplementation preferred-communication-style ()
  118. :spawn)
  119. (defimplementation create-socket (host port &key backlog)
  120. (ext:make-server-socket port))
  121. (defimplementation local-port (socket)
  122. (java:jcall (java:jmethod "java.net.ServerSocket" "getLocalPort") socket))
  123. (defimplementation close-socket (socket)
  124. (ext:server-socket-close socket))
  125. (defimplementation accept-connection (socket
  126. &key external-format buffering timeout)
  127. (declare (ignore buffering timeout))
  128. (ext:get-socket-stream (ext:socket-accept socket)
  129. :element-type (if external-format
  130. 'character
  131. '(unsigned-byte 8))
  132. :external-format (or external-format :default)))
  133. ;;;; UTF8
  134. ;; faster please!
  135. (defimplementation string-to-utf8 (s)
  136. (jbytes-to-octets
  137. (java:jcall
  138. (java:jmethod "java.lang.String" "getBytes" "java.lang.String")
  139. s
  140. "UTF8")))
  141. (defimplementation utf8-to-string (u)
  142. (java:jnew
  143. (java:jconstructor "org.armedbear.lisp.SimpleString"
  144. "java.lang.String")
  145. (java:jnew (java:jconstructor "java.lang.String" "[B" "java.lang.String")
  146. (octets-to-jbytes u)
  147. "UTF8")))
  148. (defun octets-to-jbytes (octets)
  149. (declare (type octets (simple-array (unsigned-byte 8) (*))))
  150. (let* ((len (length octets))
  151. (bytes (java:jnew-array "byte" len)))
  152. (loop for byte across octets
  153. for i from 0
  154. do (java:jstatic (java:jmethod "java.lang.reflect.Array" "setByte"
  155. "java.lang.Object" "int" "byte")
  156. "java.lang.relect.Array"
  157. bytes i byte))
  158. bytes))
  159. (defun jbytes-to-octets (jbytes)
  160. (let* ((len (java:jarray-length jbytes))
  161. (octets (make-array len :element-type '(unsigned-byte 8))))
  162. (loop for i from 0 below len
  163. for jbyte = (java:jarray-ref jbytes i)
  164. do (setf (aref octets i) jbyte))
  165. octets))
  166. ;;;; External formats
  167. (defvar *external-format-to-coding-system*
  168. '((:iso-8859-1 "latin-1" "iso-latin-1" "iso-8859-1")
  169. ((:iso-8859-1 :eol-style :lf)
  170. "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix")
  171. (:utf-8 "utf-8")
  172. ((:utf-8 :eol-style :lf) "utf-8-unix")
  173. (:euc-jp "euc-jp")
  174. ((:euc-jp :eol-style :lf) "euc-jp-unix")
  175. (:us-ascii "us-ascii")
  176. ((:us-ascii :eol-style :lf) "us-ascii-unix")))
  177. (defimplementation find-external-format (coding-system)
  178. (car (rassoc-if (lambda (x)
  179. (member coding-system x :test #'equal))
  180. *external-format-to-coding-system*)))
  181. ;;;; Unix signals
  182. (defimplementation getpid ()
  183. (handler-case
  184. (let* ((runtime
  185. (java:jstatic "getRuntime" "java.lang.Runtime"))
  186. (command
  187. (java:jnew-array-from-array
  188. "java.lang.String" #("sh" "-c" "echo $PPID")))
  189. (runtime-exec-jmethod
  190. ;; Complicated because java.lang.Runtime.exec() is
  191. ;; overloaded on a non-primitive type (array of
  192. ;; java.lang.String), so we have to use the actual
  193. ;; parameter instance to get java.lang.Class
  194. (java:jmethod "java.lang.Runtime" "exec"
  195. (java:jcall
  196. (java:jmethod "java.lang.Object" "getClass")
  197. command)))
  198. (process
  199. (java:jcall runtime-exec-jmethod runtime command))
  200. (output
  201. (java:jcall (java:jmethod "java.lang.Process" "getInputStream")
  202. process)))
  203. (java:jcall (java:jmethod "java.lang.Process" "waitFor")
  204. process)
  205. (loop :with b :do
  206. (setq b
  207. (java:jcall (java:jmethod "java.io.InputStream" "read")
  208. output))
  209. :until (member b '(-1 #x0a)) ; Either EOF or LF
  210. :collecting (code-char b) :into result
  211. :finally (return
  212. (parse-integer (coerce result 'string)))))
  213. (t () 0)))
  214. (defimplementation lisp-implementation-type-name ()
  215. "armedbear")
  216. (defimplementation set-default-directory (directory)
  217. (let ((dir (sys::probe-directory directory)))
  218. (when dir (setf *default-pathname-defaults* dir))
  219. (namestring dir)))
  220. ;;;; Misc
  221. (defimplementation arglist (fun)
  222. (cond ((symbolp fun)
  223. (multiple-value-bind (arglist present)
  224. (sys::arglist fun)
  225. (when (and (not present)
  226. (fboundp fun)
  227. (typep (symbol-function fun)
  228. 'standard-generic-function))
  229. (setq arglist
  230. (mop::generic-function-lambda-list (symbol-function fun))
  231. present
  232. t))
  233. (if present arglist :not-available)))
  234. (t :not-available)))
  235. (defimplementation function-name (function)
  236. (nth-value 2 (function-lambda-expression function)))
  237. (defimplementation macroexpand-all (form &optional env)
  238. (ext:macroexpand-all form env))
  239. (defimplementation collect-macro-forms (form &optional env)
  240. ;; Currently detects only normal macros, not compiler macros.
  241. (declare (ignore env))
  242. (with-collected-macro-forms (macro-forms)
  243. (handler-bind ((warning #'muffle-warning))
  244. (ignore-errors
  245. (compile nil `(lambda () ,(macroexpand-all form env)))))
  246. (values macro-forms nil)))
  247. (defimplementation describe-symbol-for-emacs (symbol)
  248. (let ((result '()))
  249. (flet ((doc (kind &optional (sym symbol))
  250. (or (documentation sym kind) :not-documented))
  251. (maybe-push (property value)
  252. (when value
  253. (setf result (list* property value result)))))
  254. (maybe-push
  255. :variable (when (boundp symbol)
  256. (doc 'variable)))
  257. (when (fboundp symbol)
  258. (maybe-push
  259. (cond ((macro-function symbol) :macro)
  260. ((special-operator-p symbol) :special-operator)
  261. ((typep (fdefinition symbol) 'generic-function)
  262. :generic-function)
  263. (t :function))
  264. (doc 'function)))
  265. (maybe-push
  266. :class (if (find-class symbol nil)
  267. (doc 'class)))
  268. result)))
  269. (defimplementation describe-definition (symbol namespace)
  270. (ecase namespace
  271. ((:variable :macro)
  272. (describe symbol))
  273. ((:function :generic-function)
  274. (describe (symbol-function symbol)))
  275. (:class
  276. (describe (find-class symbol)))))
  277. (defimplementation describe-definition (symbol namespace)
  278. (ecase namespace
  279. (:variable
  280. (describe symbol))
  281. ((:function :generic-function)
  282. (describe (symbol-function symbol)))
  283. (:class
  284. (describe (find-class symbol)))))
  285. ;;;; Debugger
  286. ;; Copied from swank-sbcl.lisp.
  287. ;;
  288. ;; Notice that *INVOKE-DEBUGGER-HOOK* is tried before *DEBUGGER-HOOK*,
  289. ;; so we have to make sure that the latter gets run when it was
  290. ;; established locally by a user (i.e. changed meanwhile.)
  291. (defun make-invoke-debugger-hook (hook)
  292. (lambda (condition old-hook)
  293. (if *debugger-hook*
  294. (funcall *debugger-hook* condition old-hook)
  295. (funcall hook condition old-hook))))
  296. (defimplementation call-with-debugger-hook (hook fun)
  297. (let ((*debugger-hook* hook)
  298. (sys::*invoke-debugger-hook* (make-invoke-debugger-hook hook)))
  299. (funcall fun)))
  300. (defimplementation install-debugger-globally (function)
  301. (setq *debugger-hook* function)
  302. (setq sys::*invoke-debugger-hook* (make-invoke-debugger-hook function)))
  303. (defvar *sldb-topframe*)
  304. (defimplementation call-with-debugging-environment (debugger-loop-fn)
  305. (let* ((magic-token (intern "SWANK-DEBUGGER-HOOK" 'swank))
  306. (*sldb-topframe*
  307. (second (member magic-token (sys:backtrace)
  308. :key (lambda (frame)
  309. (first (sys:frame-to-list frame)))))))
  310. (funcall debugger-loop-fn)))
  311. (defun backtrace (start end)
  312. "A backtrace without initial SWANK frames."
  313. (let ((backtrace (sys:backtrace)))
  314. (subseq (or (member *sldb-topframe* backtrace) backtrace)
  315. start end)))
  316. (defun nth-frame (index)
  317. (nth index (backtrace 0 nil)))
  318. (defimplementation compute-backtrace (start end)
  319. (let ((end (or end most-positive-fixnum)))
  320. (backtrace start end)))
  321. (defimplementation print-frame (frame stream)
  322. (write-string (sys:frame-to-string frame)
  323. stream))
  324. ;;; Sorry, but can't seem to declare DEFIMPLEMENTATION under FLET.
  325. ;;; --ME 20150403
  326. (defun nth-frame-list (index)
  327. (java:jcall "toLispList" (nth-frame index)))
  328. (defun match-lambda (operator values)
  329. (jvm::match-lambda-list
  330. (multiple-value-list
  331. (jvm::parse-lambda-list (ext:arglist operator)))
  332. values))
  333. (defimplementation frame-locals (index)
  334. (loop
  335. :for id :upfrom 0
  336. :with frame = (nth-frame-list index)
  337. :with operator = (first frame)
  338. :with values = (rest frame)
  339. :with arglist = (if (and operator (consp values) (not (null values)))
  340. (handler-case
  341. (match-lambda operator values)
  342. (jvm::lambda-list-mismatch (e)
  343. :lambda-list-mismatch))
  344. :not-available)
  345. :for value :in values
  346. :collecting (list
  347. :name (if (not (keywordp arglist))
  348. (first (nth id arglist))
  349. (format nil "arg~A" id))
  350. :id id
  351. :value value)))
  352. (defimplementation frame-var-value (index id)
  353. (elt (rest (java:jcall "toLispList" (nth-frame index))) id))
  354. #+nil
  355. (defimplementation disassemble-frame (index)
  356. (disassemble (debugger:frame-function (nth-frame index))))
  357. (defimplementation frame-source-location (index)
  358. (let ((frame (nth-frame index)))
  359. (or (source-location (nth-frame index))
  360. `(:error ,(format nil "No source for frame: ~a" frame)))))
  361. #+nil
  362. (defimplementation eval-in-frame (form frame-number)
  363. (debugger:eval-form-in-context
  364. form
  365. (debugger:environment-of-frame (nth-frame frame-number))))
  366. #+nil
  367. (defimplementation return-from-frame (frame-number form)
  368. (let ((frame (nth-frame frame-number)))
  369. (multiple-value-call #'debugger:frame-return
  370. frame (debugger:eval-form-in-context
  371. form
  372. (debugger:environment-of-frame frame)))))
  373. ;;; XXX doesn't work for frames with arguments
  374. #+nil
  375. (defimplementation restart-frame (frame-number)
  376. (let ((frame (nth-frame frame-number)))
  377. (debugger:frame-retry frame (debugger:frame-function frame))))
  378. ;;;; Compiler hooks
  379. (defvar *buffer-name* nil)
  380. (defvar *buffer-start-position*)
  381. (defvar *buffer-string*)
  382. (defvar *compile-filename*)
  383. (defvar *abcl-signaled-conditions*)
  384. (defun handle-compiler-warning (condition)
  385. (let ((loc (when (and jvm::*compile-file-pathname*
  386. system::*source-position*)
  387. (cons jvm::*compile-file-pathname* system::*source-position*))))
  388. ;; filter condition signaled more than once.
  389. (unless (member condition *abcl-signaled-conditions*)
  390. (push condition *abcl-signaled-conditions*)
  391. (signal 'compiler-condition
  392. :original-condition condition
  393. :severity :warning
  394. :message (format nil "~A" condition)
  395. :location (cond (*buffer-name*
  396. (make-location
  397. (list :buffer *buffer-name*)
  398. (list :offset *buffer-start-position* 0)))
  399. (loc
  400. (destructuring-bind (file . pos) loc
  401. (make-location
  402. (list :file (namestring (truename file)))
  403. (list :position (1+ pos)))))
  404. (t
  405. (make-location
  406. (list :file (namestring *compile-filename*))
  407. (list :position 1))))))))
  408. (defimplementation swank-compile-file (input-file output-file
  409. load-p external-format
  410. &key policy)
  411. (declare (ignore external-format policy))
  412. (let ((jvm::*resignal-compiler-warnings* t)
  413. (*abcl-signaled-conditions* nil))
  414. (handler-bind ((warning #'handle-compiler-warning))
  415. (let ((*buffer-name* nil)
  416. (*compile-filename* input-file))
  417. (multiple-value-bind (fn warn fail)
  418. (compile-file input-file :output-file output-file)
  419. (values fn warn
  420. (and fn load-p
  421. (not (load fn)))))))))
  422. (defimplementation swank-compile-string (string &key buffer position filename
  423. policy)
  424. (declare (ignore filename policy))
  425. (let ((jvm::*resignal-compiler-warnings* t)
  426. (*abcl-signaled-conditions* nil))
  427. (handler-bind ((warning #'handle-compiler-warning))
  428. (let ((*buffer-name* buffer)
  429. (*buffer-start-position* position)
  430. (*buffer-string* string)
  431. (sys::*source* (make-pathname :device "emacs-buffer" :name buffer))
  432. (sys::*source-position* position))
  433. (funcall (compile nil (read-from-string
  434. (format nil "(~S () ~A)" 'lambda string))))
  435. t))))
  436. #|
  437. ;;;; Definition Finding
  438. (defun find-fspec-location (fspec type)
  439. (let ((file (excl::fspec-pathname fspec type)))
  440. (etypecase file
  441. (pathname
  442. (let ((start (scm:find-definition-in-file fspec type file)))
  443. (make-location (list :file (namestring (truename file)))
  444. (if start
  445. (list :position (1+ start))
  446. (list :function-name (string fspec))))))
  447. ((member :top-level)
  448. (list :error (format nil "Defined at toplevel: ~A" fspec)))
  449. (null
  450. (list :error (format nil "Unkown source location for ~A" fspec))))))
  451. (defun fspec-definition-locations (fspec)
  452. (let ((defs (excl::find-multiple-definitions fspec)))
  453. (loop for (fspec type) in defs
  454. collect (list fspec (find-fspec-location fspec type)))))
  455. (defimplementation find-definitions (symbol)
  456. (fspec-definition-locations symbol))
  457. |#
  458. (defgeneric source-location (object))
  459. (defmethod source-location ((symbol symbol))
  460. (when (pathnamep (ext:source-pathname symbol))
  461. (let ((pos (ext:source-file-position symbol))
  462. (path (namestring (ext:source-pathname symbol))))
  463. (cond ((ext:pathname-jar-p path)
  464. `(:location
  465. ;; strip off "jar:file:" = 9 characters
  466. (:zip ,@(split-string (subseq path 9) "!/"))
  467. ;; pos never seems right. Use function name.
  468. (:function-name ,(string symbol))
  469. (:align t)))
  470. ((equal (pathname-device (ext:source-pathname symbol)) "emacs-buffer")
  471. ;; conspire with swank-compile-string to keep the buffer
  472. ;; name in a pathname whose device is "emacs-buffer".
  473. `(:location
  474. (:buffer ,(pathname-name (ext:source-pathname symbol)))
  475. (:function-name ,(string symbol))
  476. (:align t)))
  477. (t
  478. `(:location
  479. (:file ,path)
  480. ,(if pos
  481. (list :position (1+ pos))
  482. (list :function-name (string symbol)))
  483. (:align t)))))))
  484. (defmethod source-location ((frame sys::java-stack-frame))
  485. (destructuring-bind (&key class method file line) (sys:frame-to-list frame)
  486. (declare (ignore method))
  487. (let ((file (or (find-file-in-path file *source-path*)
  488. (let ((f (format nil "~{~a/~}~a"
  489. (butlast (split-string class "\\."))
  490. file)))
  491. (find-file-in-path f *source-path*)))))
  492. (and file
  493. `(:location ,file (:line ,line) ())))))
  494. (defmethod source-location ((frame sys::lisp-stack-frame))
  495. (destructuring-bind (operator &rest args) (sys:frame-to-list frame)
  496. (declare (ignore args))
  497. (etypecase operator
  498. (function (source-location operator))
  499. (list nil)
  500. (symbol (source-location operator)))))
  501. (defmethod source-location ((fun function))
  502. (let ((name (function-name fun)))
  503. (and name (source-location name))))
  504. (defun system-property (name)
  505. (java:jstatic "getProperty" "java.lang.System" name))
  506. (defun pathname-parent (pathname)
  507. (make-pathname :directory (butlast (pathname-directory pathname))))
  508. (defun pathname-absolute-p (pathname)
  509. (eq (car (pathname-directory pathname)) ':absolute))
  510. (defun split-string (string regexp)
  511. (coerce
  512. (java:jcall (java:jmethod "java.lang.String" "split" "java.lang.String")
  513. string regexp)
  514. 'list))
  515. (defun path-separator ()
  516. (java:jfield "java.io.File" "pathSeparator"))
  517. (defun search-path-property (prop-name)
  518. (let ((string (system-property prop-name)))
  519. (and string
  520. (remove nil
  521. (mapcar #'truename
  522. (split-string string (path-separator)))))))
  523. (defun jdk-source-path ()
  524. (let* ((jre-home (truename (system-property "java.home")))
  525. (src-zip (merge-pathnames "src.zip" (pathname-parent jre-home)))
  526. (truename (probe-file src-zip)))
  527. (and truename (list truename))))
  528. (defun class-path ()
  529. (append (search-path-property "java.class.path")
  530. (search-path-property "sun.boot.class.path")))
  531. (defvar *source-path*
  532. (append (search-path-property "user.dir")
  533. (jdk-source-path)
  534. ;;(list (truename "/scratch/abcl/src"))
  535. )
  536. "List of directories to search for source files.")
  537. (defun zipfile-contains-p (zipfile-name entry-name)
  538. (let ((zipfile (java:jnew (java:jconstructor "java.util.zip.ZipFile"
  539. "java.lang.String")
  540. zipfile-name)))
  541. (java:jcall
  542. (java:jmethod "java.util.zip.ZipFile" "getEntry" "java.lang.String")
  543. zipfile entry-name)))
  544. ;; (find-file-in-path "java/lang/String.java" *source-path*)
  545. ;; (find-file-in-path "Lisp.java" *source-path*)
  546. ;; Try to find FILENAME in PATH. If found, return a file spec as
  547. ;; needed by Emacs. We also look in zip files.
  548. (defun find-file-in-path (filename path)
  549. (labels ((try (dir)
  550. (cond ((not (pathname-type dir))
  551. (let ((f (probe-file (merge-pathnames filename dir))))
  552. (and f `(:file ,(namestring f)))))
  553. ((equal (pathname-type dir) "zip")
  554. (try-zip dir))
  555. (t (error "strange path element: ~s" path))))
  556. (try-zip (zip)
  557. (let* ((zipfile-name (namestring (truename zip))))
  558. (and (zipfile-contains-p zipfile-name filename)
  559. `(:dir ,zipfile-name ,filename)))))
  560. (cond ((pathname-absolute-p filename) (probe-file filename))
  561. (t
  562. (loop for dir in path
  563. if (try dir) return it)))))
  564. (defimplementation find-definitions (symbol)
  565. (ext:resolve symbol)
  566. (let ((srcloc (source-location symbol)))
  567. (and srcloc `((,symbol ,srcloc)))))
  568. #|
  569. Uncomment this if you have patched xref.lisp, as in
  570. http://article.gmane.org/gmane.lisp.slime.devel/2425
  571. Also, make sure that xref.lisp is loaded by modifying the armedbear
  572. part of *sysdep-pathnames* in swank.loader.lisp.
  573. ;;;; XREF
  574. (setq pxref:*handle-package-forms* '(cl:in-package))
  575. (defmacro defxref (name function)
  576. `(defimplementation ,name (name)
  577. (xref-results (,function name))))
  578. (defxref who-calls pxref:list-callers)
  579. (defxref who-references pxref:list-readers)
  580. (defxref who-binds pxref:list-setters)
  581. (defxref who-sets pxref:list-setters)
  582. (defxref list-callers pxref:list-callers)
  583. (defxref list-callees pxref:list-callees)
  584. (defun xref-results (symbols)
  585. (let ((xrefs '()))
  586. (dolist (symbol symbols)
  587. (push (list symbol (cadar (source-location symbol))) xrefs))
  588. xrefs))
  589. |#
  590. ;;;; Inspecting
  591. (defmethod emacs-inspect ((o t))
  592. (let ((parts (sys:inspected-parts o)))
  593. `("The object is of type " ,(symbol-name (type-of o)) "." (:newline)
  594. ,@(if parts
  595. (loop :for (label . value) :in parts
  596. :appending (label-value-line label value))
  597. (list "No inspectable parts, dumping output of CL:DESCRIBE:"
  598. '(:newline)
  599. (with-output-to-string (desc) (describe o desc)))))))
  600. (defmethod emacs-inspect ((slot mop::slot-definition))
  601. `("Name: "
  602. (:value ,(mop:slot-definition-name slot))
  603. (:newline)
  604. "Documentation:" (:newline)
  605. ,@(when (slot-definition-documentation slot)
  606. `((:value ,(slot-definition-documentation slot)) (:newline)))
  607. "Initialization:" (:newline)
  608. " Args: " (:value ,(mop:slot-definition-initargs slot)) (:newline)
  609. " Form: " ,(if (mop:slot-definition-initfunction slot)
  610. `(:value ,(mop:slot-definition-initform slot))
  611. "#<unspecified>") (:newline)
  612. " Function: "
  613. (:value ,(mop:slot-definition-initfunction slot))
  614. (:newline)))
  615. (defmethod emacs-inspect ((f function))
  616. `(,@(when (function-name f)
  617. `("Name: "
  618. ,(princ-to-string (function-name f)) (:newline)))
  619. ,@(multiple-value-bind (args present)
  620. (sys::arglist f)
  621. (when present
  622. `("Argument list: "
  623. ,(princ-to-string args) (:newline))))
  624. (:newline)
  625. #+nil,@(when (documentation f t)
  626. `("Documentation:" (:newline)
  627. ,(documentation f t) (:newline)))
  628. ,@(when (function-lambda-expression f)
  629. `("Lambda expression:"
  630. (:newline) ,(princ-to-string
  631. (function-lambda-expression f)) (:newline)))))
  632. ;;; Although by convention toString() is supposed to be a
  633. ;;; non-computationally expensive operation this isn't always the
  634. ;;; case, so make its computation a user interaction.
  635. (defparameter *to-string-hashtable* (make-hash-table))
  636. (defmethod emacs-inspect ((o java:java-object))
  637. (let ((to-string (lambda ()
  638. (handler-case
  639. (setf (gethash o *to-string-hashtable*)
  640. (java:jcall "toString" o))
  641. (t (e)
  642. (setf (gethash o *to-string-hashtable*)
  643. (format nil
  644. "Could not invoke toString(): ~A"
  645. e)))))))
  646. (append
  647. (if (gethash o *to-string-hashtable*)
  648. (label-value-line "toString()" (gethash o *to-string-hashtable*))
  649. `((:action "[compute toString()]" ,to-string) (:newline)))
  650. (loop :for (label . value) :in (sys:inspected-parts o)
  651. :appending (label-value-line label value)))))
  652. ;;;; Multithreading
  653. (defimplementation spawn (fn &key name)
  654. (threads:make-thread (lambda () (funcall fn)) :name name))
  655. (defvar *thread-plists* (make-hash-table) ; should be a weak table
  656. "A hashtable mapping threads to a plist.")
  657. (defvar *thread-id-counter* 0)
  658. (defimplementation thread-id (thread)
  659. (threads:synchronized-on *thread-plists*
  660. (or (getf (gethash thread *thread-plists*) 'id)
  661. (setf (getf (gethash thread *thread-plists*) 'id)
  662. (incf *thread-id-counter*)))))
  663. (defimplementation find-thread (id)
  664. (find id (all-threads)
  665. :key (lambda (thread)
  666. (getf (gethash thread *thread-plists*) 'id))))
  667. (defimplementation thread-name (thread)
  668. (threads:thread-name thread))
  669. (defimplementation thread-status (thread)
  670. (format nil "Thread is ~:[dead~;alive~]" (threads:thread-alive-p thread)))
  671. (defimplementation make-lock (&key name)
  672. (declare (ignore name))
  673. (threads:make-thread-lock))
  674. (defimplementation call-with-lock-held (lock function)
  675. (threads:with-thread-lock (lock) (funcall function)))
  676. (defimplementation current-thread ()
  677. (threads:current-thread))
  678. (defimplementation all-threads ()
  679. (copy-list (threads:mapcar-threads #'identity)))
  680. (defimplementation thread-alive-p (thread)
  681. (member thread (all-threads)))
  682. (defimplementation interrupt-thread (thread fn)
  683. (threads:interrupt-thread thread fn))
  684. (defimplementation kill-thread (thread)
  685. (threads:destroy-thread thread))
  686. (defstruct mailbox
  687. (queue '()))
  688. (defun mailbox (thread)
  689. "Return THREAD's mailbox."
  690. (threads:synchronized-on *thread-plists*
  691. (or (getf (gethash thread *thread-plists*) 'mailbox)
  692. (setf (getf (gethash thread *thread-plists*) 'mailbox)
  693. (make-mailbox)))))
  694. (defimplementation send (thread message)
  695. (let ((mbox (mailbox thread)))
  696. (threads:synchronized-on mbox
  697. (setf (mailbox-queue mbox)
  698. (nconc (mailbox-queue mbox) (list message)))
  699. (threads:object-notify-all mbox))))
  700. (defimplementation receive-if (test &optional timeout)
  701. (let* ((mbox (mailbox (current-thread))))
  702. (assert (or (not timeout) (eq timeout t)))
  703. (loop
  704. (check-slime-interrupts)
  705. (threads:synchronized-on mbox
  706. (let* ((q (mailbox-queue mbox))
  707. (tail (member-if test q)))
  708. (when tail
  709. (setf (mailbox-queue mbox) (nconc (ldiff q tail) (cdr tail)))
  710. (return (car tail)))
  711. (when (eq timeout t) (return (values nil t)))
  712. (threads:object-wait mbox 0.3))))))
  713. (defimplementation quit-lisp ()
  714. (ext:exit))
  715. ;;;
  716. #+#.(swank/backend:with-symbol 'package-local-nicknames 'ext)
  717. (defimplementation package-local-nicknames (package)
  718. (ext:package-local-nicknames package))