3 (declaim (optimize (speed 3) (debug 0) (safety 1)))
4 ;; (declaim (optimize (speed 1) (safety 3) (debug 3)))
7 (:use
:common-lisp
:uffi
:rclg-load
)
9 (:export
:start-r
:rclg
:r
:sexp
:*backconvert
* :*r-started
*
10 :r-convert
:r-do-not-convert
:convert-to-r
11 :sexp-not-needed
:update-r
:def-r-call
:*r-NA
* :r-na
))
15 (eval-when (:load-toplevel
)
17 (error "rclg-load has not loaded the R libraries.")))
19 (eval-when (:compile-toplevel
:load-toplevel
)
20 (defvar *r-default-argv
* '("rclg" "-q" "--vanilla"))
21 (defvar *r-NA-internal
* -
2147483648) ;; PLATFORM SPECIFIC HACK!!!
25 (defvar +float-seq
+ 2)
26 (defvar +complex-seq
+ 3)
27 (defvar +string-seq
+ 4)
30 (defvar +seq-fsm
+ #2A
((0 0 0 0 0)
38 (defparameter *r-started
* nil
)
42 (eval-when (:compile-toplevel
:load-toplevel
)
43 (defmacro def-typed-struct
(struct-name type
&rest field-names
)
44 `(def-struct ,struct-name
45 ,@(mapcar (lambda (n) `(,n
,type
)) field-names
)))
47 (defmacro def-voidptr-struct
(struct-name &rest field-names
)
48 "Define a structure in which all elements are of type pointer-to-void."
49 `(def-typed-struct ,struct-name
:pointer-void
,@field-names
))
51 (defmacro def-r-var
(r-name cl-name
)
52 `(def-foreign-var (,r-name
,cl-name
) sexp
"R")))
54 (def-foreign-type foreign-string
'(* :unsigned-char
))
56 ;;; This struct is bitfields.
57 (def-struct sxpinfo-struct
(data :unsigned-int
))
59 ;; The structures in the union in the SEXPREC
60 (def-struct primsxp-struct
(offset :int
))
61 (def-voidptr-struct symsxp-struct pname value internal
)
62 (def-voidptr-struct listsxp-struct carval cdrval tagval
)
63 (def-voidptr-struct envsxp-struct frame enclos hashtab
)
64 (def-voidptr-struct closxp-struct formals body env
)
65 (def-voidptr-struct promsxp-struct value expr env
)
67 (def-union sexprec-internal-union
68 (primsxp primsxp-struct
)
69 (symsxp symsxp-struct
)
70 (listsxp listsxp-struct
)
71 (envsxp envsxp-struct
)
72 (closxp closxp-struct
)
73 (promsxp promsxp-struct
))
76 (sxpinfo sxpinfo-struct
)
77 (attrib :pointer-self
)
78 (gengcg-next-node :pointer-self
)
79 (gengcg-prev-node :pointer-self
)
80 (u sexprec-internal-union
))
82 (def-foreign-type sexp
(* sexprec
))
84 ;;; A holder class for a sexp
85 (defclass sexp-holder
()
86 ((sexp :initarg
:sexp
)
87 (protected :initarg
:protected
:initform nil
)))
89 (defmethod print-object ((s sexp-holder
) stream
)
90 (format stream
"#<sexp at 0x~16R, ~A>"
91 (pointer-address (slot-value s
'sexp
))
92 (if (slot-value s
'protected
) 'protected
'unprotected
)))
94 ;;; Current best guesses
96 ;; (defmacro uffi::get-slot-value (obj type slot)
97 ;; (let ((obj-sym (gensym)))
98 ;; `(let ((,obj-sym ,obj))
99 ;; (declare (type (sb-alien:alien ,(cadr type)) ,obj-sym))
100 ;; (sb-alien:slot ,obj-sym ,slot))))
102 ;; (defmacro uffi::get-slot-value (obj type slot)
103 ;; `(sb-alien:slot (the (sb-alien:alien (* ,(cadr type))) ,obj)
106 ;; (defmacro uffi::get-slot-value (obj type slot)
107 ;; `(sb-alien:slot (the (sb-alien:alien ,(cadr type)) ,obj)
110 (defmacro uffi
::get-direct-value
(obj type slot
)
111 `(sb-alien:slot
(the (sb-alien:alien
,(cadr type
)) ,obj
) ,slot
))
113 (defun sexptype (robj)
114 "Gets the sexptype of an robj. WARNING: ASSUMES THAT THE TYPE
115 IS STORED IN THE LOW ORDER 5 BITS OF THE SXPINFO-STRUCT, AND THAT
116 IT CAN BE EXTRACTED VIA A 'mod 32' OPERATION! MAY NOT BE PORTABLE."
117 (let ((info (uffi::get-direct-value
118 (get-slot-value robj
'sexprec
'sxpinfo
)
119 'sxpinfo-struct
'data
)))
122 ;; We probably only need a few of these, but as soon as I needed two, I
123 ;; decided to go ahead and type them all in.
124 (def-enum sexptype
(:nilsxp
:symsxp
:listsxp
:closxp
:envsxp
:promsxp
:langsxp
125 :specialsxp
:builtinsxp
:charsxp
126 :lglsxp
(:intsxp
13) :realsxp
:cplxsxp
:strsxp
127 :dotsxp
:anysxp
:vecsxp
:exprsxp
:bcodesxp
128 :extptrsxp
:weakrefsxp
(:funsxp
99)))
131 (defmacro r-get-u
(sexp)
132 `(get-slot-value ,sexp
'sexprec
'u
))
134 (defmacro r-get-listsxp
(sexp)
135 `(uffi::get-direct-value
(r-get-u ,sexp
)
136 'sexprec-internal-union
140 (get-slot-value (r-get-listsxp sexp
) 'listsxp-struct
'carval
))
145 (pprint (type-of sexp
))
146 (format t
"~%--2--~%")
147 (pprint (type-of (r-get-listsxp sexp
)))
148 (format t
"~%--3--~%")
149 (pprint (get-slot-value (r-get-listsxp sexp
) 'listsxp-struct
'carval
))
150 (format t
"~%--4--~%")
153 (defun r-setcar (sexp value
)
154 (setf (get-slot-value (r-get-listsxp sexp
) 'listsxp-struct
'carval
)
157 ;; (defun r-setcar (sexp value)
158 ;; (uffi::set-slot-value (r-get-listsxp sexp) listsxp-struct 'carval value))
161 (get-slot-value (r-get-listsxp sexp
) 'listsxp-struct
'cdrval
))
164 (def-function ("SET_TAG" %set-tag
)
169 (def-function ("Rf_length" %rf-length
)
173 (def-function ("SET_VECTOR_ELT" %set-vector-elt
)
179 (def-function ("Rf_elt" %rf-elt
)
184 (def-function ("VECTOR_ELT" %vector-elt
)
189 (def-function ("Rf_coerceVector" %rf-coerce-vector
)
194 ;;; Allocation and Protection
196 (def-function ("Rf_allocVector" %rf-alloc-vector
)
201 ;; def-function doesn't take a docstring! "'Protects' the item
202 ;; (presumably by telling the garbage collector it's in use, although
203 ;; I haven't looked at the internals. Returns the same pointer you
205 (def-function ("Rf_protect" %rf-protect
)
209 (def-function ("Rf_unprotect" %rf-unprotect
)
213 (def-function ("Rf_unprotect_ptr" %rf-unprotect-ptr
)
217 (defun sexp-not-needed (poss-sexp)
218 (when (and (typep poss-sexp
'sexp-holder
)
219 (slot-value poss-sexp
'protected
))
220 (%rf-unprotect-ptr
(slot-value poss-sexp
'sexp
))
221 (setf (slot-value poss-sexp
'protected
) nil
))
227 (def-r-var "R_GlobalEnv" *r-global-env
*)
228 (def-r-var "R_UnboundValue" *r-unbound-value
*)
229 (def-r-var "R_NilValue" *r-nil-value
*)
231 ;;; Foreign string handling.
233 (defun stringseq-to-foreign-string-array (stringseq)
234 (let ((n (length stringseq
)))
235 (let ((res (uffi:allocate-foreign-object
'foreign-string n
)))
237 (setf (deref-array res
'(:array foreign-string
) i
)
238 (convert-to-foreign-string (elt stringseq i
))))
241 (defmacro with-foreign-string-array
((name length str-array
) &body body
)
242 (let ((ctr (gensym)))
243 `(multiple-value-bind (,name
,length
) (stringseq-to-foreign-string-array ,str-array
)
247 (dotimes (,ctr
,length
)
248 (free-foreign-object (deref-array ,name
'(:array foreign-string
) ,ctr
)))
249 (free-foreign-object ,name
))))))
253 (def-function ("Rf_initEmbeddedR" %rf-init-embedded-r
)
255 (argv (* foreign-string
)))
258 (defun start-r (&optional
(argv *r-default-argv
*))
261 (with-foreign-string-array (foreign-argv n argv
)
262 (%rf-init-embedded-r n foreign-argv
)))))
266 (def-function ("Rf_findVar" %rf-find-var
)
271 (def-function ("Rf_install" %rf-install
)
272 ((ident foreign-string
))
275 (def-function ("R_tryEval" %r-try-eval
)
278 (error-occurred (* :int
)))
282 (with-foreign-object (e :int
)
283 (setf (deref-pointer e
:int
) 0)
284 (let ((res (%r-try-eval expr
*r-global-env
* e
)))
285 (if (not (= (deref-pointer e
:int
) 0))
286 (error "Bad expr: ~A" (get-r-error))
289 (defun r-bound (robj)
290 "Checks to see if an R SEXP is (has the address of) the *r-unbound-value* SEXP."
291 (not (= (pointer-address robj
)
292 (pointer-address *r-unbound-value
*))))
295 "Checks to see if an R SEXP is (has the address of) the *r-nil-value* SEXP."
296 (= (pointer-address robj
)
297 (pointer-address *r-nil-value
*)))
299 (defun get-from-name-test (name)
300 (declare (type simple-string name
))
301 (CONVERT-TO-FOREIGN-STRING NAME
))
304 ;; (installed (%rf-install ident-foreign)))
312 ;; (LET ((FOREIGN-VALUE
313 ;; (%RF-FIND-VAR (%RF-INSTALL IDENT-FOREIGN) *R-GLOBAL-ENV*)))
316 ;; (IF (R-BOUND FOREIGN-VALUE) FOREIGN-VALUE NIL)))))
318 ;; (DECLARE (DYNAMIC-EXTENT IDENT-FOREIGN))
319 ;; (FREE-FOREIGN-OBJECT IDENT-FOREIGN)
322 (defun get-from-name (name)
323 "If R has a mapping for name (name is a string), returns the SEXP that points to it,
324 otherwise returns NIL."
325 (with-foreign-string (ident-foreign name
)
327 (%rf-find-var
(%rf-install ident-foreign
) *r-global-env
*)))
328 (if (r-bound foreign-value
)
332 (def-function ("Rf_getAttrib" %rf-get-attrib
)
337 (def-function ("Rf_setAttrib" %rf-set-attrib
)
343 (def-r-var "R_NamesSymbol" *r-names-symbol
*)
344 (def-r-var "R_DimSymbol" *r-dims-symbol
*)
346 ;;; Basic conversions
348 (def-function ("LOGICAL" %LOGICAL
)
352 (def-function ("INTEGER" %INT
)
356 (def-function ("REAL" %REAL
)
358 :returning
(* :double
))
361 ;; (SB-ALIEN:WITH-ALIEN ((%REAL (FUNCTION (* C-CALL:DOUBLE) SEXP) :EXTERN "REAL"))
362 ;; (VALUES (SB-ALIEN:ALIEN-FUNCALL %REAL E))))
366 (def-struct r-complex
370 (def-function ("COMPLEX" %COMPLEX
)
372 :returning
(* 'r-complex
))
375 (def-function ("Rf_mkChar" %rf-mkchar
)
379 (def-function ("SET_STRING_ELT" %set-string-elt
)
385 (def-function ("STRING_ELT" %string-elt
)
390 (def-function ("R_CHAR" %r-char
)
392 :returning foreign-string
)
394 ;;; Basic Conversion Routines
396 (defun robj-to-int (robj &optional
(i 0))
397 "Returns the integer inside an R object. Assumes it's an
398 integral robj. Converts NA's"
399 (let ((result (deref-array (%INT robj
) :int i
)))
400 (if (= result
*r-NA-internal
*)
404 (defun robj-to-logical (robj &optional
(i 0))
405 "Returns the logical inside an R object. Assumes it's an
407 (= 1 (robj-to-int robj i
)))
409 (defun robj-to-double (robj &optional
(i 0))
410 "Returns the double-float inside an R object. Assumes it's an
412 (declare (type fixnum i
))
413 (deref-array (%real robj
) :double i
))
416 (defun robj-to-complex (robj &optional
(i 0))
417 "Returns the complex number inside an R object. Assumes it's a
419 (let ((complex (deref-array (%COMPLEX robj
) 'r-complex i
)))
420 (complex (uffi::get-direct-value complex
'r-complex
'r
)
421 (uffi::get-direct-value complex
'r-complex
'i
))))
423 (defun robj-to-string (robj &optional
(i 0))
424 "Convert an R object to a string. Assumes it's a string robj."
425 (convert-from-foreign-string (%r-char
(%string-elt robj i
))))
429 (def-function ("doubleFloatVecToR" %double-float-vec-to-R
)
435 (def-function ("intVecToR" %integer-vec-to-R
)
444 ;;; Sequence and (eventually) Dictionary Conversions
447 (defun type-to-int (obj)
448 (cond ((eql obj
*r-na
*) +int-seq
+)
452 (complex +complex-seq
+)
453 (string +string-seq
+)
456 (defun sequence-to-robj (seq)
457 (let ((len (length seq
)))
458 (let ((robj (%rf-protect
(%rf-alloc-vector sexptype
#vecsxp len
)))
459 (state (type-to-int (elt seq
0)))
462 ((simple-array double-float
)
463 (%double-float-vec-to-R
(sb-sys:vector-sap seq
) len robj
))
467 ;; (%set-vector-elt robj i (double-float-to-robj e))
471 ((simple-array fixnum
)
472 (%integer-vec-to-R
(sb-sys:vector-sap seq
) len robj
4))
476 (%set-vector-elt robj i
(convert-to-r e
))
477 (setf state
(aref +seq-fsm
+ state
(type-to-int e
))
482 (#.
+int-seq
+ (%rf-coerce-vector robj sexptype
#intsxp
))
483 (#.
+float-seq
+ (%rf-coerce-vector robj sexptype
#realsxp
))
484 (#.
+complex-seq
+ (%rf-coerce-vector robj sexptype
#cplxsxp
))
485 (#.
+string-seq
+ (%rf-coerce-vector robj sexptype
#strsxp
))
488 (values result state
)))))
491 (defgeneric convert-to-r
(value)
492 (:method
((n null
)) *r-nil-value
*)
493 (:method
((i integer
)) (int-to-robj i
))
494 (:method
((f float
)) (float-to-robj f
))
495 (:method
((d double-float
)) (double-float-to-robj d
))
496 (:method
((c complex
)) (complex-to-robj c
))
497 (:method
((s string
)) (string-to-robj s
))
498 (:method
((s sequence
)) (sequence-to-robj s
))
499 (:method
((s sexp-holder
)) (slot-value s
'sexp
))
500 (:method
((v vector
)) (sequence-to-robj v
))
501 (:method
((a array
)) (array-to-robj a
))
502 (:method
((k symbol
)) k
)) ;; for keywords or for T
504 (defmethod convert-to-r ((na (eql *r-NA
*)))
505 (convert-to-r *r-NA-internal
*))
508 (defmethod convert-to-r ((l (eql t
)))
509 "Returns an R object corresponding to the logical t."
510 (let ((robj (%rf-alloc-vector sexptype
#lglsxp
1)))
511 (setf (deref-pointer (%LOGICAL robj
) :int
)
516 (defun int-to-robj (n)
517 "Returns an R object corresponding to an integer."
518 (let ((robj (%rf-alloc-vector sexptype
#intsxp
1)))
519 (setf (deref-pointer (%INT robj
) :int
) n
)
523 (defun float-to-robj (f)
524 "Returns an R object corresponding to a floating point number. Coerces
525 the number to double-float."
526 (double-float-to-robj (coerce f
'double-float
)))
529 (defun double-float-to-robj (d)
530 "Returns an R object corresponding to a floating point number. Coerces
531 the number to double-float."
532 (let ((robj (%rf-alloc-vector sexptype
#realsxp
1)))
533 (setf (deref-pointer (%real robj
) :double
) d
)
536 (defun complex-to-robj (c)
537 "Returns an R object corresponding to a CL complex number. Coerces the
538 real and imaginary points to double-float."
539 (let ((robj (%rf-alloc-vector sexptype
#cplxsxp
1)))
540 (let ((complex (deref-pointer (%COMPLEX robj
) 'r-complex
)))
541 ;; (setf (get-slot-value complex 'r-complex 'r) (coerce (realpart c) 'double-float)
542 ;; (get-slot-value complex 'r-complex) 'i) (coerce (imagpart c) 'double-float)))
543 (setf (sb-alien:slot complex
'r
) (coerce (realpart c
) 'double-float
)
544 (sb-alien:slot complex
'i
) (coerce (imagpart c
) 'double-float
)))
547 (defun string-to-robj (string)
548 "Convert a string to an R object."
549 (let ((robj (%rf-alloc-vector sexptype
#strsxp
1))
551 (with-foreign-string (s string
)
553 (%set-string-elt robj
0 str-sexp
)
556 (defun array-to-robj (a)
557 "Convert an array to an R object."
559 (convert-to-r (array-to-vec-column-major a
))))
560 (%rf-set-attrib column-vector
562 (convert-to-r (array-dimensions a
)))
565 (defun convert-from-r (robj)
566 "Attempt to convert a general R value to a CL value."
569 (let ((length (%rf-length robj
)))
572 (let ((result (convert-from-r-seq robj length
)))
577 (defun sexptype-to-element-type (type)
579 (#.sexptype
#intsxp
'integer
) ;;; Sigh, not fixnum.
580 (#.sexptype
#lglsxp
'boolean
)
581 (#.sexptype
#realsxp
'double-float
)
582 (#.sexptype
#cplxsxp
'complex
)
583 (#.sexptype
#strsxp
'string
)
584 (#.sexptype
#listsxp
't
)
585 (#.sexptype
#vecsxp
't
)
586 (t (error "Unknown type"))))
588 (defun convert-from-r-seq (robj length
)
589 "Convert an r-sequence into CL."
590 (let* ((type (sexptype robj
))
591 (result (make-array length
:element-type
(sexptype-to-element-type type
))))
593 (setf (aref result i
)
595 (#.sexptype
#intsxp
(robj-to-int robj i
))
596 (#.sexptype
#lglsxp
(robj-to-logical robj i
))
597 (#.sexptype
#realsxp
(robj-to-double robj i
))
598 (#.sexptype
#cplxsxp
(robj-to-complex robj i
))
599 (#.sexptype
#strsxp
(robj-to-string robj i
))
600 (#.sexptype
#listsxp
(convert-from-r (%rf-elt robj i
)))
601 (#.sexptype
#vecsxp
(convert-from-r (%vector-elt robj i
)))
602 (t (error "Unknown type")))))
603 (values result type
)))
605 (defmacro get-name
(symbol-or-string)
606 (if (stringp symbol-or-string
)
608 (string-downcase (symbol-name symbol-or-string
))))
610 (eval-when (:compile-toplevel
:load-toplevel
)
611 (defparameter *backconvert
* t
)
616 (map 'list
#'identity seq
))
618 (defun to-vector (seq)
619 (map 'vector
#'identity seq
))
622 (defmacro r-convert
(&body body
)
623 (let ((*backconvert
* t
)) ;; Compile time
624 `(let ((*backconvert
* t
)) ;; Run time
627 (defmacro r-do-not-convert
(&body body
)
628 (let ((*backconvert
* nil
)) ;; Compile time
629 `(let ((*backconvert
* nil
)) ;; Run time
632 (defmacro with-r-args
((name &rest arglist
) &body body
)
633 `(let ((,name
(get-r-args ,@arglist
)))
635 (multiple-value-prog1 ,@body
)
636 (unprotect-args ,name
))))
638 (defmacro with-gensyms
(syms &body body
)
639 `(let (,@(mapcar (lambda (sy)
640 `(,sy
(gensym ,(symbol-name sy
))))
644 (defmacro r
(name &rest args
)
645 "The primary user interface to rclg. Converts all the arguments into
646 R objects. Does not backconvert nested calls to R, so a call like
647 r sum (r seq 1 10)) should DTRT."
648 (with-gensyms (r-args evaled result names dims
)
649 `(with-r-args (,r-args
,@args
)
650 (let ((,evaled
(%rf-protect
(r-call (get-name ,name
) ,r-args
))))
653 `(let ((,result
(convert-from-r ,evaled
))
654 (,names
(r-names ,evaled
))
655 (,dims
(r-dims ,evaled
)))
656 (%rf-unprotect
1) ;; evaled
657 (values (if ,dims
(reshape-array ,result
,dims
) ,result
)
659 `(make-instance 'sexp-holder
:sexp
,evaled
:protected t
))))))
662 (defmacro get-r-args
(&rest args
)
664 (list ,@(mapcar (lambda (a)
667 `(%rf-protect
(convert-to-r ,a
))))
670 (defun unprotect-args (args)
671 (map nil
(lambda (a) (unless (keywordp a
) (%rf-unprotect-ptr a
))) args
))
673 (defun r-call (name args
)
674 "Does the actual call to R. The args must be a list of raw
675 R objetcs. Returns an unprotected, unconverted R object."
676 (let ((func (get-from-name name
)))
678 (error "Cannot find function ~A" name
)
679 (let ((func (%rf-protect func
))
681 (%rf-alloc-vector sexptype
#langsxp
(sexp-length args
)))))
683 (%rf-unprotect
1) ;; func
684 (parse-args (r-cdr exp
) args
)
687 (defun get-r-error ()
691 (defun parse-args (exp args
)
692 (do ((arglist args
(cdr arglist
)))
694 (let ((cur (car arglist
)))
697 (parse-keyword exp cur
(cadr arglist
))
698 (setf arglist
(cdr arglist
)))
699 (parse-regular-arg exp cur
))
700 (with-cast-pointer (r-cur exp
'sexprec
)
701 (setf exp
(r-cdr r-cur
))))))
703 (defun parse-keyword (exp kwd arg
)
704 (with-cast-pointer (p exp
'sexprec
)
706 (with-foreign-string (f (string-downcase (symbol-name kwd
)))
707 (%set-tag p
(%rf-install f
)))))
709 (defun parse-regular-arg (exp arg
)
710 (with-cast-pointer (p exp
'sexprec
)
713 (defmacro over-column-major-indices
((array cmi rmi
) &body body
)
714 (with-gensyms (n index dims update-index dim d index-param
)
715 `(let* ((,n
(array-total-size ,array
))
716 (,dims
(to-vector (array-dimensions ,array
)))
717 (,d
(array-rank ,array
))
718 (,index
(to-list (make-array ,d
:initial-element
0))))
719 (labels ((,update-index
(,index-param
,dim
)
720 (incf (car ,index-param
))
721 (when (= (car ,index-param
) (aref ,dims
,dim
))
722 (setf (car ,index-param
) 0)
723 (when (< ,dim
(- ,d
1))
724 (,update-index
(cdr ,index-param
) (+ ,dim
1))))))
726 (let ((,cmi
(apply #'array-row-major-index
,array
,index
)))
728 (,update-index
,index
0)))))))
730 (defun reshape-array (old-array dims
)
731 (let ((result (make-array (to-list dims
) :element-type
(array-element-type old-array
))))
732 (over-column-major-indices (result cmi rmi
)
733 (setf (row-major-aref result cmi
) (aref old-array rmi
)))
736 (defun array-to-vec-column-major (array)
737 (let ((result (make-array (array-total-size array
) :element-type
(array-element-type array
))))
738 (over-column-major-indices (array cmi rmi
)
739 (setf (aref result rmi
) (row-major-aref array cmi
)))
742 (defun sexp-length (args)
743 (+ 1 (length args
) (- (count-keywords args
))))
745 (defun count-keywords (args)
746 (count-if #'keywordp args
))
748 (defun r-names (robj)
749 (let ((names (%rf-get-attrib robj
*r-names-symbol
*)))
752 (convert-from-r names
))))
755 (let ((dims (%rf-get-attrib robj
*r-dims-symbol
*)))
758 (convert-from-r dims
))))
763 (def-foreign-type input-handler-ptr
(* :void
))
764 (def-foreign-type fd-mask
(* :void
))
766 (def-foreign-var ("R_InputHandlers" *r-input-handlers
*) input-handler-ptr
"R")
769 (def-function ("R_checkActivity" %r-check-activity
)
774 (def-function ("R_runHandlers" %r-run-handlers
)
775 ((i input-handler-ptr
)
779 ;;; Primarily for updating graphics
781 (%r-run-handlers
*r-input-handlers
*
782 (%r-check-activity
10000 0)))
785 (defun remove-plist (plist &rest keys
)
786 "Remove the keys from the plist.
787 Useful for re-using the &REST arg after removing some options."
789 ((null (setq rest
(nth-value 2 (get-properties plist keys
))))
790 (nreconc copy plist
))
791 (do () ((eq plist rest
))
792 (push (pop plist
) copy
)
793 (push (pop plist
) copy
))
794 (setq plist
(cddr plist
))))
796 (defun to-keyword (symbol)
797 (intern (symbol-name symbol
) :keyword
))
799 (defun atom-or-first (val)
804 (defmacro def-r-call
((macro-name r-name conversion
&rest required-args
)
806 (let* ((rest-sym (gensym "rest"))
807 (result-sym (gensym "result"))
808 (keyword-names (mapcar #'atom-or-first keyword-args
))
809 (keywords (mapcar #'to-keyword keyword-names
)))
810 `(defmacro ,macro-name
(,@required-args
814 `(let ((,',result-sym
818 ,,@(mapcan #'(lambda (k n
) (list k n
))
821 ,@(remove-plist ,rest-sym
,@keywords
)))))
822 (declare (ignorable ,',result-sym
))
824 (:convert
`(r-convert ,result-sym
))
827 (t (error "Unknown value of conversion: ~A" conversion
)))))))
829 ;; This is necessary because CMU's traps modes cause error upon
832 (eval-when (:load-toplevel
)
833 (sb-int:set-floating-point-modes
:traps
(list :overflow
)))
835 ;; (eval-when (:load-toplevel)
836 ;; (let ((current-traps (cadr (member :traps (sb-int:get-floating-point-modes)))))
837 ;; (when (find :invalid current-traps)
839 ;; (warn "WARNING: removing :invalid from floating-point-modes traps.")
840 ;; (sb-int:set-floating-point-modes :traps
841 ;; (remove :invalid current-traps))))))
844 (eval-when (:load-toplevel
)
848 (eval-when (:load-toplevel
)
849 (mp:make-process
(lambda () (do () (nil) (progn (update-r) (sleep 0.1))))))
851 (defmacro uffi
::get-slot-value
(obj type slot
)
852 `(sb-alien:slot
,obj
,slot
))