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.

994 lines
30 KiB

5 years ago
  1. ;;;; swank-goo.goo --- Swank server for GOO
  2. ;;;
  3. ;;; Copyright (C) 2005 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 to view it).
  7. ;;;; Installation
  8. ;;
  9. ;; 1. Add something like this to your .emacs:
  10. ;;
  11. ;; (setq slime-lisp-implementations
  12. ;; '((goo ("g2c") :init goo-slime-init)))
  13. ;;
  14. ;; (defun goo-slime-init (file _)
  15. ;; (format "%S\n%S\n"
  16. ;; `(set goo/system:*module-search-path*
  17. ;; (cat '(".../slime/contrib/")
  18. ;; goo/system:*module-search-path*))
  19. ;; `(swank-goo:start-swank ,file)))
  20. ;;
  21. ;; 2. Start everything with M-- M-x slime goo
  22. ;;
  23. ;;;; Code
  24. (use goo)
  25. (use goo/boot)
  26. (use goo/x)
  27. (use goo/io/port)
  28. (use goo/io/write)
  29. (use goo/eval)
  30. (use goo/system)
  31. (use goo/conditions)
  32. (use goo/fun)
  33. (use goo/loc)
  34. (use goo/chr)
  35. (use eval/module)
  36. (use eval/ast)
  37. (use eval/g2c)
  38. ;;;; server setup
  39. (df create-server (port-number) (setup-server port-number announce-port))
  40. (df start-swank (port-file)
  41. (setup-server 0 (fun (s) (write-port-file (%local-port s) port-file))))
  42. (df setup-server (port-number announce)
  43. (let ((s (create-socket port-number)))
  44. (fin (seq
  45. (announce s)
  46. (let ((c (accept s)))
  47. ;;(post "connection: %s" c)
  48. (fin (serve-requests c)
  49. (%close (@fd c)))))
  50. (post "closing socket: %s" s)
  51. (%close s))))
  52. (df announce-port (socket)
  53. (post "Listening on port: %d\n" (%local-port socket)))
  54. (df write-port-file (port-number filename)
  55. (with-port (file (open <file-out-port> filename))
  56. (msg file "%d\n" port-number)))
  57. (dc <slime-toplevel> (<restart>))
  58. (dc <connection> (<any>))
  59. (dp @socket (<connection> => <port>))
  60. (dp @in (<connection> => <in-port>))
  61. (dp @out (<connection> => <out-port>))
  62. (dv emacs-connection|(t? <connection>) #f)
  63. (df serve-requests (socket)
  64. (dlet ((emacs-connection (new <connection>
  65. @socket socket
  66. @out (new <slime-out-port> @socket socket)
  67. @in (new <slime-in-port> @socket socket))))
  68. (dlet ((out (@out emacs-connection))
  69. (in (@in emacs-connection)))
  70. (while #t
  71. (simple-restart
  72. <slime-toplevel> "SLIME top-level"
  73. (fun () (process-next-event socket)))))))
  74. (d. <nil> (t= 'nil))
  75. (d. t #t)
  76. (d. cons pair)
  77. (dv tag-counter|<int> 0)
  78. (df process-next-event (port) (dispatch-event (decode-message port) port))
  79. (df dispatch-event (event port)
  80. ;; (post "%=\n" event)
  81. (match event
  82. ((:emacs-rex ,form ,package ,_thread-id ,id)
  83. (eval-for-emacs form package port id))
  84. ((:read-string ,_)
  85. (def tag (incf tag-counter))
  86. (encode-message `(:read-string ,_ ,tag) port)
  87. (rep loop ()
  88. (match (decode-message port)
  89. ((:emacs-return-string ,_ ,rtag ,str)
  90. (assert (= tag rtag) "Unexpected reply tag: %d" rtag)
  91. str)
  92. ((,@evt)
  93. (try-recover
  94. (fun () (dispatch-event evt port))
  95. (fun () (encode-message `(:read-aborted ,_ ,tag) port)))
  96. (loop)))))
  97. ((:emacs-return-string ,_ ,rtag ,str)
  98. (error "Unexpected event: %=" event))
  99. ((,@_) (encode-message event port))))
  100. (dc <eval-context> (<any>))
  101. (dp @module (<eval-context> => <module>))
  102. (dp @id (<eval-context> => <int>))
  103. (dp @port (<eval-context> => <port>))
  104. (dp @prev (<eval-context> => (t? <eval-context>)))
  105. ;; should be ddv
  106. (dv eval-context|(t? <eval-context>) #f)
  107. (df buffer-module () (@module eval-context))
  108. (df eval-for-emacs (form|<lst> package|(t+ <str> <nil>) port id|<int>)
  109. (try-recover
  110. (fun ()
  111. (try <condition> debugger-hook
  112. (dlet ((eval-context (new <eval-context>
  113. @module (find-buffer-module package) @id id
  114. @port port @prev eval-context)))
  115. (def result (eval (frob-form-for-eval form) 'swank-goo))
  116. (force-out out)
  117. (dispatch-event `(:return (:ok ,result) ,id) port))))
  118. (fun () (dispatch-event `(:return (:abort) ,id) port))))
  119. (dm find-buffer-module (name|<str> => <module>)
  120. (or (elt-or (all-modules) (as-sym name) #f)
  121. (find-buffer-module 'nil)))
  122. (dm find-buffer-module (name|<nil> => <module>) default-module)
  123. (dv default-module|<module> (runtime-module 'goo/user))
  124. (d. slimefuns (fab <tab> 100))
  125. (ds defslimefun (,name ,args ,@body)
  126. `(set (elt slimefuns ',name)
  127. (df ,(cat-sym 'swank@ name) ,args ,@body)))
  128. (df slimefun (name)
  129. (or (elt-or slimefuns name #f)
  130. (error "Undefined slimefun: %=" name)))
  131. ;; rewrite (swank:foo ...) to ((slimefun 'foo) ...)
  132. (df frob-form-for-eval (form)
  133. (match form
  134. ((,op ,@args)
  135. (match (map as-sym (split (sym-name op) #\:))
  136. ((swank ,name)
  137. `((slimefun ',name) ,@args))))))
  138. ;;;; debugger
  139. (dc <sldb-context> (<any>))
  140. (dp @level (<sldb-context> => <int>))
  141. (dp @top-frame (<sldb-context> => <lst>))
  142. (dp @restarts (<sldb-context> => <lst>))
  143. (dp @condition (<sldb-context> => <condition>))
  144. (dp @eval-context (<sldb-context> => (t? <eval-context>)))
  145. (dv sldb-context|(t? <sldb-context>) #f)
  146. (df debugger-hook (c|<condition> resume)
  147. (let ((tf (find-top-frame 'debugger-hook 2))
  148. (rs (compute-restarts c))
  149. (l (if sldb-context (1+ (@level sldb-context)) 1)))
  150. (cond ((> l 10) (emergency-abort c))
  151. (#t
  152. (dlet ((sldb-context (new <sldb-context>
  153. @level l @top-frame tf
  154. @restarts rs @condition c
  155. @eval-context eval-context)))
  156. (let ((bt (compute-backtrace tf 0 10)))
  157. (force-out out)
  158. (dispatch-event `(:debug 0 ,l
  159. ,@(debugger-info c rs bt eval-context))
  160. (@port eval-context))
  161. (sldb-loop l (@port eval-context))))))))
  162. (df emergency-abort (c)
  163. (post "Maximum debug level reached aborting...\n")
  164. (post "%s\n" (describe-condition c))
  165. (do-stack-frames (fun (f args) (msg out " %= %=\n" f args)))
  166. (invoke-handler-interactively (find-restart <slime-toplevel>) in out))
  167. (df sldb-loop (level port)
  168. (fin (while #t
  169. (dispatch-event `(:debug-activate 0 ,level) port)
  170. (simple-restart
  171. <restart> (msg-to-str "Return to SLDB level %s" level)
  172. (fun () (process-next-event port))))
  173. (dispatch-event `(:debug-return 0 ,level nil) port)))
  174. (defslimefun backtrace (start|<int> end|(t+ <int> <nil>))
  175. (backtrace-for-emacs
  176. (compute-backtrace (@top-frame sldb-context)
  177. start
  178. (if (isa? end <int>) end #f))))
  179. (defslimefun throw-to-toplevel ()
  180. (invoke-handler-interactively (find-restart <slime-toplevel>) in out))
  181. (defslimefun invoke-nth-restart-for-emacs (sldb-level|<int> n|<int>)
  182. (when (= (@level sldb-context) sldb-level)
  183. (invoke-handler-interactively (elt (@restarts sldb-context) n) in out)))
  184. (defslimefun debugger-info-for-emacs (start end)
  185. (debugger-info (@condition sldb-context)
  186. (@restarts sldb-context)
  187. (compute-backtrace (@top-frame sldb-context)
  188. start
  189. (if (isa? end <int>) end #f))))
  190. (defslimefun frame-locals-and-catch-tags (frame-idx)
  191. (def frame (nth-frame frame-idx))
  192. (list
  193. (map-keyed (fun (i name)
  194. (lst ':name (sym-name name) ':id 0
  195. ':value (safe-write-to-string (frame-var-value frame i))))
  196. (frame-var-names frame))
  197. '()))
  198. (defslimefun inspect-frame-var (frame-idx var-idx)
  199. (reset-inspector)
  200. (inspect-object (frame-var-value (nth-frame frame-idx) var-idx)))
  201. (defslimefun inspect-current-condition ()
  202. (reset-inspector)
  203. (inspect-object (@condition sldb-context)))
  204. (defslimefun frame-source-location (frame-idx)
  205. (match (nth-frame frame-idx)
  206. ((,f ,@_)
  207. (or (emacs-src-loc f)
  208. `(:error ,(msg-to-str "No src-loc available for: %s" f))))))
  209. (defslimefun eval-string-in-frame (string frame-idx)
  210. (def frame (nth-frame frame-idx))
  211. (let ((names (frame-var-names frame))
  212. (values (frame-var-values frame)))
  213. (write-to-string
  214. (app (eval `(fun ,names ,(read-from-string string))
  215. (module-name (buffer-module)))
  216. values))))
  217. (df debugger-info (condition restarts backtrace eval-context)
  218. (lst `(,(try-or (fun () (describe-condition condition)) "<...>")
  219. ,(cat " [class: " (class-name-str condition) "]")
  220. ())
  221. (restarts-for-emacs restarts)
  222. (backtrace-for-emacs backtrace)
  223. (pending-continuations eval-context)))
  224. (df backtrace-for-emacs (backtrace)
  225. (map (fun (f)
  226. (match f
  227. ((,idx (,f ,@args))
  228. (lst idx (cat (if (fun-name f)
  229. (sym-name (fun-name f))
  230. (safe-write-to-string f))
  231. (safe-write-to-string args))))))
  232. backtrace))
  233. (df restarts-for-emacs (restarts)
  234. (map (fun (x) `(,(sym-name (class-name (%handler-condition-type x)))
  235. ,(describe-restart x)))
  236. restarts))
  237. (df describe-restart (restart)
  238. (describe-handler (%handler-info restart) (%handler-condition-type restart)))
  239. (df compute-restarts (condition)
  240. (packing (%do-handlers-of-type <restart> (fun (c) (pack c)))))
  241. (df find-restart (type)
  242. (esc ret
  243. (%do-handlers-of-type type ret)
  244. #f))
  245. (df pending-continuations (context|(t? <eval-context>))
  246. (if context
  247. (pair (@id context) (pending-continuations (@prev context)))
  248. '()))
  249. (df find-top-frame (fname|<sym> offset|<int>)
  250. (esc ret
  251. (let ((top-seen? #f))
  252. (do-stack-frames (fun (f args)
  253. (cond (top-seen?
  254. (cond ((== offset 0)
  255. (ret (pair f args)))
  256. (#t (decf offset))))
  257. ((== (fun-name f) fname)
  258. (set top-seen? #t))))))))
  259. (df compute-backtrace (top-frame start|<int> end)
  260. (packing
  261. (esc break
  262. (do-user-frames (fun (idx f args)
  263. (when (and end (<= end idx))
  264. (break #f))
  265. (when (<= start idx)
  266. (pack (lst idx (pair f args)))))
  267. top-frame))))
  268. (df nth-frame (n|<int>)
  269. (esc ret
  270. (do-user-frames
  271. (fun (idx f args)
  272. (when (= idx n)
  273. (ret (pair f args))))
  274. (@top-frame sldb-context))))
  275. (df frame-var-value (frame var-idx)
  276. (match frame
  277. ((,f ,@args)
  278. (def sig (fun-sig f))
  279. (def arity (sig-arity sig))
  280. (def nary? (sig-nary? sig))
  281. (cond ((< var-idx arity) (elt args var-idx))
  282. (nary? (sub* args arity))))))
  283. (df frame-var-names (frame)
  284. (match frame
  285. ((,f ,@_) (fun-info-names (fun-info f)))))
  286. (df frame-var-values (frame)
  287. (map (curry frame-var-value frame) (keys (frame-var-names frame))))
  288. (df do-user-frames (f|<fun> top-frame)
  289. (let ((idx -1)
  290. (top-seen? #f))
  291. (do-stack-frames
  292. (fun (ffun args)
  293. (cond (top-seen?
  294. (incf idx)
  295. (f idx ffun (rev args)))
  296. ((= (pair ffun args) top-frame)
  297. (set top-seen? #t)))))))
  298. ;;;; Write some classes a little less verbose
  299. ;; (dm recurring-write (port|<out-port> x d|<int> recur|<fun>)
  300. ;; (msg port "#{%s &%s}" (class-name-str x)
  301. ;; (num-to-str-base (address-of x) 16)))
  302. (dm recurring-write (port|<out-port> x|<module> d|<int> recur|<fun>)
  303. (msg port "#{%s %s}" (class-name-str x) (module-name x)))
  304. (dm recurring-write (port|<out-port> x|<module-binding> d|<int> recur|<fun>)
  305. (msg port "#{%s %s}" (class-name-str x) (binding-name x)))
  306. (dm recurring-write (port|<out-port> x|<tab> d|<int> recur|<fun>)
  307. (msg port "#{%s %s}" (class-name-str x) (len x)))
  308. (dm recurring-write (port|<out-port> x|<static-global-environment>
  309. d|<int> recur|<fun>)
  310. (msg port "#{%s}" (class-name-str x)))
  311. (dm recurring-write (port|<out-port> x|<regular-application>
  312. d|<int> recur|<fun>)
  313. (msg port "#{%s}" (class-name-str x)))
  314. (dm recurring-write (port|<out-port> x|<src-loc> d|<int> recur|<fun>)
  315. (msg port "#{%s %s:%=}" (class-name-str x)
  316. (src-loc-file x) (src-loc-line x)))
  317. ;;;; Inspector
  318. (dc <inspector> (<any>))
  319. (dp! @object (<inspector> => <any>))
  320. (dp! @parts (<inspector> => <vec>) (new <vec>))
  321. (dp! @stack (<inspector> => <lst>) '())
  322. (dv inspector #f)
  323. (defslimefun init-inspector (form|<str>)
  324. (reset-inspector)
  325. (inspect-object (str-eval form (buffer-module))))
  326. (defslimefun quit-inspector () (reset-inspector) 'nil)
  327. (defslimefun inspect-nth-part (n|<int>)
  328. (inspect-object (elt (@parts inspector) n)))
  329. (defslimefun inspector-pop ()
  330. (cond ((<= 2 (len (@stack inspector)))
  331. (popf (@stack inspector))
  332. (inspect-object (popf (@stack inspector))))
  333. (#t 'nil)))
  334. (df reset-inspector () (set inspector (new <inspector>)))
  335. (df inspect-object (o)
  336. (set (@object inspector) o)
  337. (set (@parts inspector) (new <vec>))
  338. (pushf (@stack inspector) o)
  339. (lst ':title (safe-write-to-string o) ; ':type (class-name-str o)
  340. ':content (inspector-content
  341. `("class: " (:value ,(class-of o)) "\n"
  342. ,@(inspect o)))))
  343. (df inspector-content (content)
  344. (map (fun (part)
  345. (case-by part isa?
  346. ((<str>) part)
  347. ((<lst>)
  348. (match part
  349. ((:value ,o ,@str)
  350. `(:value ,@(if (nul? str)
  351. (lst (safe-write-to-string o))
  352. str)
  353. ,(assign-index o)))))
  354. (#t (error "Bad inspector content: %=" part))))
  355. content))
  356. (df assign-index (o)
  357. (pushf (@parts inspector) o)
  358. (1- (len (@parts inspector))))
  359. (dg inspect (o))
  360. ;; a list of dangerous functions
  361. (d. getter-blacklist (lst fun-code fun-env class-row))
  362. (dm inspect (o)
  363. (join (map (fun (p)
  364. (let ((getter (prop-getter p)))
  365. `(,(sym-name (fun-name getter)) ": "
  366. ,(cond ((mem? getter-blacklist getter) "<...>")
  367. ((not (prop-bound? o getter)) "<unbound>")
  368. (#t (try-or (fun () `(:value ,(getter o)))
  369. "<...>"))))))
  370. (class-props (class-of o)))
  371. '("\n")))
  372. (dm inspect (o|<seq>)
  373. (join (packing (do-keyed (fun (pos val)
  374. (pack `(,(num-to-str pos) ": " (:value ,val))))
  375. o))
  376. '("\n")))
  377. (dm inspect (o|<tab>)
  378. (join (packing (do-keyed (fun (key val)
  379. (pack `((:value ,key) "\t: " (:value ,val))))
  380. o))
  381. '("\n")))
  382. ;; inspecting the env of closures is broken
  383. ;; (dm inspect (o|<met>)
  384. ;; (cat (sup o)
  385. ;; '("\n")
  386. ;; (if (%fun-env? o)
  387. ;; (inspect (packing (for ((i (below (%fun-env-len o))))
  388. ;; (pack (%fun-env-elt o i)))))
  389. ;; '())))
  390. ;;
  391. ;; (df %fun-env? (f|<met> => <log>) #eb{ FUNENV($f) != $#f })
  392. ;; (df %fun-env-len (f|<met> => <int>) #ei{ ((ENV)FUNENV ($f))->size })
  393. ;; (df %fun-env-elt (f|<met> i|<int> => <any>) #eg{ FUNENVGET($f, @i) })
  394. ;;;; init
  395. (defslimefun connection-info ()
  396. `(:pid
  397. ,(process-id) :style nil
  398. :lisp-implementation (:type "GOO" :name "goo"
  399. :version ,(%lookup '*goo-version* 'eval/main))
  400. :machine (:instance "" :type "" :version "")
  401. :features ()
  402. :package (:name "goo/user" :prompt "goo/user")))
  403. (defslimefun quit-lisp () #ei{ exit (0),0 })
  404. (defslimefun set-default-directory (dir|<str>) #ei{ chdir(@dir) } dir)
  405. ;;;; eval
  406. (defslimefun ping () "PONG")
  407. (defslimefun create-repl (_)
  408. (let ((name (sym-name (module-name (buffer-module)))))
  409. `(,name ,name)))
  410. (defslimefun listener-eval (string)
  411. (clear-input in)
  412. `(:values ,(write-to-string (str-eval string (buffer-module)))))
  413. (defslimefun interactive-eval (string)
  414. (cat "=> " (write-to-string (str-eval string (buffer-module)))))
  415. (df str-eval (s|<str> m|<module>)
  416. (eval (read-from-string s) (module-name m)))
  417. (df clear-input (in|<in-port>) (while (ready? in) (get in)))
  418. (dc <break> (<restart>))
  419. (defslimefun simple-break ()
  420. (simple-restart
  421. <break> "Continue from break"
  422. (fun () (sig (new <simple-condition>
  423. condition-message "Interrupt from Emacs"))))
  424. 'nil)
  425. (defslimefun clear-repl-results () 'nil)
  426. ;;;; compile
  427. (defslimefun compile-string-for-emacs (string buffer position directory)
  428. (def start (current-time))
  429. (def r (g2c-eval (read-from-string string)
  430. (module-target-environment (buffer-module))))
  431. (lst (write-to-string r)
  432. (/ (as <flo> (- (current-time) start)) 1000000.0)))
  433. (defslimefun compiler-notes-for-emacs () 'nil)
  434. (defslimefun filename-to-modulename (filename|<str> => (t+ <str> <nil>))
  435. (try-or (fun () (sym-name (filename-to-modulename filename))) 'nil))
  436. (df filename-to-modulename (filename|<str> => <sym>)
  437. (def paths (map pathname-to-components
  438. (map simplify-filename
  439. (pick file-exists? *module-search-path*))))
  440. (def filename (pathname-to-components filename))
  441. (def moddir (rep parent ((modpath filename))
  442. (cond ((any? (curry = modpath) paths)
  443. modpath)
  444. (#t
  445. (parent (components-parent-directory modpath))))))
  446. (def modfile (components-to-pathname (sub* filename (len moddir))))
  447. (as-sym (sub modfile 0 (- (len modfile) (len *goo-extension*)))))
  448. ;;;; Load
  449. (defslimefun load-file (filename)
  450. (let ((file (cond ((= (sub (rev filename) 0 4) "oog.") filename)
  451. (#t (cat filename ".goo")))))
  452. (safe-write-to-string (load-file file (filename-to-modulename file)))))
  453. ;;;; background activities
  454. (defslimefun operator-arglist (op _)
  455. (try-or (fun ()
  456. (let ((value (str-eval op (buffer-module))))
  457. (if (isa? value <fun>)
  458. (write-to-string value)
  459. 'nil)))
  460. 'nil))
  461. ;;;; M-.
  462. (defslimefun find-definitions-for-emacs (name|<str>)
  463. (match (parse-symbol name)
  464. ((,sym ,modname)
  465. (def env (module-target-environment (runtime-module modname)))
  466. (def b (find-binding sym env))
  467. (cond (b (find-binding-definitions b))
  468. (#t 'nil)))))
  469. (df parse-symbol (name|<str> => <lst>)
  470. (if (mem? name #\:)
  471. (match (split name #\:)
  472. ((,module ,name) (lst (as-sym name) (as-sym module))))
  473. (lst (as-sym name) (module-name (buffer-module)))))
  474. (df find-binding-definitions (b|<binding>)
  475. (def value (case (binding-kind b)
  476. (('runtime) (loc-val (binding-locative b)))
  477. (('global) (let ((box (binding-global-box b)))
  478. (and box (global-box-value box))))
  479. (('macro) (binding-info b))
  480. (#t (error "unknown binding kind %=" (binding-kind b)))))
  481. (map (fun (o)
  482. (def loc (emacs-src-loc o))
  483. `(,(write-to-string (dspec o))
  484. ,(or loc `(:error "no src-loc available"))))
  485. (defining-objects value)))
  486. (dm defining-objects (o => <lst>) '())
  487. (dm defining-objects (o|<fun> => <lst>) (lst o))
  488. (dm defining-objects (o|<gen> => <lst>) (pair o (fun-mets o)))
  489. (dm emacs-src-loc (o|<fun>)
  490. (def loc (fun-src-loc o))
  491. (and loc `(:location (:file ,(simplify-filename
  492. (find-goo-file-in-path
  493. (module-name-to-relpath (src-loc-file loc))
  494. *module-search-path*)))
  495. (:line ,(src-loc-line loc))
  496. ())))
  497. (dm dspec (f|<fun>)
  498. (cond ((fun-name f)
  499. `(,(if (isa? f <gen>) 'dg 'dm) ,(fun-name f) ,@(dspec-arglist f)))
  500. (#t f)))
  501. (df dspec-arglist (f|<fun>)
  502. (map2 (fun (name class)
  503. (cond ((= class <any>) name)
  504. ((isa? class <class>)
  505. `(,name ,(class-name class)))
  506. (#t `(,name ,class))))
  507. (fun-info-names (fun-info f))
  508. (sig-specs (fun-sig f))))
  509. (defslimefun buffer-first-change (filename) 'nil)
  510. ;;;; apropos
  511. (defslimefun apropos-list-for-emacs
  512. (pattern only-external? case-sensitive? package)
  513. (def matches (fab <tab> 100))
  514. (do-all-bindings
  515. (fun (b)
  516. (when (finds (binding-name-str b) pattern)
  517. (set (elt matches
  518. (cat-sym (binding-name b)
  519. (module-name (binding-module b))))
  520. b))))
  521. (set matches (sort-by (packing-as <vec> (for ((b matches)) (pack b)))
  522. (fun (x y)
  523. (< (binding-name x)
  524. (binding-name y)))))
  525. (map (fun (b)
  526. `(:designator
  527. ,(cat (sym-name (module-name (binding-module b))) ":"
  528. (binding-name-str b)
  529. "\tkind: " (sym-name (binding-kind b)))))
  530. (as <lst> matches)))
  531. (df do-all-bindings (f|<fun>)
  532. (for ((module (%module-loader-modules (runtime-module-loader))))
  533. (do f (environment-bindings (module-target-environment module)))))
  534. (dm < (s1|<str> s2|<str> => <log>)
  535. (let ((l1 (len s1)) (l2 (len s2)))
  536. (rep loop ((i 0))
  537. (cond ((= i l1) (~= l1 l2))
  538. ((= i l2) #f)
  539. ((< (elt s1 i) (elt s2 i)) #t)
  540. ((= (elt s1 i) (elt s2 i)) (loop (1+ i)))
  541. (#t #f)))))
  542. (df %binding-info (name|<sym> module|<sym>)
  543. (binding-info
  544. (find-binding
  545. name (module-target-environment (runtime-module module)))))
  546. ;;;; completion
  547. (defslimefun simple-completions (pattern|<str> package)
  548. (def matches (lst))
  549. (for ((b (environment-bindings (module-target-environment (buffer-module)))))
  550. (when (prefix? (binding-name-str b) pattern)
  551. (pushf matches b)))
  552. (def strings (map binding-name-str matches))
  553. `(,strings ,(cond ((nul? strings) pattern)
  554. (#t (fold+ common-prefix strings)))))
  555. (df common-prefix (s1|<seq> s2|<seq>)
  556. (let ((limit (min (len s1) (len s2))))
  557. (rep loop ((i 0))
  558. (cond ((or (= i limit)
  559. (~= (elt s1 i) (elt s2 i)))
  560. (sub s1 0 i))
  561. (#t (loop (1+ i)))))))
  562. (defslimefun list-all-package-names (_|...)
  563. (map sym-name (keys (all-modules))))
  564. (df all-modules () (%module-loader-modules (runtime-module-loader)))
  565. ;;;; Macroexpand
  566. (defslimefun swank-macroexpand-1 (str|<str>)
  567. (write-to-string
  568. (%ast-macro-expand (read-from-string str)
  569. (module-target-environment (buffer-module))
  570. #f)))
  571. ;;;; streams
  572. (dc <slime-out-port> (<out-port>))
  573. (dp @socket (<slime-out-port> => <port>))
  574. (dp! @buf-len (<slime-out-port> => <int>) 0)
  575. (dp @buf (<slime-out-port> => <vec>) (new <vec>))
  576. (dp! @timestamp (<slime-out-port> => <int>) 0)
  577. (dm recurring-write (port|<out-port> x|<slime-out-port> d|<int> recur|<fun>)
  578. (msg port "#{%s buf-len: %s}" (class-name-str x) (@buf-len x)))
  579. (dm put (p|<slime-out-port> c|<chr>)
  580. (add! (@buf p) c)
  581. (incf (@buf-len p))
  582. (maybe-flush p (= c #\newline)))
  583. (dm puts (p|<slime-out-port> s|<str>)
  584. (add! (@buf p) s)
  585. (incf (@buf-len p) (len s))
  586. (maybe-flush p (mem? s #\newline)))
  587. (df maybe-flush (p|<slime-out-port> newline?|<log>)
  588. (and (or (> (@buf-len p) 4000) newline?)
  589. (> (- (current-time) (@timestamp p)) 100000)
  590. (force-out p)))
  591. (dm force-out (p|<slime-out-port>)
  592. (unless (zero? (@buf-len p))
  593. (dispatch-event `(:write-string ,(%buf-to-str (@buf p))) (@socket p))
  594. (set (@buf-len p) 0)
  595. (zap! (@buf p)))
  596. (set (@timestamp p) (current-time)))
  597. (df %buf-to-str (buf|<vec>)
  598. (packing-as <str>
  599. (for ((i buf))
  600. (cond ((isa? i <str>) (for ((c i)) (pack c)))
  601. (#t (pack i))))))
  602. (dc <slime-in-port> (<in-port>))
  603. (dp @socket (<slime-in-port> => <port>))
  604. (dp! @idx (<slime-in-port> => <int>) 0)
  605. (dp! @buf (<slime-in-port> => <str>) "")
  606. (df receive-input (p|<slime-in-port>)
  607. (dispatch-event `(:read-string ,0) (@socket p)))
  608. (dm get (p|<slime-in-port> => <chr>)
  609. (cond ((< (@idx p) (len (@buf p)))
  610. (def c (elt (@buf p) (@idx p)))
  611. (incf (@idx p))
  612. c)
  613. (#t
  614. (def input (receive-input p))
  615. (cond ((zero? (len input)) (eof-object))
  616. (#t (set (@buf p) input)
  617. (set (@idx p) 0)
  618. (get p))))))
  619. (dm ready? (p|<slime-in-port> => <log>) (< (@idx p) (len (@buf p))))
  620. (dm peek (p|<slime-in-port> => <chr>)
  621. (let ((c (get p)))
  622. (unless (eof-object? c)
  623. (decf (@idx p)))
  624. c))
  625. ;;;; Message encoding
  626. (df decode-message (port|<in-port>)
  627. (read-from-string (get-block port (read-message-length port))))
  628. (df read-message-length (port)
  629. (or (str-to-num (cat "#x" (get-block port 6)))
  630. (error "can't parse message length")))
  631. (df encode-message (message port)
  632. (let ((string (dlet ((*max-print-length* 1000000)
  633. (*max-print-depth* 1000000))
  634. (write-to-string message))))
  635. (puts port (encode-message-length (len string)))
  636. (puts port string)
  637. (force-out port)))
  638. (df encode-message-length (n)
  639. (loc ((hex (byte)
  640. (if (< byte #x10)
  641. (cat "0" (num-to-str-base byte 16))
  642. (num-to-str-base byte 16)))
  643. (byte (i) (hex (& (>> n (* i 8)) 255))))
  644. (cat (byte 2) (byte 1) (byte 0))))
  645. ;;;; semi general utilities
  646. ;; Return the name of O's class as string.
  647. (df class-name-str (o => <str>) (sym-name (class-name (class-of o))))
  648. (df binding-name-str (b|<binding> => <str>) (sym-name (binding-name b)))
  649. (df as-sym (str|<str>) (as <sym> str))
  650. ;; Replace '//' in the middle of a filename with with a '/'
  651. (df simplify-filename (str|<str> => <str>)
  652. (match (pathname-to-components str)
  653. ((,hd ,@tl)
  654. (components-to-pathname (cons hd (del-vals tl 'root))))))
  655. ;; Execute BODY and only if BODY exits abnormally execute RECOVER.
  656. (df try-recover (body recover)
  657. (let ((ok #f))
  658. (fin (let ((val (body)))
  659. (set ok #t)
  660. val)
  661. (unless ok
  662. (recover)))))
  663. ;; like CL's IGNORE-ERRORS but return VALUE in case of an error.
  664. (df try-or (body|<fun> value)
  665. (esc ret
  666. (try <error> (fun (condition resume) (ret value))
  667. (body))))
  668. (df simple-restart (type msg body)
  669. (esc restart
  670. (try ((type type) (description msg))
  671. (fun (c r) (restart #f))
  672. (body))))
  673. (df safe-write-to-string (o)
  674. (esc ret
  675. (try <error> (fun (c r)
  676. (ret (cat "#<error during write " (class-name-str o) ">")))
  677. (write-to-string o))))
  678. ;; Read a string of length COUNT.
  679. (df get-block (port|<in-port> count|<int> => <str>)
  680. (packing-as <str>
  681. (for ((i (below count)))
  682. (let ((c (get port)))
  683. (cond ((eof-object? c)
  684. (error "Premature EOF (read %d of %d)" i count))
  685. (#t (pack c)))))))
  686. ;;;; import some internal bindings
  687. (df %lookup (name|<sym> module|<sym>)
  688. (loc-val
  689. (binding-locative
  690. (find-binding
  691. name (module-target-environment (runtime-module module))))))
  692. (d. %handler-info (%lookup 'handler-info 'goo/conditions))
  693. (d. %handler-condition-type (%lookup 'handler-condition-type 'goo/conditions))
  694. (d. %do-handlers-of-type (%lookup 'do-handlers-of-type 'goo/conditions))
  695. (d. %module-loader-modules (%lookup 'module-loader-modules 'eval/module))
  696. (d. %ast-macro-expand (%lookup 'ast-macro-expand 'eval/ast))
  697. ;;;; low level socket stuff
  698. ;;; this shouldn't be here
  699. #{
  700. #include <sys/types.h>
  701. #include <sys/socket.h>
  702. #include <netinet/in.h>
  703. #include <errno.h>
  704. #include <string.h>
  705. #include <stdlib.h>
  706. #include <sys/time.h>
  707. /* convert a goo number to a C long */
  708. static long g2i (P o) { return untag (o); }
  709. static int
  710. set_reuse_address (int socket, int value) {
  711. return setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, &value, sizeof value);
  712. }
  713. static int
  714. bind_socket (int socket, int port) {
  715. struct sockaddr_in addr;
  716. addr.sin_family = AF_INET;
  717. addr.sin_port = htons (port);
  718. addr.sin_addr.s_addr = htonl (INADDR_ANY);
  719. return bind (socket, (struct sockaddr *)&addr, sizeof addr);
  720. }
  721. static int
  722. local_port (int socket) {
  723. struct sockaddr_in addr;
  724. socklen_t len = sizeof addr;
  725. int code = getsockname (socket, (struct sockaddr *)&addr, &len);
  726. return (code == -1) ? -1 : ntohs (addr.sin_port);
  727. }
  728. static int
  729. c_accept (int socket) {
  730. struct sockaddr_in addr;
  731. socklen_t len = sizeof addr;
  732. return accept (socket, (struct sockaddr *)&addr, &len);
  733. }
  734. static P tup3 (P e0, P e1, P e2) {
  735. P tup = YPPtfab ((P)3, YPfalse);
  736. YPtelt_setter (e0, tup, (P)0);
  737. YPtelt_setter (e1, tup, (P)1);
  738. YPtelt_setter (e2, tup, (P)2);
  739. return tup;
  740. }
  741. static P
  742. current_time (void) {
  743. struct timeval timeval;
  744. int code = gettimeofday (&timeval, NULL);
  745. if (code == 0) {
  746. return tup3 (YPib ((P)(timeval.tv_sec >> 24)),
  747. YPib ((P)(timeval.tv_sec & 0xffffff)),
  748. YPib ((P)(timeval.tv_usec)));
  749. } else return YPib ((P)errno);
  750. }
  751. }
  752. ;; Return the current time in microsecs
  753. (df current-time (=> <int>)
  754. (def t #eg{ current_time () })
  755. (cond ((isa? t <int>) (error "%s" (strerror t)))
  756. (#t (+ (* (+ (<< (1st t) 24)
  757. (2nd t))
  758. 1000000)
  759. (3rd t)))))
  760. (dm strerror (e|<int> => <str>) #es{ strerror (g2i ($e)) })
  761. (dm strerror (e|(t= #f) => <str>) #es{ strerror (errno) })
  762. (df checkr (value|<int>)
  763. (cond ((~== value -1) value)
  764. (#t (error "%s" (strerror #f)))))
  765. (df create-socket (port|<int> => <int>)
  766. (let ((socket (checkr #ei{ socket (PF_INET, SOCK_STREAM, 0) })))
  767. (checkr #ei{ set_reuse_address (g2i ($socket), 1) })
  768. (checkr #ei{ bind_socket (g2i ($socket), g2i ($port)) })
  769. (checkr #ei{ listen (g2i ($socket), 1)})
  770. socket))
  771. (df %local-port (fd|<int>) (checkr #ei{ local_port (g2i ($fd)) }))
  772. (df %close (fd|<int>) (checkr #ei{ close (g2i ($fd)) }))
  773. (dc <fd-io-port> (<in-port> <out-port>))
  774. (dp @fd (<fd-io-port> => <int>))
  775. (dp @in (<fd-io-port> => <file-in-port>))
  776. (dp @out (<fd-io-port> => <file-out-port>))
  777. (dm recurring-write (port|<out-port> x|<fd-io-port> d|<int> recur|<fun>)
  778. (msg port "#{%s fd: %s}" (class-name-str x) (@fd x)))
  779. (dm get (port|<fd-io-port> => <chr>) (get (@in port)))
  780. (dm puts (port|<fd-io-port> s|<str>) (puts (@out port) s))
  781. (dm force-out (port|<fd-io-port>) (force-out (@out port)))
  782. (dm fdopen (fd|<int> type|(t= <fd-io-port>) => <fd-io-port>)
  783. (new <fd-io-port> @fd fd
  784. @in (new <file-in-port> port-handle (%fdopen fd "r"))
  785. @out (new <file-out-port> port-handle (%fdopen fd "w"))))
  786. (df %fdopen (fd|<int> mode|<str> => <loc>)
  787. (def addr #ei{ fdopen (g2i ($fd), @mode) })
  788. (when (zero? addr)
  789. (error "fdopen failed: %s" (strerror #f)))
  790. (%lb (%iu addr)))
  791. (df accept (socket|<int> => <fd-io-port>)
  792. (fdopen (checkr #ei{ c_accept (g2i ($socket)) }) <fd-io-port>))
  793. (export
  794. start-swank
  795. create-server)
  796. ;;; swank-goo.goo ends here