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

Contents of /slime/swank-backend.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (hide annotations)
Mon Jan 12 00:51:32 2004 UTC (10 years, 3 months ago) by lgorrie
Branch: MAIN
Changes since 1.12: +86 -40 lines
(create-socket-server): Generic callback-driven TCP server
interface. Replaces `create-swank-server', with the higher-level logic
moved into swank.lisp.

(emacs-connected): Invoked when Emacs initially connects, as a hook
for backend implementations.

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

  ViewVC Help
Powered by ViewVC 1.1.5