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.

1020 lines
36 KiB

4 years ago
  1. ;;; -*- indent-tabs-mode: nil -*-
  2. ;;;
  3. ;;; swank-lispworks.lisp --- LispWorks specific code for SLIME.
  4. ;;;
  5. ;;; Created 2003, Helmut Eller
  6. ;;;
  7. ;;; This code has been placed in the Public Domain. All warranties
  8. ;;; are disclaimed.
  9. ;;;
  10. (defpackage swank/lispworks
  11. (:use cl swank/backend))
  12. (in-package swank/lispworks)
  13. (eval-when (:compile-toplevel :load-toplevel :execute)
  14. (require "comm"))
  15. (defimplementation gray-package-name ()
  16. "STREAM")
  17. (import-swank-mop-symbols :clos '(:slot-definition-documentation
  18. :slot-boundp-using-class
  19. :slot-value-using-class
  20. :slot-makunbound-using-class
  21. :eql-specializer
  22. :eql-specializer-object
  23. :compute-applicable-methods-using-classes))
  24. (defun swank-mop:slot-definition-documentation (slot)
  25. (documentation slot t))
  26. (defun swank-mop:slot-boundp-using-class (class object slotd)
  27. (clos:slot-boundp-using-class class object
  28. (clos:slot-definition-name slotd)))
  29. (defun swank-mop:slot-value-using-class (class object slotd)
  30. (clos:slot-value-using-class class object
  31. (clos:slot-definition-name slotd)))
  32. (defun (setf swank-mop:slot-value-using-class) (value class object slotd)
  33. (setf (clos:slot-value-using-class class object
  34. (clos:slot-definition-name slotd))
  35. value))
  36. (defun swank-mop:slot-makunbound-using-class (class object slotd)
  37. (clos:slot-makunbound-using-class class object
  38. (clos:slot-definition-name slotd)))
  39. (defun swank-mop:compute-applicable-methods-using-classes (gf classes)
  40. (clos::compute-applicable-methods-from-classes gf classes))
  41. ;; lispworks doesn't have the eql-specializer class, it represents
  42. ;; them as a list of `(EQL ,OBJECT)
  43. (deftype swank-mop:eql-specializer () 'cons)
  44. (defun swank-mop:eql-specializer-object (eql-spec)
  45. (second eql-spec))
  46. (eval-when (:compile-toplevel :execute :load-toplevel)
  47. (defvar *original-defimplementation* (macro-function 'defimplementation))
  48. (defmacro defimplementation (&whole whole name args &body body
  49. &environment env)
  50. (declare (ignore args body))
  51. `(progn
  52. (dspec:record-definition '(defun ,name) (dspec:location)
  53. :check-redefinition-p nil)
  54. ,(funcall *original-defimplementation* whole env))))
  55. ;;; UTF8
  56. (defimplementation string-to-utf8 (string)
  57. (ef:encode-lisp-string string '(:utf-8 :eol-style :lf)))
  58. (defimplementation utf8-to-string (octets)
  59. (ef:decode-external-string octets '(:utf-8 :eol-style :lf)))
  60. ;;; TCP server
  61. (defimplementation preferred-communication-style ()
  62. :spawn)
  63. (defun socket-fd (socket)
  64. (etypecase socket
  65. (fixnum socket)
  66. (comm:socket-stream (comm:socket-stream-socket socket))))
  67. (defimplementation create-socket (host port &key backlog)
  68. (multiple-value-bind (socket where errno)
  69. #-(or lispworks4.1 (and macosx lispworks4.3))
  70. (comm::create-tcp-socket-for-service port :address host
  71. :backlog (or backlog 5))
  72. #+(or lispworks4.1 (and macosx lispworks4.3))
  73. (comm::create-tcp-socket-for-service port)
  74. (cond (socket socket)
  75. (t (error 'network-error
  76. :format-control "~A failed: ~A (~D)"
  77. :format-arguments (list where
  78. (list #+unix (lw:get-unix-error errno))
  79. errno))))))
  80. (defimplementation local-port (socket)
  81. (nth-value 1 (comm:get-socket-address (socket-fd socket))))
  82. (defimplementation close-socket (socket)
  83. (comm::close-socket (socket-fd socket)))
  84. (defimplementation accept-connection (socket
  85. &key external-format buffering timeout)
  86. (declare (ignore buffering))
  87. (let* ((fd (comm::get-fd-from-socket socket)))
  88. (assert (/= fd -1))
  89. (cond ((not external-format)
  90. (make-instance 'comm:socket-stream
  91. :socket fd
  92. :direction :io
  93. :read-timeout timeout
  94. :element-type '(unsigned-byte 8)))
  95. (t
  96. (assert (valid-external-format-p external-format))
  97. (ecase (first external-format)
  98. ((:latin-1 :ascii)
  99. (make-instance 'comm:socket-stream
  100. :socket fd
  101. :direction :io
  102. :read-timeout timeout
  103. :element-type 'base-char))
  104. (:utf-8
  105. (make-flexi-stream
  106. (make-instance 'comm:socket-stream
  107. :socket fd
  108. :direction :io
  109. :read-timeout timeout
  110. :element-type '(unsigned-byte 8))
  111. external-format)))))))
  112. (defun make-flexi-stream (stream external-format)
  113. (unless (member :flexi-streams *features*)
  114. (error "Cannot use external format ~A~
  115. without having installed flexi-streams in the inferior-lisp."
  116. external-format))
  117. (funcall (read-from-string "FLEXI-STREAMS:MAKE-FLEXI-STREAM")
  118. stream
  119. :external-format
  120. (apply (read-from-string "FLEXI-STREAMS:MAKE-EXTERNAL-FORMAT")
  121. external-format)))
  122. ;;; Coding Systems
  123. (defun valid-external-format-p (external-format)
  124. (member external-format *external-format-to-coding-system*
  125. :test #'equal :key #'car))
  126. (defvar *external-format-to-coding-system*
  127. '(((:latin-1 :eol-style :lf)
  128. "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix")
  129. ;;((:latin-1) "latin-1" "iso-latin-1" "iso-8859-1")
  130. ;;((:utf-8) "utf-8")
  131. ((:utf-8 :eol-style :lf) "utf-8-unix")
  132. ;;((:euc-jp) "euc-jp")
  133. ((:euc-jp :eol-style :lf) "euc-jp-unix")
  134. ;;((:ascii) "us-ascii")
  135. ((:ascii :eol-style :lf) "us-ascii-unix")))
  136. (defimplementation find-external-format (coding-system)
  137. (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
  138. *external-format-to-coding-system*)))
  139. ;;; Unix signals
  140. (defun sigint-handler ()
  141. (with-simple-restart (continue "Continue from SIGINT handler.")
  142. (invoke-debugger "SIGINT")))
  143. (defun make-sigint-handler (process)
  144. (lambda (&rest args)
  145. (declare (ignore args))
  146. (mp:process-interrupt process #'sigint-handler)))
  147. (defun set-sigint-handler ()
  148. ;; Set SIGINT handler on Swank request handler thread.
  149. #-win32
  150. (sys::set-signal-handler +sigint+
  151. (make-sigint-handler mp:*current-process*)))
  152. #-win32
  153. (defimplementation install-sigint-handler (handler)
  154. (sys::set-signal-handler +sigint+
  155. (let ((self mp:*current-process*))
  156. (lambda (&rest args)
  157. (declare (ignore args))
  158. (mp:process-interrupt self handler)))))
  159. (defimplementation getpid ()
  160. #+win32 (win32:get-current-process-id)
  161. #-win32 (system::getpid))
  162. (defimplementation lisp-implementation-type-name ()
  163. "lispworks")
  164. (defimplementation set-default-directory (directory)
  165. (namestring (hcl:change-directory directory)))
  166. ;;;; Documentation
  167. (defun map-list (function list)
  168. "Map over proper and not proper lists."
  169. (loop for (car . cdr) on list
  170. collect (funcall function car) into result
  171. when (null cdr) return result
  172. when (atom cdr) return (nconc result (funcall function cdr))))
  173. (defun replace-strings-with-symbols (tree)
  174. (map-list
  175. (lambda (x)
  176. (typecase x
  177. (list
  178. (replace-strings-with-symbols x))
  179. (symbol
  180. x)
  181. (string
  182. (intern x))
  183. (t
  184. (intern (write-to-string x)))))
  185. tree))
  186. (defimplementation arglist (symbol-or-function)
  187. (let ((arglist (lw:function-lambda-list symbol-or-function)))
  188. (etypecase arglist
  189. ((member :dont-know)
  190. :not-available)
  191. (list
  192. (replace-strings-with-symbols arglist)))))
  193. (defimplementation function-name (function)
  194. (nth-value 2 (function-lambda-expression function)))
  195. (defimplementation macroexpand-all (form &optional env)
  196. (declare (ignore env))
  197. (walker:walk-form form))
  198. (defun generic-function-p (object)
  199. (typep object 'generic-function))
  200. (defimplementation describe-symbol-for-emacs (symbol)
  201. "Return a plist describing SYMBOL.
  202. Return NIL if the symbol is unbound."
  203. (let ((result '()))
  204. (labels ((first-line (string)
  205. (let ((pos (position #\newline string)))
  206. (if (null pos) string (subseq string 0 pos))))
  207. (doc (kind &optional (sym symbol))
  208. (let ((string (or (documentation sym kind))))
  209. (if string
  210. (first-line string)
  211. :not-documented)))
  212. (maybe-push (property value)
  213. (when value
  214. (setf result (list* property value result)))))
  215. (maybe-push
  216. :variable (when (boundp symbol)
  217. (doc 'variable)))
  218. (maybe-push
  219. :generic-function (if (and (fboundp symbol)
  220. (generic-function-p (fdefinition symbol)))
  221. (doc 'function)))
  222. (maybe-push
  223. :function (if (and (fboundp symbol)
  224. (not (generic-function-p (fdefinition symbol))))
  225. (doc 'function)))
  226. (maybe-push
  227. :setf (let ((setf-name (sys:underlying-setf-name `(setf ,symbol))))
  228. (if (fboundp setf-name)
  229. (doc 'setf))))
  230. (maybe-push
  231. :class (if (find-class symbol nil)
  232. (doc 'class)))
  233. result)))
  234. (defimplementation describe-definition (symbol type)
  235. (ecase type
  236. (:variable (describe-symbol symbol))
  237. (:class (describe (find-class symbol)))
  238. ((:function :generic-function) (describe-function symbol))
  239. (:setf (describe-function (sys:underlying-setf-name `(setf ,symbol))))))
  240. (defun describe-function (symbol)
  241. (cond ((fboundp symbol)
  242. (format t "(~A ~/pprint-fill/)~%~%~:[(not documented)~;~:*~A~]~%"
  243. symbol
  244. (lispworks:function-lambda-list symbol)
  245. (documentation symbol 'function))
  246. (describe (fdefinition symbol)))
  247. (t (format t "~S is not fbound" symbol))))
  248. (defun describe-symbol (sym)
  249. (format t "~A is a symbol in package ~A." sym (symbol-package sym))
  250. (when (boundp sym)
  251. (format t "~%~%Value: ~A" (symbol-value sym)))
  252. (let ((doc (documentation sym 'variable)))
  253. (when doc
  254. (format t "~%~%Variable documentation:~%~A" doc)))
  255. (when (fboundp sym)
  256. (describe-function sym)))
  257. (defimplementation type-specifier-p (symbol)
  258. (or (ignore-errors
  259. (subtypep nil symbol))
  260. (not (eq (type-specifier-arglist symbol) :not-available))))
  261. ;;; Debugging
  262. (defclass slime-env (env:environment)
  263. ((debugger-hook :initarg :debugger-hoook)))
  264. (defun slime-env (hook io-bindings)
  265. (make-instance 'slime-env :name "SLIME Environment"
  266. :io-bindings io-bindings
  267. :debugger-hoook hook))
  268. (defmethod env-internals:environment-display-notifier
  269. ((env slime-env) &key restarts condition)
  270. (declare (ignore restarts condition))
  271. (swank:swank-debugger-hook condition *debugger-hook*))
  272. (defmethod env-internals:environment-display-debugger ((env slime-env))
  273. *debug-io*)
  274. (defmethod env-internals:confirm-p ((e slime-env) &optional msg &rest args)
  275. (apply #'swank:y-or-n-p-in-emacs msg args))
  276. (defimplementation call-with-debugger-hook (hook fun)
  277. (let ((*debugger-hook* hook))
  278. (env:with-environment ((slime-env hook '()))
  279. (funcall fun))))
  280. (defimplementation install-debugger-globally (function)
  281. (setq *debugger-hook* function)
  282. (setf (env:environment) (slime-env function '())))
  283. (defvar *sldb-top-frame*)
  284. (defun interesting-frame-p (frame)
  285. (cond ((or (dbg::call-frame-p frame)
  286. (dbg::derived-call-frame-p frame)
  287. (dbg::foreign-frame-p frame)
  288. (dbg::interpreted-call-frame-p frame))
  289. t)
  290. ((dbg::catch-frame-p frame) dbg:*print-catch-frames*)
  291. ((dbg::binding-frame-p frame) dbg:*print-binding-frames*)
  292. ((dbg::handler-frame-p frame) dbg:*print-handler-frames*)
  293. ((dbg::restart-frame-p frame) dbg:*print-restart-frames*)
  294. (t nil)))
  295. (defun nth-next-frame (frame n)
  296. "Unwind FRAME N times."
  297. (do ((frame frame (dbg::frame-next frame))
  298. (i n (if (interesting-frame-p frame) (1- i) i)))
  299. ((or (not frame)
  300. (and (interesting-frame-p frame) (zerop i)))
  301. frame)))
  302. (defun nth-frame (index)
  303. (nth-next-frame *sldb-top-frame* index))
  304. (defun find-top-frame ()
  305. "Return the most suitable top-frame for the debugger."
  306. (flet ((find-named-frame (name)
  307. (do ((frame (dbg::debugger-stack-current-frame
  308. dbg::*debugger-stack*)
  309. (nth-next-frame frame 1)))
  310. ((or (null frame) ; no frame found!
  311. (and (dbg::call-frame-p frame)
  312. (eq (dbg::call-frame-function-name frame)
  313. name)))
  314. (nth-next-frame frame 1)))))
  315. (or (find-named-frame 'invoke-debugger)
  316. (find-named-frame 'swank::safe-backtrace)
  317. ;; if we can't find a likely top frame, take any old frame
  318. ;; at the top
  319. (dbg::debugger-stack-current-frame dbg::*debugger-stack*))))
  320. (defimplementation call-with-debugging-environment (fn)
  321. (dbg::with-debugger-stack ()
  322. (let ((*sldb-top-frame* (find-top-frame)))
  323. (funcall fn))))
  324. (defimplementation compute-backtrace (start end)
  325. (let ((end (or end most-positive-fixnum))
  326. (backtrace '()))
  327. (do ((frame (nth-frame start) (dbg::frame-next frame))
  328. (i start))
  329. ((or (not frame) (= i end)) (nreverse backtrace))
  330. (when (interesting-frame-p frame)
  331. (incf i)
  332. (push frame backtrace)))))
  333. (defun frame-actual-args (frame)
  334. (let ((*break-on-signals* nil)
  335. (kind nil))
  336. (loop for arg in (dbg::call-frame-arglist frame)
  337. if (eq kind '&rest)
  338. nconc (handler-case
  339. (dbg::dbg-eval arg frame)
  340. (error (e) (list (format nil "<~A>" arg))))
  341. and do (loop-finish)
  342. else
  343. if (member arg '(&rest &optional &key))
  344. do (setq kind arg)
  345. else
  346. nconc
  347. (handler-case
  348. (nconc (and (eq kind '&key)
  349. (list (cond ((symbolp arg)
  350. (intern (symbol-name arg) :keyword))
  351. ((and (consp arg) (symbolp (car arg)))
  352. (intern (symbol-name (car arg))
  353. :keyword))
  354. (t (caar arg)))))
  355. (list (dbg::dbg-eval
  356. (cond ((symbolp arg) arg)
  357. ((and (consp arg) (symbolp (car arg)))
  358. (car arg))
  359. (t (cadar arg)))
  360. frame)))
  361. (error (e) (list (format nil "<~A>" arg)))))))
  362. (defimplementation print-frame (frame stream)
  363. (cond ((dbg::call-frame-p frame)
  364. (prin1 (cons (dbg::call-frame-function-name frame)
  365. (frame-actual-args frame))
  366. stream))
  367. (t (princ frame stream))))
  368. (defun frame-vars (frame)
  369. (first (dbg::frame-locals-format-list frame #'list 75 0)))
  370. (defimplementation frame-locals (n)
  371. (let ((frame (nth-frame n)))
  372. (if (dbg::call-frame-p frame)
  373. (mapcar (lambda (var)
  374. (destructuring-bind (name value symbol location) var
  375. (declare (ignore name location))
  376. (list :name symbol :id 0
  377. :value value)))
  378. (frame-vars frame)))))
  379. (defimplementation frame-var-value (frame var)
  380. (let ((frame (nth-frame frame)))
  381. (destructuring-bind (_n value _s _l) (nth var (frame-vars frame))
  382. (declare (ignore _n _s _l))
  383. value)))
  384. (defimplementation frame-source-location (frame)
  385. (let ((frame (nth-frame frame))
  386. (callee (if (plusp frame) (nth-frame (1- frame)))))
  387. (if (dbg::call-frame-p frame)
  388. (let ((dspec (dbg::call-frame-function-name frame))
  389. (cname (and (dbg::call-frame-p callee)
  390. (dbg::call-frame-function-name callee)))
  391. (path (and (dbg::call-frame-p frame)
  392. (dbg::call-frame-edit-path frame))))
  393. (if dspec
  394. (frame-location dspec cname path))))))
  395. (defimplementation eval-in-frame (form frame-number)
  396. (let ((frame (nth-frame frame-number)))
  397. (dbg::dbg-eval form frame)))
  398. (defun function-name-package (name)
  399. (typecase name
  400. (null nil)
  401. (symbol (symbol-package name))
  402. ((cons (eql hcl:subfunction))
  403. (destructuring-bind (name parent) (cdr name)
  404. (declare (ignore name))
  405. (function-name-package parent)))
  406. ((cons (eql lw:top-level-form)) nil)
  407. (t nil)))
  408. (defimplementation frame-package (frame-number)
  409. (let ((frame (nth-frame frame-number)))
  410. (if (dbg::call-frame-p frame)
  411. (function-name-package (dbg::call-frame-function-name frame)))))
  412. (defimplementation return-from-frame (frame-number form)
  413. (let* ((frame (nth-frame frame-number))
  414. (return-frame (dbg::find-frame-for-return frame)))
  415. (dbg::dbg-return-from-call-frame frame form return-frame
  416. dbg::*debugger-stack*)))
  417. (defimplementation restart-frame (frame-number)
  418. (let ((frame (nth-frame frame-number)))
  419. (dbg::restart-frame frame :same-args t)))
  420. (defimplementation disassemble-frame (frame-number)
  421. (let* ((frame (nth-frame frame-number)))
  422. (when (dbg::call-frame-p frame)
  423. (let ((function (dbg::get-call-frame-function frame)))
  424. (disassemble function)))))
  425. ;;; Definition finding
  426. (defun frame-location (dspec callee-name edit-path)
  427. (let ((infos (dspec:find-dspec-locations dspec)))
  428. (cond (infos
  429. (destructuring-bind ((rdspec location) &rest _) infos
  430. (declare (ignore _))
  431. (let ((name (and callee-name (symbolp callee-name)
  432. (string callee-name)))
  433. (path (edit-path-to-cmucl-source-path edit-path)))
  434. (make-dspec-location rdspec location
  435. `(:call-site ,name :edit-path ,path)))))
  436. (t
  437. (list :error (format nil "Source location not available for: ~S"
  438. dspec))))))
  439. ;; dbg::call-frame-edit-path is not documented but lets assume the
  440. ;; binary representation of the integer EDIT-PATH should be
  441. ;; interpreted as a sequence of CAR or CDR. #b1111010 is roughly the
  442. ;; same as cadadddr. Something is odd with the highest bit.
  443. (defun edit-path-to-cmucl-source-path (edit-path)
  444. (and edit-path
  445. (cons 0
  446. (let ((n -1))
  447. (loop for i from (1- (integer-length edit-path)) downto 0
  448. if (logbitp i edit-path) do (incf n)
  449. else collect (prog1 n (setq n 0)))))))
  450. ;; (edit-path-to-cmucl-source-path #b1111010) => (0 3 1)
  451. (defimplementation find-definitions (name)
  452. (let ((locations (dspec:find-name-locations dspec:*dspec-classes* name)))
  453. (loop for (dspec location) in locations
  454. collect (list dspec (make-dspec-location dspec location)))))
  455. ;;; Compilation
  456. (defmacro with-swank-compilation-unit ((location &rest options) &body body)
  457. (lw:rebinding (location)
  458. `(let ((compiler::*error-database* '()))
  459. (with-compilation-unit ,options
  460. (multiple-value-prog1 (progn ,@body)
  461. (signal-error-data-base compiler::*error-database*
  462. ,location)
  463. (signal-undefined-functions compiler::*unknown-functions*
  464. ,location))))))
  465. (defimplementation swank-compile-file (input-file output-file
  466. load-p external-format
  467. &key policy)
  468. (declare (ignore policy))
  469. (with-swank-compilation-unit (input-file)
  470. (compile-file input-file
  471. :output-file output-file
  472. :load load-p
  473. :external-format external-format)))
  474. (defvar *within-call-with-compilation-hooks* nil
  475. "Whether COMPILE-FILE was called from within CALL-WITH-COMPILATION-HOOKS.")
  476. (defvar *undefined-functions-hash* nil
  477. "Hash table to map info about undefined functions to pathnames.")
  478. (lw:defadvice (compile-file compile-file-and-collect-notes :around)
  479. (pathname &rest rest)
  480. (multiple-value-prog1 (apply #'lw:call-next-advice pathname rest)
  481. (when *within-call-with-compilation-hooks*
  482. (maphash (lambda (unfun dspecs)
  483. (dolist (dspec dspecs)
  484. (let ((unfun-info (list unfun dspec)))
  485. (unless (gethash unfun-info *undefined-functions-hash*)
  486. (setf (gethash unfun-info *undefined-functions-hash*)
  487. pathname)))))
  488. compiler::*unknown-functions*))))
  489. (defimplementation call-with-compilation-hooks (function)
  490. (let ((compiler::*error-database* '())
  491. (*undefined-functions-hash* (make-hash-table :test 'equal))
  492. (*within-call-with-compilation-hooks* t))
  493. (with-compilation-unit ()
  494. (prog1 (funcall function)
  495. (signal-error-data-base compiler::*error-database*)
  496. (signal-undefined-functions compiler::*unknown-functions*)))))
  497. (defun map-error-database (database fn)
  498. (loop for (filename . defs) in database do
  499. (loop for (dspec . conditions) in defs do
  500. (dolist (c conditions)
  501. (multiple-value-bind (condition path)
  502. (if (consp c) (values (car c) (cdr c)) (values c nil))
  503. (funcall fn filename dspec condition path))))))
  504. (defun lispworks-severity (condition)
  505. (cond ((not condition) :warning)
  506. (t (etypecase condition
  507. #-(or lispworks4 lispworks5)
  508. (conditions:compiler-note :note)
  509. (error :error)
  510. (style-warning :warning)
  511. (warning :warning)))))
  512. (defun signal-compiler-condition (message location condition)
  513. (check-type message string)
  514. (signal
  515. (make-instance 'compiler-condition :message message
  516. :severity (lispworks-severity condition)
  517. :location location
  518. :original-condition condition)))
  519. (defvar *temp-file-format* '(:utf-8 :eol-style :lf))
  520. (defun compile-from-temp-file (string filename)
  521. (unwind-protect
  522. (progn
  523. (with-open-file (s filename :direction :output
  524. :if-exists :supersede
  525. :external-format *temp-file-format*)
  526. (write-string string s)
  527. (finish-output s))
  528. (multiple-value-bind (binary-filename warnings? failure?)
  529. (compile-file filename :load t
  530. :external-format *temp-file-format*)
  531. (declare (ignore warnings?))
  532. (when binary-filename
  533. (delete-file binary-filename))
  534. (not failure?)))
  535. (delete-file filename)))
  536. (defun dspec-function-name-position (dspec fallback)
  537. (etypecase dspec
  538. (cons (let ((name (dspec:dspec-primary-name dspec)))
  539. (typecase name
  540. ((or symbol string)
  541. (list :function-name (string name)))
  542. (t fallback))))
  543. (null fallback)
  544. (symbol (list :function-name (string dspec)))))
  545. (defmacro with-fairly-standard-io-syntax (&body body)
  546. "Like WITH-STANDARD-IO-SYNTAX but preserve *PACKAGE* and *READTABLE*."
  547. (let ((package (gensym))
  548. (readtable (gensym)))
  549. `(let ((,package *package*)
  550. (,readtable *readtable*))
  551. (with-standard-io-syntax
  552. (let ((*package* ,package)
  553. (*readtable* ,readtable))
  554. ,@body)))))
  555. (defun skip-comments (stream)
  556. (let ((pos0 (file-position stream)))
  557. (cond ((equal (ignore-errors (list (read-delimited-list #\( stream)))
  558. '(()))
  559. (file-position stream (1- (file-position stream))))
  560. (t (file-position stream pos0)))))
  561. #-(or lispworks4.1 lispworks4.2) ; no dspec:parse-form-dspec prior to 4.3
  562. (defun dspec-stream-position (stream dspec)
  563. (with-fairly-standard-io-syntax
  564. (loop (let* ((pos (progn (skip-comments stream) (file-position stream)))
  565. (form (read stream nil '#1=#:eof)))
  566. (when (eq form '#1#)
  567. (return nil))
  568. (labels ((check-dspec (form)
  569. (when (consp form)
  570. (let ((operator (car form)))
  571. (case operator
  572. ((progn)
  573. (mapcar #'check-dspec
  574. (cdr form)))
  575. ((eval-when locally macrolet symbol-macrolet)
  576. (mapcar #'check-dspec
  577. (cddr form)))
  578. ((in-package)
  579. (let ((package (find-package (second form))))
  580. (when package
  581. (setq *package* package))))
  582. (otherwise
  583. (let ((form-dspec (dspec:parse-form-dspec form)))
  584. (when (dspec:dspec-equal dspec form-dspec)
  585. (return pos)))))))))
  586. (check-dspec form))))))
  587. (defun dspec-file-position (file dspec)
  588. (let* ((*compile-file-pathname* (pathname file))
  589. (*compile-file-truename* (truename *compile-file-pathname*))
  590. (*load-pathname* *compile-file-pathname*)
  591. (*load-truename* *compile-file-truename*))
  592. (with-open-file (stream file)
  593. (let ((pos
  594. #-(or lispworks4.1 lispworks4.2)
  595. (ignore-errors (dspec-stream-position stream dspec))))
  596. (if pos
  597. (list :position (1+ pos))
  598. (dspec-function-name-position dspec `(:position 1)))))))
  599. (defun emacs-buffer-location-p (location)
  600. (and (consp location)
  601. (eq (car location) :emacs-buffer)))
  602. (defun make-dspec-location (dspec location &optional hints)
  603. (etypecase location
  604. ((or pathname string)
  605. (multiple-value-bind (file err)
  606. (ignore-errors (namestring (truename location)))
  607. (if err
  608. (list :error (princ-to-string err))
  609. (make-location `(:file ,file)
  610. (dspec-file-position file dspec)
  611. hints))))
  612. (symbol
  613. `(:error ,(format nil "Cannot resolve location: ~S" location)))
  614. ((satisfies emacs-buffer-location-p)
  615. (destructuring-bind (_ buffer offset) location
  616. (declare (ignore _))
  617. (make-location `(:buffer ,buffer)
  618. (dspec-function-name-position dspec `(:offset ,offset 0))
  619. hints)))))
  620. (defun make-dspec-progenitor-location (dspec location edit-path)
  621. (let ((canon-dspec (dspec:canonicalize-dspec dspec)))
  622. (make-dspec-location
  623. (if canon-dspec
  624. (if (dspec:local-dspec-p canon-dspec)
  625. (dspec:dspec-progenitor canon-dspec)
  626. canon-dspec)
  627. nil)
  628. location
  629. (if edit-path
  630. (list :edit-path (edit-path-to-cmucl-source-path edit-path))))))
  631. (defun signal-error-data-base (database &optional location)
  632. (map-error-database
  633. database
  634. (lambda (filename dspec condition edit-path)
  635. (signal-compiler-condition
  636. (format nil "~A" condition)
  637. (make-dspec-progenitor-location dspec (or location filename) edit-path)
  638. condition))))
  639. (defun unmangle-unfun (symbol)
  640. "Converts symbols like 'SETF::|\"CL-USER\" \"GET\"| to
  641. function names like \(SETF GET)."
  642. (cond ((sys::setf-symbol-p symbol)
  643. (sys::setf-pair-from-underlying-name symbol))
  644. (t symbol)))
  645. (defun signal-undefined-functions (htab &optional filename)
  646. (maphash (lambda (unfun dspecs)
  647. (dolist (dspec dspecs)
  648. (signal-compiler-condition
  649. (format nil "Undefined function ~A" (unmangle-unfun unfun))
  650. (make-dspec-progenitor-location
  651. dspec
  652. (or filename
  653. (gethash (list unfun dspec) *undefined-functions-hash*))
  654. nil)
  655. nil)))
  656. htab))
  657. (defimplementation swank-compile-string (string &key buffer position filename
  658. policy)
  659. (declare (ignore filename policy))
  660. (assert buffer)
  661. (assert position)
  662. (let* ((location (list :emacs-buffer buffer position))
  663. (tmpname (hcl:make-temp-file nil "lisp")))
  664. (with-swank-compilation-unit (location)
  665. (compile-from-temp-file
  666. (with-output-to-string (s)
  667. (let ((*print-radix* t))
  668. (print `(eval-when (:compile-toplevel)
  669. (setq dspec::*location* (list ,@location)))
  670. s))
  671. (write-string string s))
  672. tmpname))))
  673. ;;; xref
  674. (defmacro defxref (name function)
  675. `(defimplementation ,name (name)
  676. (xref-results (,function name))))
  677. (defxref who-calls hcl:who-calls)
  678. (defxref who-macroexpands hcl:who-calls) ; macros are in the calls table too
  679. (defxref calls-who hcl:calls-who)
  680. (defxref list-callers list-callers-internal)
  681. (defxref list-callees list-callees-internal)
  682. (defun list-callers-internal (name)
  683. (let ((callers (make-array 100
  684. :fill-pointer 0
  685. :adjustable t)))
  686. (hcl:sweep-all-objects
  687. #'(lambda (object)
  688. (when (and #+Harlequin-PC-Lisp (low:compiled-code-p object)
  689. #+Harlequin-Unix-Lisp (sys:callablep object)
  690. #-(or Harlequin-PC-Lisp Harlequin-Unix-Lisp)
  691. (sys:compiled-code-p object)
  692. (system::find-constant$funcallable name object))
  693. (vector-push-extend object callers))))
  694. ;; Delay dspec:object-dspec until after sweep-all-objects
  695. ;; to reduce allocation problems.
  696. (loop for object across callers
  697. collect (if (symbolp object)
  698. (list 'function object)
  699. (or (dspec:object-dspec object) object)))))
  700. (defun list-callees-internal (name)
  701. (let ((callees '()))
  702. (system::find-constant$funcallable
  703. 'junk name
  704. :test #'(lambda (junk constant)
  705. (declare (ignore junk))
  706. (when (and (symbolp constant)
  707. (fboundp constant))
  708. (pushnew (list 'function constant) callees :test 'equal))
  709. ;; Return nil so we iterate over all constants.
  710. nil))
  711. callees))
  712. ;; only for lispworks 4.2 and above
  713. #-lispworks4.1
  714. (progn
  715. (defxref who-references hcl:who-references)
  716. (defxref who-binds hcl:who-binds)
  717. (defxref who-sets hcl:who-sets))
  718. (defimplementation who-specializes (classname)
  719. (let ((class (find-class classname nil)))
  720. (when class
  721. (let ((methods (clos:class-direct-methods class)))
  722. (xref-results (mapcar #'dspec:object-dspec methods))))))
  723. (defun xref-results (dspecs)
  724. (flet ((frob-locs (dspec locs)
  725. (cond (locs
  726. (loop for (name loc) in locs
  727. collect (list name (make-dspec-location name loc))))
  728. (t `((,dspec (:error "Source location not available")))))))
  729. (loop for dspec in dspecs
  730. append (frob-locs dspec (dspec:dspec-definition-locations dspec)))))
  731. ;;; Inspector
  732. (defmethod emacs-inspect ((o t))
  733. (lispworks-inspect o))
  734. (defmethod emacs-inspect ((o function))
  735. (lispworks-inspect o))
  736. ;; FIXME: slot-boundp-using-class in LW works with names so we can't
  737. ;; use our method in swank.lisp.
  738. (defmethod emacs-inspect ((o standard-object))
  739. (lispworks-inspect o))
  740. (defun lispworks-inspect (o)
  741. (multiple-value-bind (names values _getter _setter type)
  742. (lw:get-inspector-values o nil)
  743. (declare (ignore _getter _setter))
  744. (append
  745. (label-value-line "Type" type)
  746. (loop for name in names
  747. for value in values
  748. append (label-value-line name value)))))
  749. ;;; Miscellaneous
  750. (defimplementation quit-lisp ()
  751. (lispworks:quit))
  752. ;;; Tracing
  753. (defun parse-fspec (fspec)
  754. "Return a dspec for FSPEC."
  755. (ecase (car fspec)
  756. ((:defmethod) `(method ,(cdr fspec)))))
  757. (defun tracedp (dspec)
  758. (member dspec (eval '(trace)) :test #'equal))
  759. (defun toggle-trace-aux (dspec)
  760. (cond ((tracedp dspec)
  761. (eval `(untrace ,dspec))
  762. (format nil "~S is now untraced." dspec))
  763. (t
  764. (eval `(trace (,dspec)))
  765. (format nil "~S is now traced." dspec))))
  766. (defimplementation toggle-trace (fspec)
  767. (toggle-trace-aux (parse-fspec fspec)))
  768. ;;; Multithreading
  769. (defimplementation initialize-multiprocessing (continuation)
  770. (cond ((not mp::*multiprocessing*)
  771. (push (list "Initialize SLIME" '() continuation)
  772. mp:*initial-processes*)
  773. (mp:initialize-multiprocessing))
  774. (t (funcall continuation))))
  775. (defimplementation spawn (fn &key name)
  776. (mp:process-run-function name () fn))
  777. (defvar *id-lock* (mp:make-lock))
  778. (defvar *thread-id-counter* 0)
  779. (defimplementation thread-id (thread)
  780. (mp:with-lock (*id-lock*)
  781. (or (getf (mp:process-plist thread) 'id)
  782. (setf (getf (mp:process-plist thread) 'id)
  783. (incf *thread-id-counter*)))))
  784. (defimplementation find-thread (id)
  785. (find id (mp:list-all-processes)
  786. :key (lambda (p) (getf (mp:process-plist p) 'id))))
  787. (defimplementation thread-name (thread)
  788. (mp:process-name thread))
  789. (defimplementation thread-status (thread)
  790. (format nil "~A ~D"
  791. (mp:process-whostate thread)
  792. (mp:process-priority thread)))
  793. (defimplementation make-lock (&key name)
  794. (mp:make-lock :name name))
  795. (defimplementation call-with-lock-held (lock function)
  796. (mp:with-lock (lock) (funcall function)))
  797. (defimplementation current-thread ()
  798. mp:*current-process*)
  799. (defimplementation all-threads ()
  800. (mp:list-all-processes))
  801. (defimplementation interrupt-thread (thread fn)
  802. (mp:process-interrupt thread fn))
  803. (defimplementation kill-thread (thread)
  804. (mp:process-kill thread))
  805. (defimplementation thread-alive-p (thread)
  806. (mp:process-alive-p thread))
  807. (defstruct (mailbox (:conc-name mailbox.))
  808. (mutex (mp:make-lock :name "thread mailbox"))
  809. (queue '() :type list))
  810. (defvar *mailbox-lock* (mp:make-lock))
  811. (defun mailbox (thread)
  812. (mp:with-lock (*mailbox-lock*)
  813. (or (getf (mp:process-plist thread) 'mailbox)
  814. (setf (getf (mp:process-plist thread) 'mailbox)
  815. (make-mailbox)))))
  816. (defimplementation receive-if (test &optional timeout)
  817. (let* ((mbox (mailbox mp:*current-process*))
  818. (lock (mailbox.mutex mbox)))
  819. (assert (or (not timeout) (eq timeout t)))
  820. (loop
  821. (check-slime-interrupts)
  822. (mp:with-lock (lock "receive-if/try")
  823. (let* ((q (mailbox.queue mbox))
  824. (tail (member-if test q)))
  825. (when tail
  826. (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail)))
  827. (return (car tail)))))
  828. (when (eq timeout t) (return (values nil t)))
  829. (mp:process-wait-with-timeout
  830. "receive-if" 0.3 (lambda () (some test (mailbox.queue mbox)))))))
  831. (defimplementation send (thread message)
  832. (let ((mbox (mailbox thread)))
  833. (mp:with-lock ((mailbox.mutex mbox))
  834. (setf (mailbox.queue mbox)
  835. (nconc (mailbox.queue mbox) (list message))))))
  836. (let ((alist '())
  837. (lock (mp:make-lock :name "register-thread")))
  838. (defimplementation register-thread (name thread)
  839. (declare (type symbol name))
  840. (mp:with-lock (lock)
  841. (etypecase thread
  842. (null
  843. (setf alist (delete name alist :key #'car)))
  844. (mp:process
  845. (let ((probe (assoc name alist)))
  846. (cond (probe (setf (cdr probe) thread))
  847. (t (setf alist (acons name thread alist))))))))
  848. nil)
  849. (defimplementation find-registered (name)
  850. (mp:with-lock (lock)
  851. (cdr (assoc name alist)))))
  852. (defimplementation set-default-initial-binding (var form)
  853. (setq mp:*process-initial-bindings*
  854. (acons var `(eval (quote ,form))
  855. mp:*process-initial-bindings* )))
  856. (defimplementation thread-attributes (thread)
  857. (list :priority (mp:process-priority thread)
  858. :idle (mp:process-idle-time thread)))
  859. ;;;; Weak hashtables
  860. (defimplementation make-weak-key-hash-table (&rest args)
  861. (apply #'make-hash-table :weak-kind :key args))
  862. (defimplementation make-weak-value-hash-table (&rest args)
  863. (apply #'make-hash-table :weak-kind :value args))