Coverage report: /home/runner/work/geb/geb/src/util/utils.lisp
Kind | Covered | All | % |
expression | 58 | 115 | 50.4 |
branch | 2 | 8 | 25.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
(in-package :geb.utils)
3
(defun subclass-responsibility (obj)
4
"Denotes that the given method is the subclasses
5
responsibility. Inspired from Smalltalk"
6
(error "Subclass Responsbility for ~A" (class-name (class-of obj))))
8
(defun symbol-to-keyword (symbol)
9
"Turns a [symbol] into a [keyword]"
10
(intern (symbol-name symbol) :keyword))
12
(defmacro muffle-package-variance (&rest package-declarations)
13
"Muffle any errors about package variance and stating exports out of order.
14
This is particularly an issue for SBCL as it will error when using MGL-PAX
15
to do the [export] instead of DEFPACKAGE.
17
This is more modular thank
18
[MGL-PAX:DEFINE-PACKAGE](https://melisgl.Githubc.io/mgl-pax-world/mgl-pax-manual.html#MGL-PAX:DEFINE-PACKAGE%20MGL-PAX:MACRO)
19
in that this can be used with any package creation function like
20
[UIOP:DEFINE-PACKAGE](https://privet-kitty.github.io/etc/uiop.html#UIOP_002fPACKAGE).
22
Here is an example usage:
25
(geb.utils:muffle-package-variance
26
(uiop:define-package #:geb.lambda.trans
27
(:mix #:trivia #:geb #:serapeum #:common-lisp)
29
:compile-checked-term :stlc-ctx-to-mu)))
31
`(eval-when (:compile-toplevel :load-toplevel :execute)
32
(locally (declare #+sbcl (sb-ext:muffle-conditions sb-int:package-at-variance))
33
(handler-bind (#+sbcl (sb-int:package-at-variance #'muffle-warning))
34
,@package-declarations))))
36
(defmacro make-pattern (object-name &rest constructor-names)
37
"make pattern matching position style instead of record style. This
38
removes the record constructor style, however it can be brought back
42
(defclass alias (<substmorph> <substobj>)
46
:documentation \"The name of the GEB object\")
49
:documentation \"The underlying geb object\"))
50
(:documentation \"an alias for a geb object\"))
52
(make-pattern alias name obj)
54
`(trivia.level2:defpattern ,object-name
55
(&optional ,@constructor-names)
57
(list 'type ',object-name)
59
`(list 'trivia.level2:access '',x ,x))
62
(defun shallow-copy-object (original)
63
(let* ((class (class-of original))
64
(copy (allocate-instance class)))
65
(dolist (slot (mapcar #'c2mop:slot-definition-name (c2mop:class-slots class)))
66
(when (slot-boundp original slot)
67
(setf (slot-value copy slot)
68
(slot-value original slot))))
73
;; https://stackoverflow.com/questions/11067899/is-there-a-generic-method-for-cloning-clos-objects
75
;; Don't need it to be an object on non standard-classes for this
76
;; project, if so, we can promote it to the old form of being a
79
(defgeneric copy-instance (object &rest initargs &key &allow-other-keys)
81
"Makes and returns a shallow copy of OBJECT.
83
An uninitialized object of the same class as OBJECT is allocated by
84
calling ALLOCATE-INSTANCE. For all slots returned by
85
CLASS-SLOTS, the returned object has the
86
same slot values and slot-unbound status as OBJECT.
88
REINITIALIZE-INSTANCE is called to update the copy with INITARGS."))
90
(defmethod copy-instance ((object standard-object) &rest initargs &key &allow-other-keys)
91
(let* ((class (class-of object))
92
(copy (allocate-instance class)))
93
(dolist (slot (c2mop:class-slots class))
94
;; moved the mapcar into a let, as allocation wise, CCL
95
;; preformed better this way.
96
(let ((slot-name (c2mop:slot-definition-name slot)))
97
(when (slot-boundp object slot-name)
98
(setf (slot-value copy slot-name)
99
(slot-value object slot-name)))))
101
(apply #'reinitialize-instance copy initargs))))
103
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
107
(-> number-to-digits (integer &optional list) list)
108
(defun number-to-digits (number &optional rem)
109
"turns an [INTEGER][type] into a list of its digits"
110
(multiple-value-bind (cont flored) (floor number 10)
111
(if (and (zerop cont) (zerop flored))
113
(number-to-digits cont (cons flored rem)))))
115
(-> digit-to-under (fixnum) string)
116
(defun digit-to-under (digit)
117
"Turns a digit into a subscript string version of the number"
119
(0 "₀") (1 "₁") (2 "₂") (3 "₃") (4 "₄")
120
(5 "₅") (6 "₆") (7 "₇") (8 "₈") (9 "₉")
123
(-> number-to-under (integer) string)
124
(defun number-to-under (index)
125
"Turns an [INTEGER][type] into a subscripted [STRING][type]"
126
(format nil "~{~A~}" (mapcar #'digit-to-under (number-to-digits index))))
128
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
129
;; Generic type constructions
130
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
(deftype list-of (ty)
133
"Allows us to state a list contains a given type.
139
This does not type check the whole list, but only the first
140
element. This is an issue with how lists are defined in the
141
language. Thus this should be be used for intent purposes.
145
For a more proper version that checks all elements please look at writing code like
148
(deftype normal-form-list ()
149
`(satisfies normal-form-list))
151
(defun normal-form-list (list)
153
(every (lambda (x) (typep x 'normal-form)) list)))
155
(deftype normal-form ()
159
Example usage of this can be used with `typep`
162
(typep '(1 . 23) '(list-of fixnum))
165
(typep '(1 23) '(list-of fixnum))
168
(typep '(1 3 4 \"hi\" 23) '(list-of fixnum))
171
(typep '(1 23 . 5) '(list-of fixnum))
175
Further this can be used in type signatures
178
(-> foo (fixnum) (list-of fixnum))
183
`(cons ,ty (or null cons)))
185
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
186
;; Generic Constructors declarations
187
;; These aren't needed but serve as a good place to put a default doc.
188
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
190
(defgeneric mcar (obj)
192
"Can be seen as calling CAR on a generic CLOS
193
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
194
(defgeneric mcdr (obj)
195
(:documentation "Similar to MCAR, however acts like a CDR for
196
[classes] that we wish to view as a SEQUENCE"))
197
(defgeneric mcadr (obj)
198
(:documentation "like MCAR but for the CADR"))
200
(defgeneric mcaddr (obj)
201
(:documentation "like MCAR but for the CADDR"))
203
(defgeneric mcadddr (obj)
204
(:documentation "like MCAR but for the CADDDR"))
206
(defgeneric obj (obj)
208
"Grabs the underlying
209
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
211
(defgeneric name (obj)
213
"the name of the given
214
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
216
(defgeneric func (obj)
219
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
221
(defgeneric predicate (obj)
223
"the PREDICATE of the
224
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
226
(defgeneric then (obj)
228
"the then branch of the
229
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
231
(defgeneric else (obj)
233
"the then branch of the
234
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
236
(defgeneric code (obj)
239
[object](http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_o.htm#object)"))
241
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
243
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
246
(defun apply-n (times f initial)
247
"Applies a function, f, n TIMES to the INITIAL values
250
GEB> (apply-n 10 #'1+ 0)
251
10 (4 bits, #xA, #o12, #b1010)
253
(let ((value initial))
254
(dotimes (n times value)
255
(setf value (funcall f value)))))