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

Contents of /slime/swank-backend.lisp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.5