3 (in-package :cl-tuples
)
5 ;; package used to hold tuple type info
6 (defpackage :tuple-types
)
8 ;; make #{ .. } notation become a short hand for (values ...)
9 (defun |
#{-reader|
(stream char arg
)
10 (declare (ignore char arg
))
11 `(values ,@(read-delimited-list #\
} stream t
)))
13 (set-dispatch-macro-character #\
# #\
{ #'|
#{-reader|
)
14 (set-macro-character #\
} (get-macro-character #\
) nil
))
16 (defmacro with-gensyms
((&rest names
) &body body
)
17 "Classic macro for creating named unique symbols."
18 `(let ,(loop for n in names collect
`(,n
(gensym)))
21 (defmacro once-only
((&rest names
) &body body
)
22 "Evaluate arguments once only in macro form body"
23 (let ((gensyms (loop for n in names collect
(gensym))))
24 `(let (,@(loop for g in gensyms collect
`(,g
(gensym))))
25 `(let (,,@(loop for g in gensyms for n in names collect
``(,,g
,,n
)))
26 ,(let (,@(loop for n in names for g in gensyms collect
`(,n
,g
)))
29 ;; define helper functions we will use
31 (defun gensym-list (n)
32 "Give us a list of gensyms n elements long"
34 for index from
0 below n
38 (defun symbol-to-string (x)
39 "If the argument is a symbol or string, return it as a string."
40 (check-type x
(or symbol string
))
48 (defun make-adorned-symbol (name &key prefix suffix asterisk package
)
49 (check-type name symbol
)
50 (check-type prefix
(or symbol string null
))
51 (check-type suffix
(or symbol string null
))
52 (intern (concatenate 'string
63 (if package package
*package
*)))
65 (defun make-suffixed-symbol (name suffix
)
66 (make-adorned-symbol name
:suffix suffix
))
68 (defun make-prefixed-symbol (name prefix
)
69 (make-adorned-symbol name
:prefix prefix
))
71 (defun make-element-names (elements type-name
)
72 "Given a list of element names form a set of symbols of the form
73 <type-name>-<element-name> as used in struct elements."
74 (check-type elements symbol
)
75 (check-type type-name symbol
)
79 (symbol-name type-name
) "-struct-"
84 (defun make-tuple-symbol (type-name tuple-element-type elements
)
85 "Makes a symbol used to identify a typle type. Information about the tuple type
86 is stored in the property list of the symbol."
87 (assert (listp elements
))
89 ((type-name-sym (intern (string type-name
) :tuple-types
)))
92 ;; store-value the elements
93 (setf (get type-name-sym
'elements
) elements
)
94 ;; store the # of elements ( a bit redundant )
95 (setf (get type-name-sym
'tuple-length
) (length elements
))
96 ;; store-value the type of the elements
97 (setf (get type-name-sym
'element-type
) tuple-element-type
)
98 ;; store-value a flag us to make sure it's a tuple-type symbol
99 (setf (get type-name-sym
'is-tuple
) t
))))
102 (defun tuple-typep (type-name)
103 "Test to see if this symbol represents a tuple type"
104 (get (find-symbol (string-upcase (string type-name
)) :tuple-types
) 'is-tuple
))
106 (defun tuple-size (type-name)
107 "Return the size of the type"
108 (get (find-symbol (string-upcase (string type-name
)) :tuple-types
) 'tuple-length
))
111 (defun tuple-element-type (type-name)
112 "Return the size of the type"
113 (get (find-symbol (string-upcase (string type-name
)) :tuple-types
) 'element-type
))
115 (defun tuple-elements (type-name)
116 "Return the size of the type"
117 (get (find-symbol (string-upcase (string type-name
)) :tuple-types
) 'elements
))
119 (defun tuple-typespec (type-name)
120 "Return typespec of tuple."
122 for i from
0 to
(tuple-size type-name
)
123 collect
(tuple-element-type type-name
))))
125 (defun symbol-macro-expander-fn (n names types elements gensyms body
)
126 "Wrap the body of def tuple op in symbol macros mapped to gensyms to prevent
131 for gensym in
(nth n gensyms
)
132 for element in
(nth n elements
) collect
`(,element
,gensym
))
133 (declare (ignorable ,@',(nth n gensyms
)))
134 (symbol-macrolet ((,',(nth n names
) (,',(make-adorned-symbol (nth n types
) :suffix
"TUPLE")
136 for gensym in
(nth n gensyms
)
138 ,,(if (< (1+ n
) (length names
))
139 (symbol-macro-expander-fn (1+ n
) names types elements gensyms body
)
140 ``(progn ,@',body
))))
141 (if (< (1+ n
) (length names
))
142 (symbol-macro-expander-fn (1+ n
) names types elements gensyms body
)
143 ``(progn ,@',body
))))
146 (defun arg-expander-fn-aux (n names types elements gensyms body
)
148 ``(,',(make-adorned-symbol (nth n types
) :prefix
"WITH")
149 ,,(nth n names
) ,',(nth n gensyms
)
150 ,,(if (< (1+ n
) (length names
))
151 (arg-expander-fn-aux (1+ n
) names types elements gensyms body
)
152 (symbol-macro-expander-fn 0 names types elements gensyms body
)))
153 ``(symbol-macrolet ((,',(nth n names
) ,,(nth n names
)))
154 ,,(if (< (1+ n
) (length names
))
155 (arg-expander-fn-aux (1+ n
) names types elements gensyms body
)
156 (symbol-macro-expander-fn 0 names types elements gensyms body
)))))
159 (defun body-expander-fn (names types elements gensyms body
)
160 (if (eq (caar body
) :return
)
161 (let ((ret-type (if (tuple-typep (cadar body
))
164 (real-body (cddar body
)))
166 ,(arg-expander-fn-aux 0 names types elements gensyms real-body
)))
167 (arg-expander-fn-aux 0 names types elements gensyms body
)))
169 (defun arg-expander-fn (names types elements forms
)
170 "Helper function for def-tuple-op. Expands the arguments into a series of WITH-* forms so that
171 symbols are bound to tuple elements in the body of the operator."
172 (assert (= (length names
) (length types
) (length elements
)) ()
173 "Malformed def-tuple-op argument list.")
174 (let ((body (if (stringp (first forms
)) (rest forms
) forms
)))
177 (mapcar #'(lambda (element-list)
178 (gensym-list (length element-list
))) elements
)))
179 (body-expander-fn names types elements gensyms body
)))))
182 ;; (arg-expander-fn '(v q) '(vector3d quaternion) '((x y z) (qx qy qz qw)) '("Return the vector + real" (:return (values single-float single-float single-float single-float) (vertex3d-tuple x y z qw))))
183 ;; (arg-expander-fn '(v q) '(vector3d quaternion) '((x y z) (qx qy qz qw)) '("Return the vector + real" ((:return (values single-float single-float single-float single-float)) (vertex3d-tuple x y z qw))))