/[slime]/slime/swank-backend.lisp
ViewVC logotype

Contents of /slime/swank-backend.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (show annotations)
Thu Jan 15 11:42:12 2004 UTC (10 years, 3 months ago) by lgorrie
Branch: MAIN
Changes since 1.16: +13 -50 lines
Changed multiprocessing interface.
1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil; outline-regexp: ";;;;;*" -*-
2 ;;;
3 ;;; slime-backend.lisp --- SLIME backend interface.
4 ;;;
5 ;;; Created by James Bielman in 2003. Released into the public domain.
6 ;;;
7 ;;; This file defines the functions that must be implemented
8 ;;; separately for each Lisp. Each is declared as a generic function
9 ;;; for which swank-<implementation>.lisp provides methods.
10
11 (defpackage :swank
12 (:use :common-lisp)
13 (:nicknames #:swank-backend)
14 (:export #:*sldb-pprint-frames*
15 #:apropos-list-for-emacs
16 #:arglist-string
17 #:backtrace
18 #:call-with-I/O-lock
19 #:call-with-conversation-lock
20 #:compiler-notes-for-emacs
21 #:completions
22 #:create-server
23 #:create-swank-server
24 #:describe-alien-enum
25 #:describe-alien-struct
26 #:describe-alien-type
27 #:describe-alien-union
28 #:describe-class
29 #:describe-function
30 #:describe-inspectee
31 #:describe-setf-function
32 #:describe-symbol
33 #:describe-type
34 #:disassemble-symbol
35 #:documentation-symbol
36 #:eval-in-frame
37 #:eval-string
38 #:eval-string-in-frame
39 #:find-function-locations
40 #:frame-catch-tags
41 #:frame-locals
42 #:frame-source-location-for-emacs
43 #:frame-source-position
44 #:getpid
45 #:give-goahead
46 #:give-gohead
47 #:init-inspector
48 #:inspect-in-frame
49 #:inspect-nth-part
50 #:inspector-next
51 #:inspector-pop
52 #:interactive-eval
53 #:interactive-eval-region
54 #:invoke-nth-restart
55 #:invoke-nth-restart-for-emacs
56 #:list-all-package-names
57 #:list-callees
58 #:list-callers
59 #:listener-eval
60 #:load-file
61 #:pprint-eval
62 #:pprint-eval-string-in-frame
63 #:quit-inspector
64 #:re-evaluate-defvar
65 #:set-default-directory
66 #:set-package
67 #:sldb-abort
68 #:sldb-break-with-default-debugger
69 #:sldb-continue
70 #:slime-debugger-function
71 #:start-server
72 #:startup-multiprocessing
73 #:startup-multiprocessing-for-emacs
74 #:swank-compile-file
75 #:swank-compile-string
76 #:swank-macroexpand
77 #:swank-macroexpand-1
78 #:swank-macroexpand-all
79 #:take-input
80 #:thread-id
81 #:thread-name
82 #:throw-to-toplevel
83 #:toggle-trace-fdefinition
84 #:untrace-all
85 #:wait-goahead
86 #:who-binds
87 #:who-calls
88 #:who-macroexpands
89 #:who-references
90 #:who-sets
91 ))
92
93 (in-package :swank)
94
95
96 ;;;; TCP server
97
98 (defgeneric create-socket (port)
99 (:documentation "Create a listening TCP socket on port PORT."))
100
101 (defgeneric local-port (socket)
102 (:documentation "Return the local port number of SOCKET."))
103
104 (defgeneric close-socket (socket)
105 (:documentation "Close the socket SOCKET."))
106
107 (defgeneric accept-connection (socket)
108 (:documentation
109 "Accept a client connection on the listening socket SOCKET. Return
110 a stream for the new connection."))
111
112 (defgeneric add-input-handler (socket fn)
113 (:documentation "Call FN whenever SOCKET is readable."))
114
115 ;;; Base condition for networking errors.
116 (define-condition network-error (error) ())
117
118 (defgeneric emacs-connected ()
119 (:documentation
120 "Hook called when the first connection from Emacs is established.
121 Called from the INIT-FN of the socket server that accepts the
122 connection.
123
124 This is intended for setting up extra context, e.g. to discover
125 that the calling thread is the one that interacts with Emacs."))
126
127 (defmethod no-applicable-method ((m (eql #'emacs-connected)) &rest _)
128 (declare (ignore _))
129 nil)
130
131
132 ;;;; Compilation
133
134 (defgeneric call-with-compilation-hooks (func)
135 (:documentation
136 "Call FUNC with hooks to trigger SLDB on compiler errors."))
137
138 (defmacro with-compilation-hooks ((&rest ignore) &body body)
139 (declare (ignore ignore))
140 `(call-with-compilation-hooks (lambda () (progn ,@body))))
141
142 (defgeneric compile-string-for-emacs (string &key buffer position)
143 (:documentation
144 "Compile source from STRING. During compilation, compiler
145 conditions must be trapped and resignalled as COMPILER-CONDITIONs.
146
147 If supplied, BUFFER and POSITION specify the source location in Emacs.
148
149 Additionally, if POSITION is supplied, it must be added to source
150 positions reported in compiler conditions."))
151
152 (defgeneric compile-file-for-emacs (filename load-p)
153 (:documentation
154 "Compile FILENAME signalling COMPILE-CONDITIONs.
155 If LOAD-P is true, load the file after compilation."))
156
157 (deftype severity () '(member :error :warning :style-warning :note))
158
159 ;; Base condition type for compiler errors, warnings and notes.
160 (define-condition compiler-condition (condition)
161 ((original-condition
162 ;; The original condition thrown by the compiler if appropriate.
163 ;; May be NIL if a compiler does not report using conditions.
164 :type (or null condition)
165 :initarg :original-condition
166 :accessor original-condition)
167
168 (severity :type severity
169 :initarg :severity
170 :accessor severity)
171
172 (message :initarg :message
173 :accessor message)
174
175 (location :initarg :location
176 :accessor location)))
177
178
179 ;;;; Streams
180
181 (defgeneric make-fn-streams (input-fn output-fn)
182 (:documentation
183 "Return character input and output streams backended by functions.
184 When input is needed, INPUT-FN is called with no arguments to
185 return a string.
186 When output is ready, OUTPUT-FN is called with the output as its
187 argument.
188
189 Output should be forced to OUTPUT-FN before calling INPUT-FN.
190
191 The streams are returned as two values."))
192
193
194 ;;;; Documentation
195
196 (defgeneric arglist-string (function-name)
197 (:documentation
198 "Return the argument for FUNCTION-NAME as a string.
199 The result should begin and end with parenthesis."))
200
201 (defgeneric macroexpand-all (form)
202 (:documentation
203 "Recursively expand all macros in FORM.
204 Return the resulting form."))
205
206 (defgeneric describe-symbol-for-emacs (symbol)
207 (:documentation
208 "Return a property list describing SYMBOL.
209
210 The property list has an entry for each interesting aspect of the
211 symbol. The recognised keys are:
212
213 :VARIABLE :FUNCTION :SETF :TYPE :CLASS :MACRO :COMPILER-MACRO
214 :ALIEN-TYPE :ALIEN-STRUCT :ALIEN-UNION :ALIEN-ENUM
215
216 The value of each property is the corresponding documentation string,
217 or :NOT-DOCUMENTED. It is legal to include keys not listed here.
218
219 Properties should be included if and only if they are applicable to
220 the symbol. For example, only (and all) fbound symbols should include
221 the :FUNCTION property.
222
223 Example:
224 \(describe-symbol-for-emacs 'vector)
225 => (:CLASS :NOT-DOCUMENTED
226 :TYPE :NOT-DOCUMENTED
227 :FUNCTION \"Constructs a simple-vector from the given objects.\")"))
228
229
230 ;;;; Debugging
231
232 (defgeneric call-with-debugging-environment (debugger-loop-fn)
233 (:documentation
234 "Call DEBUGGER-LOOP-FN in a suitable debugging environment.
235
236 This function is called recursively at each debug level to invoke the
237 debugger loop. The purpose is to setup any necessary environment for
238 other debugger callbacks that will be called within the debugger loop.
239
240 For example, this is a reasonable place to compute a backtrace, switch
241 to safe reader/printer settings, and so on."))
242
243 (define-condition sldb-condition (condition)
244 ((original-condition
245 :initarg :original-condition
246 :accessor original-condition))
247 (:documentation
248 "Wrapper for conditions that should not be debugged.
249
250 When a condition arises from the internals of the debugger, it is not
251 desirable to debug it -- we'd risk entering an endless loop trying to
252 debug the debugger! Instead, such conditions can be reported to the
253 user without (re)entering the debugger by wrapping them as
254 `sldb-condition's."))
255
256 (defgeneric debugger-info-for-emacs (start end)
257 (:documentation
258 "Return debugger state, with stack frames from START to END.
259 The result is a list:
260 (condition ({restart}*) ({stack-frame}*)
261 where
262 condition ::= (description type)
263 restart ::= (name description)
264 stack-frame ::= (number description)
265
266 condition---a pair of strings: message, and type.
267
268 restart---a pair of strings: restart name, and description.
269
270 stack-frame---a number from zero (the top), and a printed
271 representation of the frame's call.
272
273 Below is an example return value. In this case the condition was a
274 division by zero (multi-line description), and only one frame is being
275 fetched (start=0, end=1).
276
277 ((\"Arithmetic error DIVISION-BY-ZERO signalled.
278 Operation was KERNEL::DIVISION, operands (1 0).\"
279 \"[Condition of type DIVISION-BY-ZERO]\")
280 ((\"ABORT\" \"Return to Slime toplevel.\")
281 (\"ABORT\" \"Return to Top-Level.\"))
282 ((0 \"(KERNEL::INTEGER-/-INTEGER 1 0)\")))"))
283
284 (defgeneric backtrace (start end)
285 (:documentation
286 "Return a list containing a backtrace of the condition current
287 being debugged. The results are unspecified if this function is
288 called outside the dynamic contour of a debugger hook defined by
289 DEFINE-DEBUGGER-HOOK.
290
291 START and END are zero-based indices constraining the number of
292 frames returned. Frame zero is defined as the frame which invoked
293 the debugger.
294
295 The backtrace is returned as a list of tuples of the form
296 \(FRAME-NUMBER FRAME-DESCRIPTION), where FRAME-NUMBER is the
297 index of the frame, defined like START/END, and FRAME-DESCRIPTION
298 is a string containing text to display in the debugger for this
299 frame.
300
301 An example return value:
302
303 ((0 \"(HELLO \"world\")\")
304 (1 \"(RUN-EXCITING-LISP-DEMO)\")
305 (2 \"(SYS::%TOPLEVEL #<SYS::ENVIRONMENT #x394834>)\"))"))
306
307 (defgeneric frame-source-location-for-emacs (frame-number)
308 (:documentation
309 "Return the source location for FRAME-NUMBER."))
310
311 (defgeneric frame-catch-tags (frame-number)
312 (:documentation
313 "Return a list of XXX list of what? catch tags for a debugger
314 stack frame. The results are undefined unless this is called
315 within the dynamic contour of a function defined by
316 DEFINE-DEBUGGER-HOOK."))
317
318 (defgeneric frame-locals (frame-number)
319 (:documentation
320 "Return a list of XXX local variable designators define me
321 for a debugger stack frame. The results are undefined unless
322 this is called within the dynamic contour of a function defined
323 by DEFINE-DEBUGGER-HOOK."))
324
325 (defgeneric eval-in-frame (form frame-number)
326 (:documentation
327 "Evaluate a Lisp form in the lexical context of a stack frame
328 in the debugger. The results are undefined unless called in the
329 dynamic contour of a function defined by DEFINE-DEBUGGER-HOOK.
330
331 FRAME-NUMBER must be a positive integer with 0 indicating the
332 frame which invoked the debugger.
333
334 The return value is the result of evaulating FORM in the
335 appropriate context."))
336
337
338 ;;;; Queries
339
340 #+(or)
341 ;;; This is probably a better interface than find-function-locations.
342 (defgeneric find-definitions (name)
343 (:documentation
344 "Return a list of (LABEL . LOCATION) pairs for NAME's definitions.
345
346 NAME is string denoting a symbol or \"definition specifier\".
347
348 LABEL is a string describing the definition, e.g., \"foo\" or
349 \"(method foo (string number))\" or \"(variable bar)\".
350
351 LOCATION is a source location of the form:
352
353 <location> ::= (:location <buffer> <position>)
354 | (:error <message>)
355
356 <buffer> ::= (:file <filename>)
357 | (:buffer <buffername>)
358 | (:source-form <string>)
359
360 <position> ::= (:position <fixnum> [<align>]) ; 1 based
361 | (:function-name <string>)
362 "))
363
364 (defgeneric find-function-locations (name)
365 (:documentation
366 "Return a list (LOCATION LOCATION ...) for NAME's definitions.
367
368 LOCATION is a source location of the form:
369
370 <location> ::= (:location <buffer> <position>)
371 | (:error <message>)
372
373 <buffer> ::= (:file <filename>)
374 | (:buffer <buffername>)
375 | (:source-form <string>)
376
377 <position> ::= (:position <fixnum> [<align>]) ; 1 based
378 | (:line <fixnum> [<fixnum>])
379 | (:function-name <string>)
380 | (:source-path <list> <start-position>)
381 "))
382
383
384 ;;;; Multiprocessing
385
386 (defgeneric startup-multiprocessing ()
387 (:documentation
388 "Initialize multiprocessing, if necessary.
389
390 This function is called directly through the listener, not in an RPC
391 from Emacs. This is to support interfaces such as CMUCL's
392 MP::STARTUP-IDLE-AND-TOP-LEVEL-LOOPS which does not return like a
393 normal function."))
394
395 (defgeneric spawn (fn &key name)
396 (:documentation "Create a new thread to call FN."))
397
398 (defgeneric thread-id ()
399 (:documentation
400 "Return a value that uniquely identifies the current thread.
401 Thread-IDs allow Emacs to refer to individual threads.
402
403 When called several times by the same thread, all return values are
404 EQUAL. The value has a READable printed representation that preserves
405 equality. The printed representation must be identical in Emacs Lisp
406 and Common Lisp, and short enough to include in the REPL prompt.
407
408 For example, a THREAD-ID could be an integer or a short ASCII string.
409
410 Systems that do not support multiprocessing return NIL."))
411
412 (defgeneric thread-name (thread-id)
413 (:documentation
414 "Return the name of the thread identified by THREAD-ID.
415
416 Thread names are be single-line strings and are meaningful to the
417 user. They do not have to be unique."))
418
419 (defgeneric make-lock (&key name)
420 (:documentation
421 "Make a lock for thread synchronization.
422 Only one thread may hold the lock (via CALL-WITH-LOCK-HELD) at a time."))
423
424 (defgeneric call-with-lock-held (lock function)
425 (:documentation
426 "Call FUNCTION with LOCK held, queueing if necessary."))
427
428
429 ;;;;; Default implementation for non-MP systems
430
431 ;;; Using NO-APPLICABLE-METHOD to supply a default implementation that
432 ;;; works in systems that don't have multiprocessing.
433 ;;; (Good or bad idea? -luke)
434
435 (defmethod no-applicable-method ((m (eql #'startup-multiprocessing)) &rest _)
436 (declare (ignore _))
437 nil)
438 (defmethod no-applicable-method ((m (eql #'thread-id)) &rest _)
439 (declare (ignore _))
440 nil)
441 (defmethod no-applicable-method ((m (eql #'thread-name)) &rest _)
442 (declare (ignore _))
443 "The One True Thread")
444 (defmethod no-applicable-method ((m (eql #'make-lock)) &rest _)
445 (declare (ignore _))
446 :null-lock)
447 (defmethod no-applicable-method ((m (eql #'call-with-lock-held)) &rest args)
448 (funcall (second args)))
449

  ViewVC Help
Powered by ViewVC 1.1.5