src/c-types-{proto,impl,parse}.lisp: Add `storage specifiers' to the model.
[sod] / src / c-types-impl.lisp
CommitLineData
abdf50aa
MW
1;;; -*-lisp-*-
2;;;
dea4d055 3;;; C type representation implementation
abdf50aa 4;;;
dea4d055 5;;; (c) 2009 Straylight/Edgeware
abdf50aa
MW
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
e0808c47 10;;; This file is part of the Sensible Object Design, an object system for C.
abdf50aa
MW
11;;;
12;;; SOD is free software; you can redistribute it and/or modify
13;;; it under the terms of the GNU General Public License as published by
14;;; the Free Software Foundation; either version 2 of the License, or
15;;; (at your option) any later version.
16;;;
17;;; SOD is distributed in the hope that it will be useful,
18;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;;; GNU General Public License for more details.
21;;;
22;;; You should have received a copy of the GNU General Public License
23;;; along with SOD; if not, write to the Free Software Foundation,
24;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26(cl:in-package #:sod)
27
28;;;--------------------------------------------------------------------------
dea4d055
MW
29;;; Interning types.
30
31(defparameter *c-type-intern-map* (make-hash-table :test #'equal)
32 "Hash table mapping lists describing types to their distinguished
33 representations.")
34
35(defun intern-c-type (class &rest initargs)
36 "If the CLASS and INITARGS have already been interned, then return the
37 existing object; otherwise make a new one."
38 (let ((list (cons class initargs)))
39 (or (gethash list *c-type-intern-map*)
40 (let ((new (apply #'make-instance class initargs)))
41 (setf (gethash new *c-type-intern-map*) t
42 (gethash list *c-type-intern-map*) new)))))
43
44#+test
45(defun check-type-intern-map ()
46 "Sanity check for the type-intern map."
47 (let ((map (make-hash-table)))
48
49 ;; Pass 1: check that interned types are consistent with their keys.
50 ;; Remember interned types.
51 (maphash (lambda (k v)
52 (when (listp k)
53 (let ((ty (apply #'make-instance k)))
54 (assert (c-type-equal-p ty v)))
55 (setf (gethash v map) t)))
56 *c-type-intern-map*)
57
58 ;; Pass 2: check that the interned type indicators are correct.
59 (maphash (lambda (k v)
60 (declare (ignore v))
61 (assert (gethash k *c-type-intern-map*)))
62 map)
63 (maphash (lambda (k v)
64 (declare (ignore v))
65 (when (typep k 'c-type)
66 (assert (gethash k map))))
67 *c-type-intern-map*)))
abdf50aa 68
2b2252cc
MW
69(defun make-or-intern-c-type (new-type-class base-types &rest initargs)
70 "Return a possibly-new instance of NEW-TYPE-CLASS with the given INITARGS.
71
72 If all of the BASE-TYPES are interned, then use `intern-c-type' to
73 construct the new type; otherwise just make a new one with
74 `make-instance'. BASE-TYPES may be a singleton type, or a sequence of
75 types."
76 (apply (if (if (typep base-types 'sequence)
77 (every (lambda (type)
78 (gethash type *c-type-intern-map*))
79 base-types)
80 (gethash base-types *c-type-intern-map*))
81 #'intern-c-type #'make-instance)
82 new-type-class
83 initargs))
84
b5c8ba34
MW
85;;;--------------------------------------------------------------------------
86;;; Qualifiers.
87
88(defmethod c-qualifier-keyword ((qualifier (eql :atomic))) "_Atomic")
89
bf090e02
MW
90(defmethod qualify-c-type ((type qualifiable-c-type) qualifiers)
91 (let ((initargs (instance-initargs type)))
92 (remf initargs :qualifiers)
2b2252cc 93 (apply #'make-or-intern-c-type (class-of type) type
bf090e02
MW
94 :qualifiers (canonify-qualifiers
95 (append qualifiers (c-type-qualifiers type)))
96 initargs)))
97
abdf50aa 98;;;--------------------------------------------------------------------------
b7fcf941
MW
99;;; Storage specifiers.
100
101(defmethod c-type-equal-p :around
102 ((type-a c-storage-specifiers-type) (type-b c-type))
103 "Ignore storage specifiers when comparing C types."
104 (c-type-equal-p (c-type-subtype type-a) type-b))
105
106(defmethod c-type-equal-p :around
107 ((type-a c-type) (type-b c-storage-specifiers-type))
108 "Ignore storage specifiers when comparing C types."
109 (c-type-equal-p type-a (c-type-subtype type-b)))
110
111(defun make-storage-specifiers-type (subtype specifiers)
112 "Construct a type based on SUBTYPE, carrying the storage SPECIFIERS."
113 (if (null specifiers) subtype
114 (make-or-intern-c-type 'c-storage-specifiers-type subtype
115 :specifiers specifiers
116 :subtype subtype)))
117
118(defmethod pprint-c-type ((type c-storage-specifiers-type) stream kernel)
119 (dolist (spec (c-type-specifiers type))
120 (pprint-c-storage-specifier spec stream)
121 (write-char #\space stream)
122 (pprint-newline :miser stream))
123 (pprint-c-type (c-type-subtype type) stream kernel))
124
125(defmethod print-c-type
126 (stream (type c-storage-specifiers-type) &optional colon atsign)
127 (declare (ignore colon atsign))
128 (format stream "~:@<SPECS ~@_~:I~/sod:print-c-type/~
129 ~{ ~_~/sod:print-c-storage-specifier/~}~:>"
130 (c-type-subtype type) (c-type-specifiers type)))
131
132(export 'specs)
133(define-c-type-syntax specs (subtype &rest specifiers)
134 `(make-storage-specifiers-type
135 ,(expand-c-type-spec subtype)
136 (list ,@(mapcar #'expand-c-storage-specifier specifiers))))
137
138;;;--------------------------------------------------------------------------
dea4d055 139;;; Simple C types.
abdf50aa 140
dea4d055 141;; Class definition.
abdf50aa 142
dea4d055
MW
143(export '(simple-c-type c-type-name))
144(defclass simple-c-type (qualifiable-c-type)
145 ((name :initarg :name :type string :reader c-type-name))
abdf50aa 146 (:documentation
dea4d055 147 "C types with simple forms."))
abdf50aa 148
dea4d055 149;; Constructor function and interning.
abdf50aa 150
dea4d055
MW
151(export 'make-simple-type)
152(defun make-simple-type (name &optional qualifiers)
153 "Make a distinguished object for the simple type called NAME."
154 (intern-c-type 'simple-c-type
155 :name name
156 :qualifiers (canonify-qualifiers qualifiers)))
abdf50aa 157
dea4d055 158;; Comparison protocol.
abdf50aa 159
dea4d055
MW
160(defmethod c-type-equal-p and
161 ((type-a simple-c-type) (type-b simple-c-type))
162 (string= (c-type-name type-a) (c-type-name type-b)))
abdf50aa 163
dea4d055 164;; C syntax output protocol.
1f1d88f5
MW
165
166(defmethod pprint-c-type ((type simple-c-type) stream kernel)
167 (pprint-logical-block (stream nil)
ff4e398b
MW
168 (format stream "~{~A ~@_~}~A"
169 (c-type-qualifier-keywords type)
1f1d88f5
MW
170 (c-type-name type))
171 (funcall kernel stream 0 t)))
abdf50aa 172
dea4d055
MW
173;; S-expression notation protocol.
174
175(defparameter *simple-type-map* (make-hash-table)
176 "Hash table mapping strings of C syntax to symbolic names.")
abdf50aa
MW
177
178(defmethod print-c-type (stream (type simple-c-type) &optional colon atsign)
179 (declare (ignore colon atsign))
180 (let* ((name (c-type-name type))
181 (symbol (gethash name *simple-type-map*)))
1f1d88f5
MW
182 (format stream "~:[~S~;~:@<~S~0@*~{ ~_~S~}~:>~]"
183 (c-type-qualifiers type) (or symbol name))))
abdf50aa 184
1f1d88f5
MW
185(eval-when (:compile-toplevel :load-toplevel :execute)
186 (defmethod expand-c-type-spec ((spec string))
187 `(make-simple-type ,spec))
188 (defmethod expand-c-type-form ((head string) tail)
dea4d055 189 `(make-simple-type ,head (list ,@tail))))
abdf50aa 190
dea4d055 191(export 'define-simple-c-type)
e43d3532 192(defmacro define-simple-c-type (names type &key export)
abdf50aa 193 "Define each of NAMES to be a simple type called TYPE."
1f1d88f5
MW
194 (let ((names (if (listp names) names (list names))))
195 `(progn
196 (setf (gethash ,type *simple-type-map*) ',(car names))
e43d3532 197 (defctype ,names ,type :export ,export)
1f1d88f5
MW
198 (define-c-type-syntax ,(car names) (&rest quals)
199 `(make-simple-type ,',type (list ,@quals))))))
abdf50aa 200
dea4d055
MW
201;; Built-in C types.
202
e43d3532
MW
203(define-simple-c-type void "void" :export t)
204
205(define-simple-c-type char "char" :export t)
206(define-simple-c-type (unsigned-char uchar) "unsigned char" :export t)
207(define-simple-c-type (signed-char schar) "signed char" :export t)
208(define-simple-c-type wchar-t "wchar-t" :export t)
209
210(define-simple-c-type (int signed signed-int sint) "int" :export t)
211(define-simple-c-type (unsigned unsigned-int uint) "unsigned" :export t)
abdf50aa
MW
212
213(define-simple-c-type (short signed-short short-int signed-short-int sshort)
e43d3532 214 "short" :export t)
abdf50aa 215(define-simple-c-type (unsigned-short unsigned-short-int ushort)
e43d3532 216 "unsigned short" :export t)
abdf50aa
MW
217
218(define-simple-c-type (long signed-long long-int signed-long-int slong)
e43d3532 219 "long" :export t)
abdf50aa 220(define-simple-c-type (unsigned-long unsigned-long-int ulong)
e43d3532 221 "unsigned long" :export t)
abdf50aa
MW
222
223(define-simple-c-type (long-long signed-long-long long-long-int
224 signed-long-long-int llong sllong)
e43d3532 225 "long long" :export t)
abdf50aa 226(define-simple-c-type (unsigned-long-long unsigned-long-long-int ullong)
e43d3532 227 "unsigned long long" :export t)
abdf50aa 228
e43d3532
MW
229(define-simple-c-type float "float" :export t)
230(define-simple-c-type double "double" :export t)
231(define-simple-c-type long-double "long double" :export t)
abdf50aa 232
e43d3532 233(define-simple-c-type bool "_Bool" :export t)
0e7cdea0 234
e43d3532
MW
235(define-simple-c-type float-complex "float _Complex" :export t)
236(define-simple-c-type double-complex "double _Complex" :export t)
237(define-simple-c-type long-double-complex "long double _Complex" :export t)
0e7cdea0 238
e43d3532
MW
239(define-simple-c-type float-imaginary "float _Imaginary" :export t)
240(define-simple-c-type double-imaginary "double _Imaginary" :export t)
241(define-simple-c-type long-double-imaginary
242 "long double _Imaginary" :export t)
0e7cdea0 243
e43d3532
MW
244(define-simple-c-type va-list "va_list" :export t)
245(define-simple-c-type size-t "size_t" :export t)
246(define-simple-c-type ptrdiff-t "ptrdiff_t" :export t)
abdf50aa
MW
247
248;;;--------------------------------------------------------------------------
dea4d055 249;;; Tagged types (enums, structs and unions).
abdf50aa 250
dea4d055 251;; Class definition.
abdf50aa 252
dea4d055 253(export '(tagged-c-type c-type-tag))
abdf50aa 254(defclass tagged-c-type (qualifiable-c-type)
77027cca 255 ((tag :initarg :tag :type string :reader c-type-tag))
abdf50aa
MW
256 (:documentation
257 "C types with tags."))
258
dea4d055
MW
259;; Subclass definitions.
260
261(export 'c-tagged-type-kind)
abdf50aa
MW
262(defgeneric c-tagged-type-kind (type)
263 (:documentation
264 "Return the kind of tagged type that TYPE is, as a keyword."))
265
dea4d055
MW
266(export 'kind-c-tagged-type)
267(defgeneric kind-c-tagged-type (kind)
268 (:documentation
269 "Given a keyword KIND, return the appropriate class name."))
270
271(export 'make-c-tagged-type)
272(defun make-c-tagged-type (kind tag &optional qualifiers)
273 "Return a tagged type with the given KIND (keyword) and TAG (string)."
274 (intern-c-type (kind-c-tagged-type kind)
275 :tag tag
276 :qualifiers (canonify-qualifiers qualifiers)))
277
abdf50aa 278(macrolet ((define-tagged-type (kind what)
dea4d055
MW
279 (let* ((type (symbolicate 'c- kind '-type))
280 (keyword (intern (symbol-name kind) :keyword))
281 (constructor (symbolicate 'make- kind '-type)))
abdf50aa 282 `(progn
bf090e02 283 (export '(,type ,kind ,constructor))
abdf50aa
MW
284 (defclass ,type (tagged-c-type) ()
285 (:documentation ,(format nil "C ~a types." what)))
286 (defmethod c-tagged-type-kind ((type ,type))
dea4d055
MW
287 ',keyword)
288 (defmethod kind-c-tagged-type ((kind (eql ',keyword)))
289 ',type)
290 (defun ,constructor (tag &optional qualifiers)
291 (intern-c-type ',type :tag tag
292 :qualifiers (canonify-qualifiers
293 qualifiers)))
1f1d88f5
MW
294 (define-c-type-syntax ,kind (tag &rest quals)
295 ,(format nil "Construct ~A type named TAG" what)
296 `(,',constructor ,tag (list ,@quals)))))))
297 (define-tagged-type enum "enumerated")
298 (define-tagged-type struct "structure")
299 (define-tagged-type union "union"))
300
dea4d055
MW
301;; Comparison protocol.
302
303(defmethod c-type-equal-p and ((type-a tagged-c-type) (type-b tagged-c-type))
304 (string= (c-type-tag type-a) (c-type-tag type-b)))
305
306;; C syntax output protocol.
307
1f1d88f5
MW
308(defmethod pprint-c-type ((type tagged-c-type) stream kernel)
309 (pprint-logical-block (stream nil)
ff4e398b
MW
310 (format stream "~{~A ~@_~}~(~A~) ~A"
311 (c-type-qualifier-keywords type)
1f1d88f5
MW
312 (c-tagged-type-kind type)
313 (c-type-tag type))
314 (funcall kernel stream 0 t)))
abdf50aa 315
dea4d055 316;; S-expression notation protocol.
abdf50aa
MW
317
318(defmethod print-c-type (stream (type tagged-c-type) &optional colon atsign)
319 (declare (ignore colon atsign))
1f1d88f5 320 (format stream "~:@<~S ~@_~S~{ ~_~S~}~:>"
abdf50aa 321 (c-tagged-type-kind type)
1f1d88f5
MW
322 (c-type-tag type)
323 (c-type-qualifiers type)))
abdf50aa
MW
324
325;;;--------------------------------------------------------------------------
ae0f15ee
MW
326;;; Atomic types.
327
328;; Class definition.
329
330(export 'c-atomic-type)
331(defclass c-atomic-type (qualifiable-c-type)
332 ((subtype :initarg :subtype :type c-type :reader c-type-subtype))
333 (:documentation "C atomic types."))
334
335;; Constructor function.
336
337(export 'make-atomic-type)
338(defun make-atomic-type (subtype &optional qualifiers)
339 "Return a (maybe distinguished) atomic type."
340 (make-or-intern-c-type 'c-atomic-type subtype
341 :subtype subtype
342 :qualifiers (canonify-qualifiers qualifiers)))
343
344;; Comparison protocol.
345
346(defmethod c-type-equal-p and ((type-a c-atomic-type) (type-b c-atomic-type))
347 (c-type-equal-p (c-type-subtype type-a) (c-type-subtype type-b)))
348
349;; C-syntax output protocol.
350
351(defmethod pprint-c-type ((type c-atomic-type) stream kernel)
352 (pprint-logical-block (stream nil)
353 (format stream "~{~A ~@_~}" (c-type-qualifier-keywords type))
354 (write-string "_Atomic(" stream)
355 (pprint-indent :current 0 stream)
356 (pprint-c-type (c-type-subtype type) stream
357 (lambda (stream prio spacep)
358 (declare (ignore stream prio spacep))))
359 (write-char #\) stream)))
360
361;; S-expression notation protocol.
362
363(defmethod print-c-type (stream (type c-atomic-type) &optional colon atsign)
364 (declare (ignore colon atsign))
365 (format stream "~:@<ATOMIC ~@_~/sod:print-c-type/~{ ~_~S~}~:>"
366 (c-type-subtype type)
367 (c-type-qualifiers type)))
368
369(export 'atomic)
370(define-c-type-syntax atomic (sub &rest quals)
371 "Return the type of atomic SUB."
372 `(make-atomic-type ,(expand-c-type-spec sub) (list ,@quals)))
373
374;;;--------------------------------------------------------------------------
abdf50aa
MW
375;;; Pointer types.
376
dea4d055 377;; Class definition.
abdf50aa 378
dea4d055 379(export 'c-pointer-type)
abdf50aa 380(defclass c-pointer-type (qualifiable-c-type)
77027cca 381 ((subtype :initarg :subtype :type c-type :reader c-type-subtype))
dea4d055 382 (:documentation "C pointer types."))
abdf50aa 383
dea4d055
MW
384;; Constructor function.
385
386(export 'make-pointer-type)
387(defun make-pointer-type (subtype &optional qualifiers)
388 "Return a (maybe distinguished) pointer type."
2b2252cc
MW
389 (make-or-intern-c-type 'c-pointer-type subtype
390 :subtype subtype
391 :qualifiers (canonify-qualifiers qualifiers)))
dea4d055
MW
392
393;; Comparison protocol.
394
395(defmethod c-type-equal-p and ((type-a c-pointer-type)
396 (type-b c-pointer-type))
397 (c-type-equal-p (c-type-subtype type-a) (c-type-subtype type-b)))
398
399;; C syntax output protocol.
1f1d88f5
MW
400
401(defmethod pprint-c-type ((type c-pointer-type) stream kernel)
402 (pprint-c-type (c-type-subtype type) stream
403 (lambda (stream prio spacep)
404 (when spacep (c-type-space stream))
405 (maybe-in-parens (stream (> prio 1))
ff4e398b
MW
406 (format stream "*~{~A~^ ~@_~}"
407 (c-type-qualifier-keywords type))
1f1d88f5 408 (funcall kernel stream 1 (c-type-qualifiers type))))))
abdf50aa 409
dea4d055 410;; S-expression notation protocol.
abdf50aa
MW
411
412(defmethod print-c-type (stream (type c-pointer-type) &optional colon atsign)
413 (declare (ignore colon atsign))
dea4d055 414 (format stream "~:@<* ~@_~/sod:print-c-type/~{ ~_~S~}~:>"
1f1d88f5
MW
415 (c-type-subtype type)
416 (c-type-qualifiers type)))
abdf50aa 417
dea4d055 418(export '(* pointer ptr))
1f1d88f5 419(define-c-type-syntax * (sub &rest quals)
abdf50aa 420 "Return the type of pointer-to-SUB."
1f1d88f5
MW
421 `(make-pointer-type ,(expand-c-type-spec sub) (list ,@quals)))
422(c-type-alias * pointer ptr)
abdf50aa 423
dea4d055
MW
424;; Built-in C types.
425
426(export '(string const-string))
abdf50aa 427(defctype string (* char))
1f1d88f5 428(defctype const-string (* (char :const)))
abdf50aa
MW
429
430;;;--------------------------------------------------------------------------
431;;; Array types.
432
dea4d055 433;; Class definition.
abdf50aa 434
dea4d055 435(export '(c-array-type c-array-dimensions))
abdf50aa 436(defclass c-array-type (c-type)
77027cca
MW
437 ((subtype :initarg :subtype :type c-type :reader c-type-subtype)
438 (dimensions :initarg :dimensions :type list :reader c-array-dimensions))
abdf50aa
MW
439 (:documentation
440 "C array types."))
441
dea4d055
MW
442;; Constructor function.
443
444(export 'make-array-type)
1f1d88f5
MW
445(defun make-array-type (subtype dimensions)
446 "Return a new array of SUBTYPE with given DIMENSIONS."
447 (make-instance 'c-array-type :subtype subtype
448 :dimensions (or dimensions '(nil))))
abdf50aa 449
dea4d055
MW
450;; Comparison protocol.
451
452(defmethod c-type-equal-p and ((type-a c-array-type) (type-b c-array-type))
453
454 ;; Messy. C doesn't have multidimensional arrays, but we fake them for
455 ;; convenience's sake. But it means that we have to arrange for
456 ;; multidimensional arrays to equal vectors of vectors -- and in general
457 ;; for multidimensional arrays of multidimensional arrays to match each
458 ;; other properly, even when their dimensions don't align precisely.
459 (labels ((check (sub-a dim-a sub-b dim-b)
460 (cond ((endp dim-a)
461 (cond ((endp dim-b)
462 (c-type-equal-p sub-a sub-b))
463 ((typep sub-a 'c-array-type)
464 (check (c-type-subtype sub-a)
465 (c-array-dimensions sub-a)
466 sub-b dim-b))
467 (t
468 nil)))
469 ((endp dim-b)
470 (check sub-b dim-b sub-a dim-a))
471 ((equal (car dim-a) (car dim-b))
472 (check sub-a (cdr dim-a) sub-b (cdr dim-b)))
473 (t
474 nil))))
475 (check (c-type-subtype type-a) (c-array-dimensions type-a)
476 (c-type-subtype type-b) (c-array-dimensions type-b))))
477
478;; C syntax output protocol.
479
1f1d88f5
MW
480(defmethod pprint-c-type ((type c-array-type) stream kernel)
481 (pprint-c-type (c-type-subtype type) stream
482 (lambda (stream prio spacep)
483 (maybe-in-parens (stream (> prio 2))
484 (funcall kernel stream 2 spacep)
485 (format stream "~@<~{[~@[~A~]]~^~_~}~:>"
486 (c-array-dimensions type))))))
abdf50aa 487
dea4d055 488;; S-expression notation protocol.
abdf50aa
MW
489
490(defmethod print-c-type (stream (type c-array-type) &optional colon atsign)
491 (declare (ignore colon atsign))
dea4d055 492 (format stream "~:@<[] ~@_~:I~/sod:print-c-type/~{ ~_~S~}~:>"
abdf50aa
MW
493 (c-type-subtype type)
494 (c-array-dimensions type)))
495
dea4d055 496(export '([] array vec))
1f1d88f5 497(define-c-type-syntax [] (sub &rest dims)
abdf50aa
MW
498 "Return the type of arrays of SUB with the dimensions DIMS.
499
500 If the DIMS are omitted, a single unknown-length dimension is added."
1f1d88f5
MW
501 `(make-array-type ,(expand-c-type-spec sub)
502 (list ,@(or dims '(nil)))))
503(c-type-alias [] array vec)
abdf50aa
MW
504
505;;;--------------------------------------------------------------------------
506;;; Function types.
507
dea4d055 508;; Function arguments.
abdf50aa 509
933bbda6 510(defun argument-lists-equal-p (list-a list-b)
1f1d88f5
MW
511 "Return whether LIST-A and LIST-B match.
512
513 They must have the same number of arguments, and each argument must have
3109662a 514 the same type, or be `:ellipsis'. The argument names are not inspected."
abdf50aa
MW
515 (and (= (length list-a) (length list-b))
516 (every (lambda (arg-a arg-b)
517 (if (eq arg-a :ellipsis)
518 (eq arg-b :ellipsis)
b4aab8d4
MW
519 (and (argumentp arg-a) (argumentp arg-b)
520 (c-type-equal-p (argument-type arg-a)
521 (argument-type arg-b)))))
abdf50aa
MW
522 list-a list-b)))
523
dea4d055 524;; Class definition.
1f1d88f5 525
dea4d055 526(export '(c-function-type c-function-arguments))
1f1d88f5 527(defclass c-function-type (c-type)
77027cca 528 ((subtype :initarg :subtype :type c-type :reader c-type-subtype)
8e36de0e 529 (arguments :type list :reader c-function-arguments))
1f1d88f5
MW
530 (:documentation
531 "C function types. The subtype is the return type, as implied by the C
532 syntax for function declarations."))
533
8e36de0e
MW
534(defmethod shared-initialize :after
535 ((type c-function-type) slot-names &key (arguments nil argsp))
536 (declare (ignore slot-names))
537 (when argsp
538 (setf (slot-value type 'arguments)
539 (if (and arguments
540 (null (cdr arguments))
541 (not (eq (car arguments) :ellipsis))
542 (eq (argument-type (car arguments)) c-type-void))
543 nil
544 arguments))))
545
dea4d055
MW
546;; Constructor function.
547
548(export 'make-function-type)
1f1d88f5
MW
549(defun make-function-type (subtype arguments)
550 "Return a new function type, returning SUBTYPE and accepting ARGUMENTS."
4d89d941 551 (make-instance 'c-function-type :subtype subtype
8e36de0e 552 :arguments arguments))
1f1d88f5 553
dea4d055
MW
554;; Comparison protocol.
555
556(defmethod c-type-equal-p and
557 ((type-a c-function-type) (type-b c-function-type))
558 (and (c-type-equal-p (c-type-subtype type-a) (c-type-subtype type-b))
933bbda6
MW
559 (argument-lists-equal-p (c-function-arguments type-a)
560 (c-function-arguments type-b))))
abdf50aa 561
dea4d055 562;; C syntax output protocol.
abdf50aa 563
4d89d941
MW
564(let ((void-arglist (list (make-argument nil c-type-void))))
565 (defmethod pprint-c-type ((type c-function-type) stream kernel)
566 (pprint-c-type (c-type-subtype type) stream
567 (lambda (stream prio spacep)
568 (maybe-in-parens (stream (> prio 2))
569 (when spacep (c-type-space stream))
570 (funcall kernel stream 2 nil)
571 (pprint-indent :block 4 stream)
572 (pprint-logical-block
573 (stream nil :prefix "(" :suffix ")")
574 (let ((firstp t))
575 (dolist (arg (or (c-function-arguments type)
576 void-arglist))
577 (if firstp
578 (setf firstp nil)
579 (format stream ", ~_"))
580 (if (eq arg :ellipsis)
581 (write-string "..." stream)
582 (pprint-c-type (argument-type arg)
583 stream
584 (argument-name arg)))))))))))
1f1d88f5 585
dea4d055
MW
586;; S-expression notation protocol.
587
588(defmethod print-c-type
589 (stream (type c-function-type) &optional colon atsign)
590 (declare (ignore colon atsign))
591 (format stream "~:@<~
592 FUN ~@_~:I~/sod:print-c-type/~
593 ~{ ~_~:<~S ~@_~/sod:print-c-type/~:>~}~
594 ~:>"
595 (c-type-subtype type)
596 (mapcar (lambda (arg)
1224dfb0 597 (if (eq arg :ellipsis) arg
dea4d055
MW
598 (list (argument-name arg) (argument-type arg))))
599 (c-function-arguments type))))
abdf50aa 600
93348ae9 601(export '(fun function () func fn))
1f1d88f5 602(define-c-type-syntax fun (ret &rest args)
abdf50aa
MW
603 "Return the type of functions which returns RET and has arguments ARGS.
604
1f1d88f5
MW
605 The ARGS are a list of arguments of the form (NAME TYPE). The NAME can be
606 NIL to indicate that no name was given.
607
608 If an entry isn't a list, it's assumed to be the start of a Lisp
609 expression to compute the tail of the list; similarly, if the list is
610 improper, then it's considered to be a complete expression. The upshot of
611 this apparently bizarre rule is that you can say
612
613 (c-type (fun int (\"foo\" int) . arg-tail))
614
615 where ARG-TAIL is (almost) any old Lisp expression and have it tack the
616 arguments onto the end. Of course, there don't have to be any explicit
617 arguments at all. The only restriction is that the head of the Lisp form
618 can't be a list -- so ((lambda (...) ...) ...) is out, but you probably
619 wouldn't type that anyway."
620
621 `(make-function-type ,(expand-c-type-spec ret)
622 ,(do ((args args (cdr args))
623 (list nil
624 (cons `(make-argument ,(caar args)
625 ,(expand-c-type-spec
626 (cadar args)))
627 list)))
628 ((or (atom args) (atom (car args)))
629 (cond ((and (null args) (null list)) `nil)
630 ((null args) `(list ,@(nreverse list)))
dea4d055
MW
631 ((and (consp args)
632 (eq (car args) :ellipsis))
633 `(list ,@(nreverse list) :ellipsis))
1f1d88f5
MW
634 ((null list) `,args)
635 (t `(list* ,@(nreverse list) ,args)))))))
636(c-type-alias fun function () func fn)
abdf50aa 637
dea4d055
MW
638;; Additional utilities for dealing with functions.
639
640(export 'commentify-argument-names)
641(defun commentify-argument-names (arguments)
642 "Return an argument list with the arguments commentified.
643
3109662a
MW
644 That is, with each argument name passed through
645 `commentify-argument-name'."
dea4d055 646 (mapcar (lambda (arg)
1224dfb0 647 (if (eq arg :ellipsis) arg
dea4d055
MW
648 (make-argument (commentify-argument-name (argument-name arg))
649 (argument-type arg))))
650 arguments))
651
652(export 'commentify-function-type)
653(defun commentify-function-type (type)
654 "Return a type like TYPE, but with arguments commentified.
655
656 This doesn't recurse into the return type or argument types."
657 (make-function-type (c-type-subtype type)
658 (commentify-argument-names
659 (c-function-arguments type))))
660
abdf50aa 661;;;----- That's all, folks --------------------------------------------------