source: trunk/abcl/contrib/named-readtables/src/define-api.lisp

Last change on this file was 15019, checked in by Mark Evenson, 7 years ago

abcl-contrib: add NAMED-READTABLES

From <https://github.com/melisgl/named-readtables>.

c.f. <https://github.com/melisgl/named-readtables/issues/10>

File size: 2.8 KB
Line 
1(in-package :named-readtables)
2
3(defmacro define-api (name lambda-list type-list &body body)
4  (flet ((parse-type-list (type-list)
5           (let ((pos (position '=> type-list)))
6             (assert pos () "You forgot to specify return type (`=>' missing.)")
7             (values (subseq type-list 0 pos)
8                     `(values ,@(nthcdr (1+ pos) type-list) &optional)))))
9    (multiple-value-bind (body decls docstring)
10        (parse-body body :documentation t :whole `(define-api ,name))
11      (multiple-value-bind (arg-typespec value-typespec)
12          (parse-type-list type-list)
13        (multiple-value-bind (reqs opts rest keys)
14            (parse-ordinary-lambda-list lambda-list)
15          (declare (ignorable reqs opts rest keys))
16          `(progn
17             (declaim (ftype (function ,arg-typespec ,value-typespec) ,name))
18             (locally
19                 ;;; Muffle the annoying "&OPTIONAL and &KEY found in
20                 ;;; the same lambda list" style-warning
21                 #+sbcl (declare (sb-ext:muffle-conditions style-warning))
22               (defun ,name ,lambda-list
23                 ,docstring
24
25                 #+sbcl (declare (sb-ext:unmuffle-conditions style-warning))
26
27                 ,@decls
28
29                 ;; SBCL will interpret the ftype declaration as
30                 ;; assertion and will insert type checks for us.
31                 #-sbcl
32                 (progn
33                   ;; CHECK-TYPE required parameters
34                   ,@(loop for req-arg in reqs
35                           for req-type = (pop type-list)
36                           do (assert req-type)
37                           collect `(check-type ,req-arg ,req-type))
38
39                   ;; CHECK-TYPE optional parameters
40                   ,@(loop initially (assert (or (null opts)
41                                                 (eq (pop type-list) '&optional)))
42                           for (opt-arg . nil) in opts
43                           for opt-type = (pop type-list)
44                           do (assert opt-type)
45                           collect `(check-type ,opt-arg ,opt-type))
46
47                   ;; CHECK-TYPE rest parameter
48                   ,@(when rest
49                       (assert (eq (pop type-list) '&rest))
50                       (let ((rest-type (pop type-list)))
51                         (assert rest-type)
52                         `((dolist (x ,rest)
53                             (check-type x ,rest-type)))))
54
55                   ;; CHECK-TYPE key parameters
56                   ,@(loop initially (assert (or (null keys)
57                                                 (eq (pop type-list) '&key)))
58                           for ((keyword key-arg)  . nil) in keys
59                           for (nil key-type) = (find keyword type-list :key #'car)
60                           collect `(check-type ,key-arg ,key-type)))
61
62                 ,@body))))))))
Note: See TracBrowser for help on using the repository browser.