Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/slime/contrib/swank-arglists.lisp
990 views
1
;;; swank-arglists.lisp --- arglist related code ??
2
;;
3
;; Authors: Matthias Koeppe <[email protected]>
4
;; Tobias C. Rittweiler <[email protected]>
5
;; and others
6
;;
7
;; License: Public Domain
8
;;
9
10
(in-package :swank)
11
12
(eval-when (:compile-toplevel :load-toplevel :execute)
13
(swank-require :swank-c-p-c))
14
15
;;;; Utilities
16
17
(defun compose (&rest functions)
18
"Compose FUNCTIONS right-associatively, returning a function"
19
#'(lambda (x)
20
(reduce #'funcall functions :initial-value x :from-end t)))
21
22
(defun length= (seq n)
23
"Test for whether SEQ contains N number of elements. I.e. it's equivalent
24
to (= (LENGTH SEQ) N), but besides being more concise, it may also be more
25
efficiently implemented."
26
(etypecase seq
27
(list (do ((i n (1- i))
28
(list seq (cdr list)))
29
((or (<= i 0) (null list))
30
(and (zerop i) (null list)))))
31
(sequence (= (length seq) n))))
32
33
(declaim (inline memq))
34
(defun memq (item list)
35
(member item list :test #'eq))
36
37
(defun exactly-one-p (&rest values)
38
"If exactly one value in VALUES is non-NIL, this value is returned.
39
Otherwise NIL is returned."
40
(let ((found nil))
41
(dolist (v values)
42
(when v (if found
43
(return-from exactly-one-p nil)
44
(setq found v))))
45
found))
46
47
(defun valid-operator-symbol-p (symbol)
48
"Is SYMBOL the name of a function, a macro, or a special-operator?"
49
(or (fboundp symbol)
50
(macro-function symbol)
51
(special-operator-p symbol)
52
(member symbol '(declare declaim))))
53
54
(defun valid-operator-name-p (string)
55
"Is STRING the name of a function, macro, or special-operator?"
56
(let ((symbol (parse-symbol string)))
57
(valid-operator-symbol-p symbol)))
58
59
(defun valid-function-name-p (form)
60
(and (match form
61
((#'symbolp _) t)
62
(('setf (#'symbolp _)) t)
63
(_ nil))
64
(fboundp form)
65
t))
66
67
(defun interesting-variable-p (symbol)
68
(and symbol
69
(symbolp symbol)
70
(boundp symbol)
71
(not (memq symbol '(cl:t cl:nil)))
72
(not (keywordp symbol))))
73
74
(defmacro multiple-value-or (&rest forms)
75
(if (null forms)
76
nil
77
(let ((first (first forms))
78
(rest (rest forms)))
79
`(let* ((values (multiple-value-list ,first))
80
(primary-value (first values)))
81
(if primary-value
82
(values-list values)
83
(multiple-value-or ,@rest))))))
84
85
(defun arglist-available-p (arglist)
86
(not (eql arglist :not-available)))
87
88
(defmacro with-available-arglist ((var &rest more-vars) form &body body)
89
`(multiple-value-bind (,var ,@more-vars) ,form
90
(if (eql ,var :not-available)
91
:not-available
92
(progn ,@body))))
93
94
95
;;;; Arglist Definition
96
97
(defstruct (arglist (:conc-name arglist.) (:predicate arglist-p))
98
provided-args ; list of the provided actual arguments
99
required-args ; list of the required arguments
100
optional-args ; list of the optional arguments
101
key-p ; whether &key appeared
102
keyword-args ; list of the keywords
103
rest ; name of the &rest or &body argument (if any)
104
body-p ; whether the rest argument is a &body
105
allow-other-keys-p ; whether &allow-other-keys appeared
106
aux-args ; list of &aux variables
107
any-p ; whether &any appeared
108
any-args ; list of &any arguments [*]
109
known-junk ; &whole, &environment
110
unknown-junk) ; unparsed stuff
111
112
;;;
113
;;; [*] The &ANY lambda keyword is an extension to ANSI Common Lisp,
114
;;; and is only used to describe certain arglists that cannot be
115
;;; described in another way.
116
;;;
117
;;; &ANY is very similiar to &KEY but while &KEY is based upon
118
;;; the idea of a plist (key1 value1 key2 value2), &ANY is a
119
;;; cross between &OPTIONAL, &KEY and *FEATURES* lists:
120
;;;
121
;;; a) (&ANY :A :B :C) means that you can provide any (non-null)
122
;;; set consisting of the keywords `:A', `:B', or `:C' in
123
;;; the arglist. E.g. (:A) or (:C :B :A).
124
;;;
125
;;; (This is not restricted to keywords only, but any self-evaluating
126
;;; expression is allowed.)
127
;;;
128
;;; b) (&ANY (key1 v1) (key2 v2) (key3 v3)) means that you can
129
;;; provide any (non-null) set consisting of lists where
130
;;; the CAR of the list is one of `key1', `key2', or `key3'.
131
;;; E.g. ((key1 100) (key3 42)), or ((key3 66) (key2 23))
132
;;;
133
;;;
134
;;; For example, a) let us describe the situations of EVAL-WHEN as
135
;;;
136
;;; (EVAL-WHEN (&ANY :compile-toplevel :load-toplevel :execute) &BODY body)
137
;;;
138
;;; and b) let us describe the optimization qualifiers that are valid
139
;;; in the declaration specifier `OPTIMIZE':
140
;;;
141
;;; (DECLARE (OPTIMIZE &ANY (compilation-speed 1) (safety 1) ...))
142
;;;
143
144
;; This is a wrapper object around anything that came from Slime and
145
;; could not reliably be read.
146
(defstruct (arglist-dummy
147
(:conc-name #:arglist-dummy.)
148
(:constructor make-arglist-dummy (string-representation)))
149
string-representation)
150
151
(defun empty-arg-p (dummy)
152
(and (arglist-dummy-p dummy)
153
(zerop (length (arglist-dummy.string-representation dummy)))))
154
155
(eval-when (:compile-toplevel :load-toplevel :execute)
156
(defparameter +lambda-list-keywords+
157
'(&provided &required &optional &rest &key &any)))
158
159
(defmacro do-decoded-arglist (decoded-arglist &body clauses)
160
(assert (loop for clause in clauses
161
thereis (member (car clause) +lambda-list-keywords+)))
162
(flet ((parse-clauses (clauses)
163
(let* ((size (length +lambda-list-keywords+))
164
(initial (make-hash-table :test #'eq :size size))
165
(main (make-hash-table :test #'eq :size size))
166
(final (make-hash-table :test #'eq :size size)))
167
(loop for clause in clauses
168
for lambda-list-keyword = (first clause)
169
for clause-parameter = (second clause)
170
doing (cond ((eq clause-parameter :initially)
171
(setf (gethash lambda-list-keyword initial) clause))
172
((eq clause-parameter :finally)
173
(setf (gethash lambda-list-keyword final) clause))
174
(t
175
(setf (gethash lambda-list-keyword main) clause)))
176
finally
177
(return (values initial main final)))))
178
(generate-main-clause (clause arglist)
179
(destructure-case clause
180
((&provided (&optional arg) . body)
181
(let ((gensym (gensym "PROVIDED-ARG+")))
182
`(dolist (,gensym (arglist.provided-args ,arglist))
183
(declare (ignorable ,gensym))
184
(let (,@(when arg `((,arg ,gensym))))
185
,@body))))
186
((&required (&optional arg) . body)
187
(let ((gensym (gensym "REQUIRED-ARG+")))
188
`(dolist (,gensym (arglist.required-args ,arglist))
189
(declare (ignorable ,gensym))
190
(let (,@(when arg `((,arg ,gensym))))
191
,@body))))
192
((&optional (&optional arg init) . body)
193
(let ((optarg (gensym "OPTIONAL-ARG+")))
194
`(dolist (,optarg (arglist.optional-args ,arglist))
195
(declare (ignorable ,optarg))
196
(let (,@(when arg `((,arg (optional-arg.arg-name ,optarg))))
197
,@(when init `((,init (optional-arg.default-arg ,optarg)))))
198
,@body))))
199
((&key (&optional keyword arg init) . body)
200
(let ((keyarg (gensym "KEY-ARG+")))
201
`(dolist (,keyarg (arglist.keyword-args ,arglist))
202
(declare (ignorable ,keyarg))
203
(let (,@(when keyword `((,keyword (keyword-arg.keyword ,keyarg))))
204
,@(when arg `((,arg (keyword-arg.arg-name ,keyarg))))
205
,@(when init `((,init (keyword-arg.default-arg ,keyarg)))))
206
,@body))))
207
((&rest (&optional arg body-p) . body)
208
`(when (arglist.rest ,arglist)
209
(let (,@(when arg `((,arg (arglist.rest ,arglist))))
210
,@(when body-p `((,body-p (arglist.body-p ,arglist)))))
211
,@body)))
212
((&any (&optional arg) . body)
213
(let ((gensym (gensym "REQUIRED-ARG+")))
214
`(dolist (,gensym (arglist.any-args ,arglist))
215
(declare (ignorable ,gensym))
216
(let (,@(when arg `((,arg ,gensym))))
217
,@body)))))))
218
(let ((arglist (gensym "DECODED-ARGLIST+")))
219
(multiple-value-bind (initially-clauses main-clauses finally-clauses)
220
(parse-clauses clauses)
221
`(let ((,arglist ,decoded-arglist))
222
(block do-decoded-arglist
223
,@(loop for keyword in '(&provided &required &optional &rest &key &any)
224
append (cddr (gethash keyword initially-clauses))
225
collect (let ((clause (gethash keyword main-clauses)))
226
(when clause (generate-main-clause clause arglist)))
227
append (cddr (gethash keyword finally-clauses)))))))))
228
229
;;;; Arglist Printing
230
231
(defun print-decoded-arglist (arglist &key operator provided-args highlight)
232
(macrolet ((space ()
233
;; Kludge: When OPERATOR is not given, we don't want to
234
;; print a space for the first argument.
235
`(if (not operator)
236
(setq operator t)
237
(progn (write-char #\space)
238
(pprint-newline :fill))))
239
(with-highlighting ((&key index) &body body)
240
`(if (eql ,index (car highlight))
241
(progn (princ "===> ") ,@body (princ " <==="))
242
(progn ,@body)))
243
(print-arglist-recursively (argl &key index)
244
`(if (eql ,index (car highlight))
245
(print-decoded-arglist ,argl :highlight (cdr highlight))
246
(print-decoded-arglist ,argl))))
247
(let ((index 0))
248
(pprint-logical-block (nil nil :prefix "(" :suffix ")")
249
(when operator
250
(print-arg operator)
251
(pprint-indent :current 1)) ; 1 due to possibly added space
252
(do-decoded-arglist (remove-given-args arglist provided-args)
253
(&provided (arg)
254
(space)
255
(print-arg arg)
256
(incf index))
257
(&required (arg)
258
(space)
259
(if (arglist-p arg)
260
(print-arglist-recursively arg :index index)
261
(with-highlighting (:index index)
262
(print-arg arg)))
263
(incf index))
264
(&optional :initially
265
(when (arglist.optional-args arglist)
266
(space)
267
(princ '&optional)))
268
(&optional (arg init-value)
269
(space)
270
(if (arglist-p arg)
271
(print-arglist-recursively arg :index index)
272
(with-highlighting (:index index)
273
(if (null init-value)
274
(print-arg arg)
275
(format t "~:@<~A ~S~@:>" arg init-value))))
276
(incf index))
277
(&key :initially
278
(when (arglist.key-p arglist)
279
(space)
280
(princ '&key)))
281
(&key (keyword arg init)
282
(space)
283
(if (arglist-p arg)
284
(pprint-logical-block (nil nil :prefix "(" :suffix ")")
285
(prin1 keyword) (space)
286
(print-arglist-recursively arg :index keyword))
287
(with-highlighting (:index keyword)
288
(cond ((and init (keywordp keyword))
289
(format t "~:@<~A ~S~@:>" keyword init))
290
(init
291
(format t "~:@<(~S ..) ~S~@:>" keyword init))
292
((not (keywordp keyword))
293
(format t "~:@<(~S ..)~@:>" keyword))
294
(t
295
(princ keyword))))))
296
(&key :finally
297
(when (arglist.allow-other-keys-p arglist)
298
(space)
299
(princ '&allow-other-keys)))
300
(&any :initially
301
(when (arglist.any-p arglist)
302
(space)
303
(princ '&any)))
304
(&any (arg)
305
(space)
306
(print-arg arg))
307
(&rest (args bodyp)
308
(space)
309
(princ (if bodyp '&body '&rest))
310
(space)
311
(if (arglist-p args)
312
(print-arglist-recursively args :index index)
313
(with-highlighting (:index index)
314
(print-arg args))))
315
;; FIXME: add &UNKNOWN-JUNK?
316
)))))
317
318
(defun print-arg (arg)
319
(let ((arg (if (arglist-dummy-p arg)
320
(arglist-dummy.string-representation arg)
321
arg)))
322
(if (keywordp arg)
323
(prin1 arg)
324
(princ arg))))
325
326
(defun print-decoded-arglist-as-template (decoded-arglist &key
327
(prefix "(") (suffix ")"))
328
(let ((first-p t))
329
(flet ((space ()
330
(unless first-p
331
(write-char #\space))
332
(setq first-p nil))
333
(print-arg-or-pattern (arg)
334
(etypecase arg
335
(symbol (if (keywordp arg) (prin1 arg) (princ arg)))
336
(string (princ arg))
337
(list (princ arg))
338
(arglist-dummy (princ (arglist-dummy.string-representation arg)))
339
(arglist (print-decoded-arglist-as-template arg)))
340
(pprint-newline :fill)))
341
(pprint-logical-block (nil nil :prefix prefix :suffix suffix)
342
(do-decoded-arglist decoded-arglist
343
(&provided ()) ; do nothing; provided args are in the buffer already.
344
(&required (arg)
345
(space) (print-arg-or-pattern arg))
346
(&optional (arg)
347
(space) (princ "[") (print-arg-or-pattern arg) (princ "]"))
348
(&key (keyword arg)
349
(space)
350
(prin1 (if (keywordp keyword) keyword `',keyword))
351
(space)
352
(print-arg-or-pattern arg)
353
(pprint-newline :linear))
354
(&any (arg)
355
(space) (print-arg-or-pattern arg))
356
(&rest (args)
357
(when (or (not (arglist.keyword-args decoded-arglist))
358
(arglist.allow-other-keys-p decoded-arglist))
359
(space)
360
(format t "~A..." args))))))))
361
362
(defvar *arglist-pprint-bindings*
363
'((*print-case* . :downcase)
364
(*print-pretty* . t)
365
(*print-circle* . nil)
366
(*print-readably* . nil)
367
(*print-level* . 10)
368
(*print-length* . 20)
369
(*print-escape* . nil)))
370
371
(defvar *arglist-show-packages* t)
372
373
(defmacro with-arglist-io-syntax (&body body)
374
(let ((package (gensym)))
375
`(let ((,package *package*))
376
(with-standard-io-syntax
377
(let ((*package* (if *arglist-show-packages*
378
*package*
379
,package)))
380
(with-bindings *arglist-pprint-bindings*
381
,@body))))))
382
383
(defun decoded-arglist-to-string (decoded-arglist
384
&key operator highlight
385
print-right-margin)
386
(with-output-to-string (*standard-output*)
387
(with-arglist-io-syntax
388
(let ((*print-right-margin* print-right-margin))
389
(print-decoded-arglist decoded-arglist
390
:operator operator
391
:highlight highlight)))))
392
393
(defun decoded-arglist-to-template-string (decoded-arglist
394
&key (prefix "(") (suffix ")"))
395
(with-output-to-string (*standard-output*)
396
(with-arglist-io-syntax
397
(print-decoded-arglist-as-template decoded-arglist
398
:prefix prefix
399
:suffix suffix))))
400
401
;;;; Arglist Decoding / Encoding
402
403
(defun decode-required-arg (arg)
404
"ARG can be a symbol or a destructuring pattern."
405
(etypecase arg
406
(symbol arg)
407
(arglist-dummy arg)
408
(list (decode-arglist arg))))
409
410
(defun encode-required-arg (arg)
411
(etypecase arg
412
(symbol arg)
413
(arglist (encode-arglist arg))))
414
415
(defstruct (keyword-arg
416
(:conc-name keyword-arg.)
417
(:constructor make-keyword-arg (keyword arg-name default-arg)))
418
keyword
419
arg-name
420
default-arg)
421
422
(defun decode-keyword-arg (arg)
423
"Decode a keyword item of formal argument list.
424
Return three values: keyword, argument name, default arg."
425
(flet ((intern-as-keyword (arg)
426
(intern (etypecase arg
427
(symbol (symbol-name arg))
428
(arglist-dummy (arglist-dummy.string-representation arg)))
429
keyword-package)))
430
(cond ((or (symbolp arg) (arglist-dummy-p arg))
431
(make-keyword-arg (intern-as-keyword arg) arg nil))
432
((and (consp arg)
433
(consp (car arg)))
434
(make-keyword-arg (caar arg)
435
(decode-required-arg (cadar arg))
436
(cadr arg)))
437
((consp arg)
438
(make-keyword-arg (intern-as-keyword (car arg)) (car arg) (cadr arg)))
439
(t
440
(error "Bad keyword item of formal argument list")))))
441
442
(defun encode-keyword-arg (arg)
443
(cond
444
((arglist-p (keyword-arg.arg-name arg))
445
;; Destructuring pattern
446
(let ((keyword/name (list (keyword-arg.keyword arg)
447
(encode-required-arg
448
(keyword-arg.arg-name arg)))))
449
(if (keyword-arg.default-arg arg)
450
(list keyword/name
451
(keyword-arg.default-arg arg))
452
(list keyword/name))))
453
((eql (intern (symbol-name (keyword-arg.arg-name arg))
454
keyword-package)
455
(keyword-arg.keyword arg))
456
(if (keyword-arg.default-arg arg)
457
(list (keyword-arg.arg-name arg)
458
(keyword-arg.default-arg arg))
459
(keyword-arg.arg-name arg)))
460
(t
461
(let ((keyword/name (list (keyword-arg.keyword arg)
462
(keyword-arg.arg-name arg))))
463
(if (keyword-arg.default-arg arg)
464
(list keyword/name
465
(keyword-arg.default-arg arg))
466
(list keyword/name))))))
467
468
(progn
469
(assert (equalp (decode-keyword-arg 'x)
470
(make-keyword-arg :x 'x nil)))
471
(assert (equalp (decode-keyword-arg '(x t))
472
(make-keyword-arg :x 'x t)))
473
(assert (equalp (decode-keyword-arg '((:x y)))
474
(make-keyword-arg :x 'y nil)))
475
(assert (equalp (decode-keyword-arg '((:x y) t))
476
(make-keyword-arg :x 'y t))))
477
478
;;; FIXME suppliedp?
479
(defstruct (optional-arg
480
(:conc-name optional-arg.)
481
(:constructor make-optional-arg (arg-name default-arg)))
482
arg-name
483
default-arg)
484
485
(defun decode-optional-arg (arg)
486
"Decode an optional item of a formal argument list.
487
Return an OPTIONAL-ARG structure."
488
(etypecase arg
489
(symbol (make-optional-arg arg nil))
490
(arglist-dummy (make-optional-arg arg nil))
491
(list (make-optional-arg (decode-required-arg (car arg))
492
(cadr arg)))))
493
494
(defun encode-optional-arg (optional-arg)
495
(if (or (optional-arg.default-arg optional-arg)
496
(arglist-p (optional-arg.arg-name optional-arg)))
497
(list (encode-required-arg
498
(optional-arg.arg-name optional-arg))
499
(optional-arg.default-arg optional-arg))
500
(optional-arg.arg-name optional-arg)))
501
502
(progn
503
(assert (equalp (decode-optional-arg 'x)
504
(make-optional-arg 'x nil)))
505
(assert (equalp (decode-optional-arg '(x t))
506
(make-optional-arg 'x t))))
507
508
(define-modify-macro nreversef () nreverse "Reverse the list in PLACE.")
509
510
(defun decode-arglist (arglist)
511
"Parse the list ARGLIST and return an ARGLIST structure."
512
(etypecase arglist
513
((eql :not-available) (return-from decode-arglist
514
:not-available))
515
(list))
516
(loop
517
with mode = nil
518
with result = (make-arglist)
519
for arg = (if (consp arglist)
520
(pop arglist)
521
(progn
522
(prog1 arglist
523
(setf mode '&rest
524
arglist nil))))
525
do (cond
526
((eql mode '&unknown-junk)
527
;; don't leave this mode -- we don't know how the arglist
528
;; after unknown lambda-list keywords is interpreted
529
(push arg (arglist.unknown-junk result)))
530
((eql arg '&allow-other-keys)
531
(setf (arglist.allow-other-keys-p result) t))
532
((eql arg '&key)
533
(setf (arglist.key-p result) t
534
mode arg))
535
((memq arg '(&optional &rest &body &aux))
536
(setq mode arg))
537
((memq arg '(&whole &environment))
538
(setq mode arg)
539
(push arg (arglist.known-junk result)))
540
((and (symbolp arg)
541
(string= (symbol-name arg) (string '#:&any))) ; may be interned
542
(setf (arglist.any-p result) t) ; in any *package*.
543
(setq mode '&any))
544
((memq arg lambda-list-keywords)
545
(setq mode '&unknown-junk)
546
(push arg (arglist.unknown-junk result)))
547
(t
548
(ecase mode
549
(&key
550
(push (decode-keyword-arg arg)
551
(arglist.keyword-args result)))
552
(&optional
553
(push (decode-optional-arg arg)
554
(arglist.optional-args result)))
555
(&body
556
(setf (arglist.body-p result) t
557
(arglist.rest result) arg))
558
(&rest
559
(setf (arglist.rest result) arg))
560
(&aux
561
(push (decode-optional-arg arg)
562
(arglist.aux-args result)))
563
((nil)
564
(push (decode-required-arg arg)
565
(arglist.required-args result)))
566
((&whole &environment)
567
(setf mode nil)
568
(push arg (arglist.known-junk result)))
569
(&any
570
(push arg (arglist.any-args result))))))
571
until (null arglist)
572
finally (nreversef (arglist.required-args result))
573
finally (nreversef (arglist.optional-args result))
574
finally (nreversef (arglist.keyword-args result))
575
finally (nreversef (arglist.aux-args result))
576
finally (nreversef (arglist.any-args result))
577
finally (nreversef (arglist.known-junk result))
578
finally (nreversef (arglist.unknown-junk result))
579
finally (assert (or (and (not (arglist.key-p result))
580
(not (arglist.any-p result)))
581
(exactly-one-p (arglist.key-p result)
582
(arglist.any-p result))))
583
finally (return result)))
584
585
(defun encode-arglist (decoded-arglist)
586
(append (mapcar #'encode-required-arg (arglist.required-args decoded-arglist))
587
(when (arglist.optional-args decoded-arglist)
588
'(&optional))
589
(mapcar #'encode-optional-arg (arglist.optional-args decoded-arglist))
590
(when (arglist.key-p decoded-arglist)
591
'(&key))
592
(mapcar #'encode-keyword-arg (arglist.keyword-args decoded-arglist))
593
(when (arglist.allow-other-keys-p decoded-arglist)
594
'(&allow-other-keys))
595
(when (arglist.any-args decoded-arglist)
596
`(&any ,@(arglist.any-args decoded-arglist)))
597
(cond ((not (arglist.rest decoded-arglist))
598
'())
599
((arglist.body-p decoded-arglist)
600
`(&body ,(arglist.rest decoded-arglist)))
601
(t
602
`(&rest ,(arglist.rest decoded-arglist))))
603
(when (arglist.aux-args decoded-arglist)
604
`(&aux ,(arglist.aux-args decoded-arglist)))
605
(arglist.known-junk decoded-arglist)
606
(arglist.unknown-junk decoded-arglist)))
607
608
;;;; Arglist Enrichment
609
610
(defun arglist-keywords (lambda-list)
611
"Return the list of keywords in ARGLIST.
612
As a secondary value, return whether &allow-other-keys appears."
613
(let ((decoded-arglist (decode-arglist lambda-list)))
614
(values (arglist.keyword-args decoded-arglist)
615
(arglist.allow-other-keys-p decoded-arglist))))
616
617
618
(defun methods-keywords (methods)
619
"Collect all keywords in the arglists of METHODS.
620
As a secondary value, return whether &allow-other-keys appears somewhere."
621
(let ((keywords '())
622
(allow-other-keys nil))
623
(dolist (method methods)
624
(multiple-value-bind (kw aok)
625
(arglist-keywords
626
(swank-mop:method-lambda-list method))
627
(setq keywords (remove-duplicates (append keywords kw)
628
:key #'keyword-arg.keyword)
629
allow-other-keys (or allow-other-keys aok))))
630
(values keywords allow-other-keys)))
631
632
(defun generic-function-keywords (generic-function)
633
"Collect all keywords in the methods of GENERIC-FUNCTION.
634
As a secondary value, return whether &allow-other-keys appears somewhere."
635
(methods-keywords
636
(swank-mop:generic-function-methods generic-function)))
637
638
(defun applicable-methods-keywords (generic-function arguments)
639
"Collect all keywords in the methods of GENERIC-FUNCTION that are
640
applicable for argument of CLASSES. As a secondary value, return
641
whether &allow-other-keys appears somewhere."
642
(methods-keywords
643
(multiple-value-bind (amuc okp)
644
(swank-mop:compute-applicable-methods-using-classes
645
generic-function (mapcar #'class-of arguments))
646
(if okp
647
amuc
648
(compute-applicable-methods generic-function arguments)))))
649
650
(defgeneric extra-keywords (operator &rest args)
651
(:documentation "Return a list of extra keywords of OPERATOR (a
652
symbol) when applied to the (unevaluated) ARGS.
653
As a secondary value, return whether other keys are allowed.
654
As a tertiary value, return the initial sublist of ARGS that was needed
655
to determine the extra keywords."))
656
657
;;; We make sure that symbol-from-KEYWORD-using keywords come before
658
;;; symbol-from-arbitrary-package-using keywords. And we sort the
659
;;; latter according to how their home-packages relate to *PACKAGE*.
660
;;;
661
;;; Rationale is to show those key parameters first which make most
662
;;; sense in the current context. And in particular: to put
663
;;; implementation-internal stuff last.
664
;;;
665
;;; This matters tremendeously on Allegro in combination with
666
;;; AllegroCache as that does some evil tinkering with initargs,
667
;;; obfuscating the arglist of MAKE-INSTANCE.
668
;;;
669
670
(defmethod extra-keywords :around (op &rest args)
671
(declare (ignorable op args))
672
(multiple-value-bind (keywords aok enrichments) (call-next-method)
673
(values (sort-extra-keywords keywords) aok enrichments)))
674
675
(defun make-package-comparator (reference-packages)
676
"Returns a two-argument test function which compares packages
677
according to their used-by relation with REFERENCE-PACKAGES. Packages
678
will be sorted first which appear first in the PACKAGE-USE-LIST of the
679
reference packages."
680
(let ((package-use-table (make-hash-table :test 'eq)))
681
;; Walk the package dependency graph breadth-fist, and fill
682
;; PACKAGE-USE-TABLE accordingly.
683
(loop with queue = (copy-list reference-packages)
684
with bfn = 0 ; Breadth-First Number
685
for p = (pop queue)
686
unless (gethash p package-use-table)
687
do (setf (gethash p package-use-table) (shiftf bfn (1+ bfn)))
688
and do (setf queue (nconc queue (copy-list (package-use-list p))))
689
while queue)
690
#'(lambda (p1 p2)
691
(let ((bfn1 (gethash p1 package-use-table))
692
(bfn2 (gethash p2 package-use-table)))
693
(cond ((and bfn1 bfn2) (<= bfn1 bfn2))
694
(bfn1 bfn1)
695
(bfn2 nil) ; p2 is used, p1 not
696
(t (string<= (package-name p1) (package-name p2))))))))
697
698
(defun sort-extra-keywords (kwds)
699
(stable-sort kwds (make-package-comparator (list keyword-package *package*))
700
:key (compose #'symbol-package #'keyword-arg.keyword)))
701
702
(defun keywords-of-operator (operator)
703
"Return a list of KEYWORD-ARGs that OPERATOR accepts.
704
This function is useful for writing EXTRA-KEYWORDS methods for
705
user-defined functions which are declared &ALLOW-OTHER-KEYS and which
706
forward keywords to OPERATOR."
707
(with-available-arglist (arglist) (arglist-from-form (ensure-list operator))
708
(values (arglist.keyword-args arglist)
709
(arglist.allow-other-keys-p arglist))))
710
711
(defmethod extra-keywords (operator &rest args)
712
;; default method
713
(declare (ignore args))
714
(let ((symbol-function (symbol-function operator)))
715
(if (typep symbol-function 'generic-function)
716
(generic-function-keywords symbol-function)
717
nil)))
718
719
(defun class-from-class-name-form (class-name-form)
720
(when (and (listp class-name-form)
721
(= (length class-name-form) 2)
722
(eq (car class-name-form) 'quote))
723
(let* ((class-name (cadr class-name-form))
724
(class (find-class class-name nil)))
725
(when (and class
726
(not (swank-mop:class-finalized-p class)))
727
;; Try to finalize the class, which can fail if
728
;; superclasses are not defined yet
729
(handler-case (swank-mop:finalize-inheritance class)
730
(program-error (c)
731
(declare (ignore c)))))
732
class)))
733
734
(defun extra-keywords/slots (class)
735
(multiple-value-bind (slots allow-other-keys-p)
736
(if (swank-mop:class-finalized-p class)
737
(values (swank-mop:class-slots class) nil)
738
(values (swank-mop:class-direct-slots class) t))
739
(let ((slot-init-keywords
740
(loop for slot in slots append
741
(mapcar (lambda (initarg)
742
(make-keyword-arg
743
initarg
744
(swank-mop:slot-definition-name slot)
745
(swank-mop:slot-definition-initform slot)))
746
(swank-mop:slot-definition-initargs slot)))))
747
(values slot-init-keywords allow-other-keys-p))))
748
749
(defun extra-keywords/make-instance (operator &rest args)
750
(declare (ignore operator))
751
(unless (null args)
752
(let* ((class-name-form (car args))
753
(class (class-from-class-name-form class-name-form)))
754
(when class
755
(multiple-value-bind (slot-init-keywords class-aokp)
756
(extra-keywords/slots class)
757
(multiple-value-bind (allocate-instance-keywords ai-aokp)
758
(applicable-methods-keywords
759
#'allocate-instance (list class))
760
(multiple-value-bind (initialize-instance-keywords ii-aokp)
761
(ignore-errors
762
(applicable-methods-keywords
763
#'initialize-instance (list (swank-mop:class-prototype class))))
764
(multiple-value-bind (shared-initialize-keywords si-aokp)
765
(ignore-errors
766
(applicable-methods-keywords
767
#'shared-initialize (list (swank-mop:class-prototype class) t)))
768
(values (append slot-init-keywords
769
allocate-instance-keywords
770
initialize-instance-keywords
771
shared-initialize-keywords)
772
(or class-aokp ai-aokp ii-aokp si-aokp)
773
(list class-name-form))))))))))
774
775
(defun extra-keywords/change-class (operator &rest args)
776
(declare (ignore operator))
777
(unless (null args)
778
(let* ((class-name-form (car args))
779
(class (class-from-class-name-form class-name-form)))
780
(when class
781
(multiple-value-bind (slot-init-keywords class-aokp)
782
(extra-keywords/slots class)
783
(declare (ignore class-aokp))
784
(multiple-value-bind (shared-initialize-keywords si-aokp)
785
(ignore-errors
786
(applicable-methods-keywords
787
#'shared-initialize (list (swank-mop:class-prototype class) t)))
788
;; FIXME: much as it would be nice to include the
789
;; applicable keywords from
790
;; UPDATE-INSTANCE-FOR-DIFFERENT-CLASS, I don't really see
791
;; how to do it: so we punt, always declaring
792
;; &ALLOW-OTHER-KEYS.
793
(declare (ignore si-aokp))
794
(values (append slot-init-keywords shared-initialize-keywords)
795
t
796
(list class-name-form))))))))
797
798
(defmethod extra-keywords ((operator (eql 'make-instance))
799
&rest args)
800
(multiple-value-or (apply #'extra-keywords/make-instance operator args)
801
(call-next-method)))
802
803
(defmethod extra-keywords ((operator (eql 'make-condition))
804
&rest args)
805
(multiple-value-or (apply #'extra-keywords/make-instance operator args)
806
(call-next-method)))
807
808
(defmethod extra-keywords ((operator (eql 'error))
809
&rest args)
810
(multiple-value-or (apply #'extra-keywords/make-instance operator args)
811
(call-next-method)))
812
813
(defmethod extra-keywords ((operator (eql 'signal))
814
&rest args)
815
(multiple-value-or (apply #'extra-keywords/make-instance operator args)
816
(call-next-method)))
817
818
(defmethod extra-keywords ((operator (eql 'warn))
819
&rest args)
820
(multiple-value-or (apply #'extra-keywords/make-instance operator args)
821
(call-next-method)))
822
823
(defmethod extra-keywords ((operator (eql 'cerror))
824
&rest args)
825
(multiple-value-bind (keywords aok determiners)
826
(apply #'extra-keywords/make-instance operator
827
(cdr args))
828
(if keywords
829
(values keywords aok
830
(cons (car args) determiners))
831
(call-next-method))))
832
833
(defmethod extra-keywords ((operator (eql 'change-class))
834
&rest args)
835
(multiple-value-bind (keywords aok determiners)
836
(apply #'extra-keywords/change-class operator (cdr args))
837
(if keywords
838
(values keywords aok
839
(cons (car args) determiners))
840
(call-next-method))))
841
842
(defun enrich-decoded-arglist-with-keywords (decoded-arglist keywords allow-other-keys-p)
843
"Modify DECODED-ARGLIST using KEYWORDS and ALLOW-OTHER-KEYS-P."
844
(when keywords
845
(setf (arglist.key-p decoded-arglist) t)
846
(setf (arglist.keyword-args decoded-arglist)
847
(remove-duplicates
848
(append (arglist.keyword-args decoded-arglist)
849
keywords)
850
:key #'keyword-arg.keyword)))
851
(setf (arglist.allow-other-keys-p decoded-arglist)
852
(or (arglist.allow-other-keys-p decoded-arglist)
853
allow-other-keys-p)))
854
855
(defun enrich-decoded-arglist-with-extra-keywords (decoded-arglist form)
856
"Determine extra keywords from the function call FORM, and modify
857
DECODED-ARGLIST to include them. As a secondary return value, return
858
the initial sublist of ARGS that was needed to determine the extra
859
keywords. As a tertiary return value, return whether any enrichment
860
was done."
861
(multiple-value-bind (extra-keywords extra-aok determining-args)
862
(apply #'extra-keywords form)
863
;; enrich the list of keywords with the extra keywords
864
(enrich-decoded-arglist-with-keywords decoded-arglist
865
extra-keywords extra-aok)
866
(values decoded-arglist
867
determining-args
868
(or extra-keywords extra-aok))))
869
870
(defgeneric compute-enriched-decoded-arglist (operator-form argument-forms)
871
(:documentation
872
"Return three values: DECODED-ARGLIST, DETERMINING-ARGS, and
873
ANY-ENRICHMENT, just like enrich-decoded-arglist-with-extra-keywords.
874
If the arglist is not available, return :NOT-AVAILABLE."))
875
876
(defmethod compute-enriched-decoded-arglist (operator-form argument-forms)
877
(with-available-arglist (decoded-arglist)
878
(decode-arglist (arglist operator-form))
879
(enrich-decoded-arglist-with-extra-keywords decoded-arglist
880
(cons operator-form
881
argument-forms))))
882
883
(defmethod compute-enriched-decoded-arglist ((operator-form (eql 'with-open-file))
884
argument-forms)
885
(declare (ignore argument-forms))
886
(multiple-value-bind (decoded-arglist determining-args)
887
(call-next-method)
888
(let ((first-arg (first (arglist.required-args decoded-arglist)))
889
(open-arglist (compute-enriched-decoded-arglist 'open nil)))
890
(when (and (arglist-p first-arg) (arglist-p open-arglist))
891
(enrich-decoded-arglist-with-keywords
892
first-arg
893
(arglist.keyword-args open-arglist)
894
nil)))
895
(values decoded-arglist determining-args t)))
896
897
(defmethod compute-enriched-decoded-arglist ((operator-form (eql 'apply))
898
argument-forms)
899
(let ((function-name-form (car argument-forms)))
900
(when (and (listp function-name-form)
901
(length= function-name-form 2)
902
(memq (car function-name-form) '(quote function)))
903
(let ((function-name (cadr function-name-form)))
904
(when (valid-operator-symbol-p function-name)
905
(let ((function-arglist
906
(compute-enriched-decoded-arglist function-name
907
(cdr argument-forms))))
908
(return-from compute-enriched-decoded-arglist
909
(values (make-arglist :required-args
910
(list 'function)
911
:optional-args
912
(append
913
(mapcar #'(lambda (arg)
914
(make-optional-arg arg nil))
915
(arglist.required-args function-arglist))
916
(arglist.optional-args function-arglist))
917
:key-p
918
(arglist.key-p function-arglist)
919
:keyword-args
920
(arglist.keyword-args function-arglist)
921
:rest
922
'args
923
:allow-other-keys-p
924
(arglist.allow-other-keys-p function-arglist))
925
(list function-name-form)
926
t)))))))
927
(call-next-method))
928
929
(defun delete-given-args (decoded-arglist args)
930
"Delete given ARGS from DECODED-ARGLIST."
931
(macrolet ((pop-or-return (list)
932
`(if (null ,list)
933
(return-from do-decoded-arglist)
934
(pop ,list))))
935
(do-decoded-arglist decoded-arglist
936
(&provided ()
937
(assert (eq (pop-or-return args)
938
(pop (arglist.provided-args decoded-arglist)))))
939
(&required ()
940
(pop-or-return args)
941
(pop (arglist.required-args decoded-arglist)))
942
(&optional ()
943
(pop-or-return args)
944
(pop (arglist.optional-args decoded-arglist)))
945
(&key (keyword)
946
;; N.b. we consider a keyword to be given only when the keyword
947
;; _and_ a value has been given for it.
948
(loop for (key value) on args by #'cddr
949
when (and (eq keyword key) value)
950
do (setf (arglist.keyword-args decoded-arglist)
951
(remove keyword (arglist.keyword-args decoded-arglist)
952
:key #'keyword-arg.keyword))))))
953
decoded-arglist)
954
955
(defun remove-given-args (decoded-arglist args)
956
;; FIXME: We actually needa deep copy here.
957
(delete-given-args (copy-arglist decoded-arglist) args))
958
959
;;;; Arglist Retrieval
960
961
(defun arglist-from-form (form)
962
(if (null form)
963
:not-available
964
(arglist-dispatch (car form) (cdr form))))
965
966
(defgeneric arglist-dispatch (operator arguments)
967
;; Default method
968
(:method (operator arguments)
969
(unless (and (symbolp operator) (valid-operator-symbol-p operator))
970
(return-from arglist-dispatch :not-available))
971
972
(multiple-value-bind (decoded-arglist determining-args)
973
(compute-enriched-decoded-arglist operator arguments)
974
(with-available-arglist (arglist) decoded-arglist
975
;; replace some formal args by determining actual args
976
(setf arglist (delete-given-args arglist determining-args))
977
(setf (arglist.provided-args arglist) determining-args)
978
arglist))))
979
980
(defmethod arglist-dispatch ((operator (eql 'defmethod)) arguments)
981
(match (cons operator arguments)
982
(('defmethod (#'valid-function-name-p gf-name) . rest)
983
(let ((gf (fdefinition gf-name)))
984
(when (typep gf 'generic-function)
985
(with-available-arglist (arglist) (decode-arglist (arglist gf))
986
(let ((qualifiers (loop for x in rest
987
until (or (listp x) (empty-arg-p x))
988
collect x)))
989
(return-from arglist-dispatch
990
(make-arglist :provided-args (cons gf-name qualifiers)
991
:required-args (list arglist)
992
:rest "body" :body-p t)))))))
993
(_)) ; Fall through
994
(call-next-method))
995
996
(defmethod arglist-dispatch ((operator (eql 'define-compiler-macro)) arguments)
997
(match (cons operator arguments)
998
(('define-compiler-macro (#'valid-function-name-p gf-name) . _)
999
(let ((gf (fdefinition gf-name)))
1000
(with-available-arglist (arglist) (decode-arglist (arglist gf))
1001
(return-from arglist-dispatch
1002
(make-arglist :provided-args (list gf-name)
1003
:required-args (list arglist)
1004
:rest "body" :body-p t)))))
1005
(_)) ; Fall through
1006
(call-next-method))
1007
1008
1009
(defmethod arglist-dispatch ((operator (eql 'eval-when)) arguments)
1010
(declare (ignore arguments))
1011
(let ((eval-when-args '(:compile-toplevel :load-toplevel :execute)))
1012
(make-arglist
1013
:required-args (list (make-arglist :any-p t :any-args eval-when-args))
1014
:rest '#:body :body-p t)))
1015
1016
1017
(defmethod arglist-dispatch ((operator (eql 'declare)) arguments)
1018
(let* ((declaration (cons operator (last arguments)))
1019
(typedecl-arglist (arglist-for-type-declaration declaration)))
1020
(if (arglist-available-p typedecl-arglist)
1021
typedecl-arglist
1022
(match declaration
1023
(('declare ((#'consp typespec) . decl-args))
1024
(with-available-arglist (typespec-arglist)
1025
(decoded-arglist-for-type-specifier typespec)
1026
(make-arglist
1027
:required-args (list (make-arglist
1028
:required-args (list typespec-arglist)
1029
:rest '#:variables)))))
1030
(('declare (decl-identifier . decl-args))
1031
(decoded-arglist-for-declaration decl-identifier decl-args))
1032
(_ (make-arglist :rest '#:declaration-specifiers))))))
1033
1034
(defmethod arglist-dispatch ((operator (eql 'declaim)) arguments)
1035
(arglist-dispatch 'declare arguments))
1036
1037
1038
(defun arglist-for-type-declaration (declaration)
1039
(flet ((%arglist-for-type-declaration (identifier typespec rest-var-name)
1040
(with-available-arglist (typespec-arglist)
1041
(decoded-arglist-for-type-specifier typespec)
1042
(make-arglist
1043
:required-args (list (make-arglist
1044
:provided-args (list identifier)
1045
:required-args (list typespec-arglist)
1046
:rest rest-var-name))))))
1047
(match declaration
1048
(('declare ('type (#'consp typespec) . decl-args))
1049
(%arglist-for-type-declaration 'type typespec '#:variables))
1050
(('declare ('ftype (#'consp typespec) . decl-args))
1051
(%arglist-for-type-declaration 'ftype typespec '#:function-names))
1052
(('declare ((#'consp typespec) . decl-args))
1053
(with-available-arglist (typespec-arglist)
1054
(decoded-arglist-for-type-specifier typespec)
1055
(make-arglist
1056
:required-args (list (make-arglist
1057
:required-args (list typespec-arglist)
1058
:rest '#:variables)))))
1059
(_ :not-available))))
1060
1061
(defun decoded-arglist-for-declaration (decl-identifier decl-args)
1062
(declare (ignore decl-args))
1063
(with-available-arglist (arglist)
1064
(decode-arglist (declaration-arglist decl-identifier))
1065
(setf (arglist.provided-args arglist) (list decl-identifier))
1066
(make-arglist :required-args (list arglist))))
1067
1068
(defun decoded-arglist-for-type-specifier (type-specifier)
1069
(etypecase type-specifier
1070
(arglist-dummy :not-available)
1071
(cons (decoded-arglist-for-type-specifier (car type-specifier)))
1072
(symbol
1073
(with-available-arglist (arglist)
1074
(decode-arglist (type-specifier-arglist type-specifier))
1075
(setf (arglist.provided-args arglist) (list type-specifier))
1076
arglist))))
1077
1078
;;; Slimefuns
1079
1080
;;; We work on a RAW-FORM, or BUFFER-FORM, which represent the form at
1081
;;; user's point in Emacs. A RAW-FORM looks like
1082
;;;
1083
;;; ("FOO" ("BAR" ...) "QUUX" ("ZURP" SWANK::%CURSOR-MARKER%))
1084
;;;
1085
;;; The expression before the cursor marker is the expression where
1086
;;; user's cursor points at. An explicit marker is necessary to
1087
;;; disambiguate between
1088
;;;
1089
;;; ("IF" ("PRED")
1090
;;; ("F" "X" "Y" %CURSOR-MARKER%))
1091
;;;
1092
;;; and
1093
;;; ("IF" ("PRED")
1094
;;; ("F" "X" "Y") %CURSOR-MARKER%)
1095
1096
;;; Notice that for a form like (FOO (BAR |) QUUX), where | denotes
1097
;;; user's point, the following should be sent ("FOO" ("BAR" ""
1098
;;; %CURSOR-MARKER%)). Only the forms up to point should be
1099
;;; considered.
1100
1101
(defslimefun autodoc (raw-form &key print-right-margin)
1102
"Return a string representing the arglist for the deepest subform in
1103
RAW-FORM that does have an arglist. The highlighted parameter is
1104
wrapped in ===> X <===."
1105
(handler-bind ((serious-condition
1106
#'(lambda (c)
1107
(unless (debug-on-swank-error)
1108
(let ((*print-right-margin* print-right-margin))
1109
(return-from autodoc
1110
(format nil "Arglist Error: \"~A\"" c)))))))
1111
(with-buffer-syntax ()
1112
(multiple-value-bind (form arglist obj-at-cursor form-path)
1113
(find-subform-with-arglist (parse-raw-form raw-form))
1114
(cond ((interesting-variable-p obj-at-cursor)
1115
(print-variable-to-string obj-at-cursor))
1116
(t
1117
(with-available-arglist (arglist) arglist
1118
(decoded-arglist-to-string
1119
arglist
1120
:print-right-margin print-right-margin
1121
:operator (car form)
1122
:highlight (form-path-to-arglist-path form-path
1123
form
1124
arglist)))))))))
1125
1126
(defun print-variable-to-string (symbol)
1127
"Return a short description of VARIABLE-NAME, or NIL."
1128
(let ((*print-pretty* t) (*print-level* 4)
1129
(*print-length* 10) (*print-lines* 1)
1130
(*print-readably* nil))
1131
(call/truncated-output-to-string
1132
75 (lambda (s)
1133
(format s "~A => ~S" symbol (symbol-value symbol))))))
1134
1135
1136
(defslimefun complete-form (raw-form)
1137
"Read FORM-STRING in the current buffer package, then complete it
1138
by adding a template for the missing arguments."
1139
;; We do not catch errors here because COMPLETE-FORM is an
1140
;; interactive command, not automatically run in the background like
1141
;; ARGLIST-FOR-ECHO-AREA.
1142
(with-buffer-syntax ()
1143
(multiple-value-bind (arglist provided-args)
1144
(find-immediately-containing-arglist (parse-raw-form raw-form))
1145
(with-available-arglist (arglist) arglist
1146
(decoded-arglist-to-template-string
1147
(delete-given-args arglist
1148
(remove-if #'empty-arg-p provided-args
1149
:from-end t :count 1))
1150
:prefix "" :suffix "")))))
1151
1152
(defslimefun completions-for-keyword (keyword-string raw-form)
1153
"Return a list of possible completions for KEYWORD-STRING relative
1154
to the context provided by RAW-FORM."
1155
(with-buffer-syntax ()
1156
(let ((arglist (find-immediately-containing-arglist
1157
(parse-raw-form raw-form))))
1158
(when (arglist-available-p arglist)
1159
;; It would be possible to complete keywords only if we are in
1160
;; a keyword position, but it is not clear if we want that.
1161
(let* ((keywords
1162
(append (mapcar #'keyword-arg.keyword
1163
(arglist.keyword-args arglist))
1164
(remove-if-not #'keywordp (arglist.any-args arglist))))
1165
(keyword-name
1166
(tokenize-symbol keyword-string))
1167
(matching-keywords
1168
(find-matching-symbols-in-list
1169
keyword-name keywords (make-compound-prefix-matcher #\-)))
1170
(converter (completion-output-symbol-converter keyword-string))
1171
(strings
1172
(mapcar converter
1173
(mapcar #'symbol-name matching-keywords)))
1174
(completion-set
1175
(format-completion-set strings nil "")))
1176
(list completion-set
1177
(longest-compound-prefix completion-set)))))))
1178
1179
(defparameter +cursor-marker+ '%cursor-marker%)
1180
1181
(defun find-subform-with-arglist (form)
1182
"Returns four values:
1183
1184
The appropriate subform of `form' which is closest to the
1185
+CURSOR-MARKER+ and whose operator is valid and has an
1186
arglist. The +CURSOR-MARKER+ is removed from that subform.
1187
1188
Second value is the arglist. Local function and macro definitions
1189
appearing in `form' into account.
1190
1191
Third value is the object in front of +CURSOR-MARKER+.
1192
1193
Fourth value is a form path to that object."
1194
(labels
1195
((yield-success (form local-ops)
1196
(multiple-value-bind (form obj-at-cursor form-path)
1197
(extract-cursor-marker form)
1198
(values form
1199
(let ((entry (assoc (car form) local-ops :test #'op=)))
1200
(if entry
1201
(decode-arglist (cdr entry))
1202
(arglist-from-form form)))
1203
obj-at-cursor
1204
form-path)))
1205
(yield-failure ()
1206
(values nil :not-available))
1207
(operator-p (operator local-ops)
1208
(or (and (symbolp operator) (valid-operator-symbol-p operator))
1209
(assoc operator local-ops :test #'op=)))
1210
(op= (op1 op2)
1211
(cond ((and (symbolp op1) (symbolp op2))
1212
(eq op1 op2))
1213
((and (arglist-dummy-p op1) (arglist-dummy-p op2))
1214
(string= (arglist-dummy.string-representation op1)
1215
(arglist-dummy.string-representation op2)))))
1216
(grovel-form (form local-ops)
1217
"Descend FORM top-down, always taking the rightest branch,
1218
until +CURSOR-MARKER+."
1219
(assert (listp form))
1220
(destructuring-bind (operator . args) form
1221
;; N.b. the user's cursor is at the rightmost, deepest
1222
;; subform right before +CURSOR-MARKER+.
1223
(let ((last-subform (car (last form)))
1224
(new-ops))
1225
(cond
1226
((eq last-subform +cursor-marker+)
1227
(if (operator-p operator local-ops)
1228
(yield-success form local-ops)
1229
(yield-failure)))
1230
((not (operator-p operator local-ops))
1231
(grovel-form last-subform local-ops))
1232
;; Make sure to pick up the arglists of local
1233
;; function/macro definitions.
1234
((setq new-ops (extract-local-op-arglists operator args))
1235
(multiple-value-or (grovel-form last-subform
1236
(nconc new-ops local-ops))
1237
(yield-success form local-ops)))
1238
;; Some typespecs clash with function names, so we make
1239
;; sure to bail out early.
1240
((member operator '(cl:declare cl:declaim))
1241
(yield-success form local-ops))
1242
;; Mostly uninteresting, hence skip.
1243
((memq operator '(cl:quote cl:function))
1244
(yield-failure))
1245
(t
1246
(multiple-value-or (grovel-form last-subform local-ops)
1247
(yield-success form local-ops))))))))
1248
(if (null form)
1249
(yield-failure)
1250
(grovel-form form '()))))
1251
1252
(defun extract-cursor-marker (form)
1253
"Returns three values: normalized `form' without +CURSOR-MARKER+,
1254
the object in front of +CURSOR-MARKER+, and a form path to that
1255
object."
1256
(labels ((grovel (form last path)
1257
(let ((result-form))
1258
(loop for (car . cdr) on form do
1259
(cond ((eql car +cursor-marker+)
1260
(decf (first path))
1261
(return-from grovel
1262
(values (nreconc result-form cdr)
1263
last
1264
(nreverse path))))
1265
((consp car)
1266
(multiple-value-bind (new-car new-last new-path)
1267
(grovel car last (cons 0 path))
1268
(when new-path ; CAR contained cursor-marker?
1269
(return-from grovel
1270
(values (nreconc
1271
(cons new-car result-form) cdr)
1272
new-last
1273
new-path))))))
1274
(push car result-form)
1275
(setq last car)
1276
(incf (first path))
1277
finally
1278
(return-from grovel
1279
(values (nreverse result-form) nil nil))))))
1280
(grovel form nil (list 0))))
1281
1282
(defgeneric extract-local-op-arglists (operator args)
1283
(:documentation
1284
"If the form `(OPERATOR ,@ARGS) is a local operator binding form,
1285
return a list of pairs (OP . ARGLIST) for each locally bound op.")
1286
(:method (operator args)
1287
(declare (ignore operator args))
1288
nil)
1289
;; FLET
1290
(:method ((operator (eql 'cl:flet)) args)
1291
(let ((defs (first args))
1292
(body (rest args)))
1293
(cond ((null body) nil) ; `(flet ((foo (x) |'
1294
((atom defs) nil) ; `(flet ,foo (|'
1295
(t (%collect-op/argl-alist defs)))))
1296
;; LABELS
1297
(:method ((operator (eql 'cl:labels)) args)
1298
;; Notice that we only have information to "look backward" and
1299
;; show arglists of previously occuring local functions.
1300
(destructuring-bind (defs . body) args
1301
(unless (or (atom defs) (null body)) ; `(labels ,foo (|'
1302
(let ((current-def (car (last defs))))
1303
(cond ((atom current-def) nil) ; `(labels ((foo (x) ...)|'
1304
((not (null body))
1305
(extract-local-op-arglists 'cl:flet args))
1306
(t
1307
(let ((def.body (cddr current-def)))
1308
(when def.body
1309
(%collect-op/argl-alist defs)))))))))
1310
;; MACROLET
1311
(:method ((operator (eql 'cl:macrolet)) args)
1312
(extract-local-op-arglists 'cl:labels args)))
1313
1314
(defun %collect-op/argl-alist (defs)
1315
(setq defs (remove-if-not #'(lambda (x)
1316
;; Well-formed FLET/LABELS def?
1317
(and (consp x) (second x)))
1318
defs))
1319
(loop for (name arglist . nil) in defs
1320
collect (cons name arglist)))
1321
1322
(defun find-immediately-containing-arglist (form)
1323
"Returns the arglist of the subform _immediately_ containing
1324
+CURSOR-MARKER+ in `form'. Notice, however, that +CURSOR-MARKER+ may
1325
be in a nested arglist \(e.g. `(WITH-OPEN-FILE (<here>'\), and the
1326
arglist of the appropriate parent form \(WITH-OPEN-FILE\) will be
1327
returned in that case."
1328
(flet ((try (form-path form arglist)
1329
(let* ((arglist-path (form-path-to-arglist-path form-path
1330
form
1331
arglist))
1332
(argl (apply #'arglist-ref
1333
arglist
1334
arglist-path))
1335
(args (apply #'provided-arguments-ref
1336
(cdr form)
1337
arglist
1338
arglist-path)))
1339
(when (and (arglist-p argl) (listp args))
1340
(values argl args)))))
1341
(multiple-value-bind (form arglist obj form-path)
1342
(find-subform-with-arglist form)
1343
(declare (ignore obj))
1344
(with-available-arglist (arglist) arglist
1345
;; First try the form the cursor is in (in case of a normal
1346
;; form), then try the surrounding form (in case of a nested
1347
;; macro form).
1348
(multiple-value-or (try form-path form arglist)
1349
(try (butlast form-path) form arglist)
1350
:not-available)))))
1351
1352
(defun form-path-to-arglist-path (form-path form arglist)
1353
"Convert a form path to an arglist path consisting of arglist
1354
indices."
1355
(labels ((convert (path args arglist)
1356
(if (null path)
1357
nil
1358
(let* ((idx (car path))
1359
(idx* (arglist-index idx args arglist))
1360
(arglist* (and idx* (arglist-ref arglist idx*)))
1361
(args* (and idx* (provided-arguments-ref args
1362
arglist
1363
idx*))))
1364
;; The FORM-PATH may be more detailed than ARGLIST;
1365
;; consider (defun foo (x y) ...), a form path may
1366
;; point into the function's lambda-list, but the
1367
;; arglist of DEFUN won't contain as much information.
1368
;; So we only recurse if possible.
1369
(cond ((null idx*)
1370
nil)
1371
((arglist-p arglist*)
1372
(cons idx* (convert (cdr path) args* arglist*)))
1373
(t
1374
(list idx*)))))))
1375
(convert
1376
;; FORM contains irrelevant operator. Adjust FORM-PATH.
1377
(cond ((null form-path) nil)
1378
((equal form-path '(0)) nil)
1379
(t
1380
(destructuring-bind (car . cdr) form-path
1381
(cons (1- car) cdr))))
1382
(cdr form)
1383
arglist)))
1384
1385
(defun arglist-index (provided-argument-index provided-arguments arglist)
1386
"Return the arglist index into `arglist' for the parameter belonging
1387
to the argument (NTH `provided-argument-index' `provided-arguments')."
1388
(let ((positional-args# (positional-args-number arglist))
1389
(arg-index provided-argument-index))
1390
(with-struct (arglist. key-p rest) arglist
1391
(cond
1392
((< arg-index positional-args#) ; required + optional
1393
arg-index)
1394
((and (not key-p) (not rest)) ; more provided than allowed
1395
nil)
1396
((not key-p) ; rest + body
1397
(assert (arglist.rest arglist))
1398
positional-args#)
1399
(t ; key
1400
;; Find last provided &key parameter
1401
(let* ((argument (nth arg-index provided-arguments))
1402
(provided-keys (subseq provided-arguments positional-args#)))
1403
(loop for (key value) on provided-keys by #'cddr
1404
when (eq value argument)
1405
return (match key
1406
(('quote symbol) symbol)
1407
(_ key)))))))))
1408
1409
(defun arglist-ref (arglist &rest indices)
1410
"Returns the parameter in ARGLIST along the INDICIES path. Numbers
1411
represent positional parameters (required, optional), keywords
1412
represent key parameters."
1413
(flet ((ref-positional-arg (arglist index)
1414
(check-type index (integer 0 *))
1415
(with-struct (arglist. provided-args required-args optional-args rest)
1416
arglist
1417
(loop for args in (list provided-args required-args
1418
(mapcar #'optional-arg.arg-name optional-args))
1419
for args# = (length args)
1420
if (< index args#)
1421
return (nth index args)
1422
else
1423
do (decf index args#)
1424
finally (return (or rest nil)))))
1425
(ref-keyword-arg (arglist keyword)
1426
;; keyword argument may be any symbol,
1427
;; not only from the KEYWORD package.
1428
(let ((keyword (match keyword
1429
(('quote symbol) symbol)
1430
(_ keyword))))
1431
(do-decoded-arglist arglist
1432
(&key (kw arg) (when (eq kw keyword)
1433
(return-from ref-keyword-arg arg)))))
1434
nil))
1435
(dolist (index indices)
1436
(assert (arglist-p arglist))
1437
(setq arglist (if (numberp index)
1438
(ref-positional-arg arglist index)
1439
(ref-keyword-arg arglist index))))
1440
arglist))
1441
1442
(defun provided-arguments-ref (provided-args arglist &rest indices)
1443
"Returns the argument in PROVIDED-ARGUMENT along the INDICES path
1444
relative to ARGLIST."
1445
(check-type arglist arglist)
1446
(flet ((ref (provided-args arglist index)
1447
(if (numberp index)
1448
(nth index provided-args)
1449
(let ((provided-keys (subseq provided-args
1450
(positional-args-number arglist))))
1451
(loop for (key value) on provided-keys
1452
when (eq key index)
1453
return value)))))
1454
(dolist (idx indices)
1455
(setq provided-args (ref provided-args arglist idx))
1456
(setq arglist (arglist-ref arglist idx)))
1457
provided-args))
1458
1459
(defun positional-args-number (arglist)
1460
(+ (length (arglist.provided-args arglist))
1461
(length (arglist.required-args arglist))
1462
(length (arglist.optional-args arglist))))
1463
1464
(defun parse-raw-form (raw-form)
1465
"Parse a RAW-FORM into a Lisp form. I.e. substitute strings by
1466
symbols if already interned. For strings not already interned, use
1467
ARGLIST-DUMMY."
1468
(unless (null raw-form)
1469
(loop for element in raw-form
1470
collect (etypecase element
1471
(string (read-conversatively element))
1472
(list (parse-raw-form element))
1473
(symbol (prog1 element
1474
;; Comes after list, so ELEMENT can't be NIL.
1475
(assert (eq element +cursor-marker+))))))))
1476
1477
(defun read-conversatively (string)
1478
"Tries to find the symbol that's represented by STRING.
1479
1480
If it can't, this either means that STRING does not represent a
1481
symbol, or that the symbol behind STRING would have to be freshly
1482
interned. Because this function is supposed to be called from the
1483
automatic arglist display stuff from Slime, interning freshly
1484
symbols is a big no-no.
1485
1486
In such a case (that no symbol could be found), an object of type
1487
ARGLIST-DUMMY is returned instead, which works as a placeholder
1488
datum for subsequent logics to rely on."
1489
(let* ((string (string-left-trim '(#\Space #\Tab #\Newline) string))
1490
(length (length string))
1491
(type (cond ((zerop length) nil)
1492
((eql (aref string 0) #\')
1493
:quoted-symbol)
1494
((search "#'" string :end2 (min length 2))
1495
:sharpquoted-symbol)
1496
((and (eql (aref string 0) #\")
1497
(eql (aref string (1- length)) #\"))
1498
:string)
1499
(t
1500
:symbol))))
1501
(multiple-value-bind (symbol found?)
1502
(case type
1503
(:symbol (parse-symbol string))
1504
(:quoted-symbol (parse-symbol (subseq string 1)))
1505
(:sharpquoted-symbol (parse-symbol (subseq string 2)))
1506
(:string (values string t))
1507
(t (values string nil)))
1508
(if found?
1509
(ecase type
1510
(:symbol symbol)
1511
(:quoted-symbol `(quote ,symbol))
1512
(:sharpquoted-symbol `(function ,symbol))
1513
(:string string))
1514
(make-arglist-dummy string)))))
1515
1516
(defun test-print-arglist ()
1517
(flet ((test (arglist string)
1518
(let* ((*package* (find-package :swank))
1519
(actual (decoded-arglist-to-string (decode-arglist arglist))))
1520
(unless (string= actual string)
1521
(warn "Test failed: ~S => ~S~% Expected: ~S"
1522
arglist actual string)))))
1523
(test '(function cons) "(function cons)")
1524
(test '(quote cons) "(quote cons)")
1525
(test '(&key (function #'+)) "(&key (function #'+))")
1526
(test '(&whole x y z) "(y z)")
1527
(test '(x &aux y z) "(x)")
1528
(test '(x &environment env y) "(x y)")
1529
(test '(&key ((function f))) "(&key ((function ..)))")
1530
(test '(eval-when (&any :compile-toplevel :load-toplevel :execute) &body body)
1531
"(eval-when (&any :compile-toplevel :load-toplevel :execute) &body body)")
1532
(test '(declare (optimize &any (speed 1) (safety 1)))
1533
"(declare (optimize &any (speed 1) (safety 1)))")
1534
))
1535
1536
(defun test-arglist-ref ()
1537
(macrolet ((soft-assert (form)
1538
`(unless ,form
1539
(warn "Assertion failed: ~S~%" ',form))))
1540
(let ((sample (decode-arglist '(x &key ((:k (y z)))))))
1541
(soft-assert (eq (arglist-ref sample 0) 'x))
1542
(soft-assert (eq (arglist-ref sample :k 0) 'y))
1543
(soft-assert (eq (arglist-ref sample :k 1) 'z))
1544
1545
(soft-assert (eq (provided-arguments-ref '(a :k (b c)) sample 0) 'a))
1546
(soft-assert (eq (provided-arguments-ref '(a :k (b c)) sample :k 0) 'b))
1547
(soft-assert (eq (provided-arguments-ref '(a :k (b c)) sample :k 1) 'c)))))
1548
1549
(test-print-arglist)
1550
(test-arglist-ref)
1551
1552
(provide :swank-arglists)
1553
1554