Coverage report: /home/ellis/comp/core/std/macs/sugar.lisp
Kind | Covered | All | % |
expression | 6 | 275 | 2.2 |
branch | 0 | 24 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; sugar.lisp --- Syntactic Sugar Macros
3
;; Utility macros to make our code a bit more sweet.
8
(defmacro def! (name &body body)
9
"`defun' without args."
10
`(defun ,name () ,@body))
12
(defmacro eval-always (&body body)
13
"Eval BODY in all contexts (:compile-toplevel :load-toplevel :execute)."
14
`(eval-when (:compile-toplevel :load-toplevel :execute) ,@body))
16
(defun compile-and-eval (form)
17
"Compile and eval a FORM."
18
(funcall (compile nil `(lambda () ,form))))
20
(defun compile-and-eval* (form)
21
"Splice, compile, and eval a FORM."
22
(funcall (compile nil `(lambda () ,@form))))
24
(defun compile-and-load (file &key (output-file ""))
25
"Utility function which compiles a lisp FILE and loads the resulting fasl file."
26
(load (compile-file (pathname file) :output-file output-file)))
28
;; from jackdaniel's Dynamic Slots, see also META/DYNAMIC
29
(defmacro dlet (bindings &body body)
30
"LET form -> PROGV form."
31
(loop for (var val) in bindings
34
finally (return `(progv (list ,@vars) (list ,@vals)
37
(defun without-props (plist props)
38
"Return a new PLIST with all keys in PROPS dropped."
39
(loop for (options value) on plist by #'cddr
40
append (unless (member options props)
41
(list options value))))
44
(defmacro defclass* (name direct-superclasses direct-slots &rest opts)
45
"Convenience wrapper for DEFCLASS - always binds the following slot args to
46
default values unless overwritten at runtime:
50
`(defclass ,name ,direct-superclasses
53
(atom `(,x :initarg ,(sb-int:keywordicate x) :accessor ,(sb-int:symbolicate name '- x)))
60
(if-let ((acc (getf x :accessor)))
63
`(:initarg ,it :accessor ,acc ,@%args))
64
`(:initarg ,it :accessor ,(sb-int:symbolicate name '- x) ,@%args)))
67
(if-let ((acc (getf x :intargr)))
70
`(:accessor ,it :initarg ,acc ,@%args))
71
`(:accessor ,it :initarg ,%name ,@%args)))))))))
75
;; Based on INCONGRUENT-METHODS:DEFINE-CLASS
76
(defmacro define-class (name direct-superclasses direct-slots &body body)
77
"Like DEFCLASS but with the forms in BODY acting as simplified method
80
(labels ((slot-definition (x)
83
(without-props (rest x)
84
'(:reader :writer :accessor)))
86
(slot-accessor-definition (x)
87
(destructuring-bind (slot-name &rest options) x
88
(loop :for (options value) :on options :by #'cddr
92
`((defmethod ,value ((,self ,name))
93
(slot-value ,self ',slot-name))
94
(defmethod (setf ,value)
96
(setf (slot-value ,self ',slot-name) new))))
98
`((defmethod ,value ((,self ,name))
99
(slot-value ,self ',slot-name))))
101
`((defmethod (setf ,value)
103
(setf (slot-value ,self ',slot-name) new))))))))
104
(method-definition (definition)
105
(destructuring-bind (method-name lambda-list &rest body)
107
(if (listp method-name)
108
`(define-class-method ,method-name (,(first lambda-list)
109
(,(intern "SELF") ,name)
110
,@(rest lambda-list))
112
`(define-class-method ,method-name ((,(intern "SELF") ,name)
116
(defclass ,name ,direct-superclasses
117
,(mapcar #'slot-definition direct-slots))
118
,@(mapcan #'slot-accessor-definition
119
(remove-if-not #'listp direct-slots))
120
,@(mapcar #'method-definition body)))))
123
;; I don't use this much, but it is quite handy.
124
;; ref: https://fare.livejournal.com/189741.html
126
;; in this case we just pull the version from UIOP
127
(defmacro nest (&rest things)
128
"Macro to keep code nesting and indentation under control." ;; Thanks to mbaringer
129
(reduce #'(lambda (outer inner) `(,@outer ,inner))
133
(defmacro letv* (bindings &rest body)
134
"Extended LET* which handles multiple values, destructuring bind, and type declarations.
136
The declarations list VARS is similar to that in let.
139
(macroexpand-1 `(letv* ((x 2 :type fixnum)
140
((a &optional (c 2)) b (values (list 1) 3) :type (fixnum &optional (t)) t))
143
;; (DECLARE (TYPE FIXNUM X))
144
;; (MULTIPLE-VALUE-BIND (#:G1120 B) (VALUES (LIST 1) 3)
145
;; (DECLARE (TYPE T B))
146
;; (DESTRUCTURING-BIND (A &OPTIONAL (C 2)) #:G1120
147
;; (DECLARE (TYPE FIXNUM A)
150
(labels ((typedecl (syms alist)
151
(let ((decls (remove-if #'null (mapcar #'(lambda (s)
152
(let ((ts (assoc s alist)))
157
(when decls `((declare ,@decls))))))
158
(apply #'recursive-append
160
(mapcan #'(lambda (x)
161
(destructuring-bind (bind expr type) (let ((tpos (position :type x)) (len (length x)))
162
(list (subseq x 0 (1- (or tpos len))) (nth (1- (or tpos len)) x) (when tpos (nthcdr (1+ tpos) x))))
163
(let* ((typa (loop for (s ty) on (flatten (zip-tree bind type))
165
if (or skip? (null s)) do (setf skip? nil)
167
do (progn (setf skip? t)
168
(unless (member s cl:lambda-list-keywords)
169
(collect (cons s ty))))))
170
(vsyms (mapcar #'(lambda (x) (if (consp x)
173
`(destructuring-bind (,@x) ,g
174
,@(typedecl (flatten x) typa))))
179
(if (> (length bind) 1)
180
`(multiple-value-bind (,@(mapcar #'car vsyms)) ,expr)
181
`(let ((,@(mapcar #'car vsyms) ,expr))))
182
(car (typedecl (mapcar #'car vsyms) typa)))
183
(remove-if #'null (mapcar #'cadr vsyms))))))
185
`((progn ,@body))))))
187
(defmacro lety (bindings &rest body)
188
"Like let, but also allows type-declarations with the key :type.
192
`(let-typed ((x 1 :type fixnum))
195
;; (DECLARE (TYPE FIXNUM X))
197
`(let (,@(mapcar #'(lambda (x) (subseq x 0 2)) bindings))
198
,@(let ((types (remove-if #'null (mapcar #'(lambda (x) (destructuring-bind (s e &key (type t)) x
205
(when types `((declare ,@types))))
208
(defmacro lety* (bindings &rest body)
209
"Like let*, but also allows type-declarations with the key :type.
213
`(let*-typed ((x 1 :type fixnum))
216
;; (DECLARE (TYPE FIXNUM X))
218
`(let* (,@(mapcar #'(lambda (x) (subseq x 0 2)) bindings))
219
,@(let ((types (remove-if #'null
220
(mapcar #'(lambda (x) (destructuring-bind (s e &key (type t)) x
227
(when types `((declare ,@types))))