;;;; coops-extras.scm ;;;; Kon Lovett, Jul '18 ;;;; Kon Lovett, Jun '17 ;;;; Kon Lovett, Aug '10 (declare (bound-to-procedure ##sys#peek-unsigned-integer ##sys#check-closure ) ) (module coops-extras (;export slot@ make-copy describe-object describe-object-slot ; print-closure) (import scheme (chicken base) (chicken fixnum) (chicken type) (only (chicken format) format) (only (srfi 1) cons* remove) (only (srfi 13) string-pad) coops-introspection coops) ;;; (define (symbol-printname-length s) (string-length (symbol->string s)) ) ;;; (define-type coops-class *) (define-type coops-instance *) (define-type coops-generic *) (define-type coops-method *) ;;; Helpers (define-constant MAXIMUM-SLOTNAME-LENGTH 32) (: closure-C-address (procedure --> number)) ; (define (closure-C-address proc) (##sys#peek-unsigned-integer proc 0) ) (: check-closure (symbol * --> procedure)) ; (define (check-closure loc obj) (##sys#check-closure obj loc) obj ) ;memq is not specific enough (: initslot? (symbol list --> boolean)) ; (define (initslot? slot initforms) ;search plist for slot name (let loop ((initforms initforms)) (and (not (null? initforms)) (or (eq? slot (car initforms)) (loop (cddr initforms)) ) ) ) ) (: slot-values (coops-instance (list-of symbol) #!optional list --> list)) ; (define (slot-values x slots #!optional (base '())) (foldl (lambda (ls slot) (if (slot-initialized? x slot) ;per Jun 19, '17 email from Sandra Snan (cons* slot (slot-value x slot) ls) ls ) ) base slots) ) (: *class-slots (coops-class --> list)) ; (define (*class-slots class) (slot-value class 'slots) ) (: shadowed-initforms (coops-instance list #!optional coops-class --> list)) ; (define (shadowed-initforms obj initforms #!optional (class (class-of obj))) (slot-values obj (remove (cut initslot? <> initforms) (*class-slots class)) initforms) ) ;;; Extras ;; ;sub-instance slot reference (define-syntax slot@ (syntax-rules (=) ; ((_ ?obj) ?obj ) ; ((_ ?obj ?slot = ?val) (set! (slot-value ?obj '?slot) ?val) ) ; ((_ ?obj ?slot ?slots ...) (slot@ (slot-value ?obj '?slot) ?slots ...) ) ) ) ;; ;use w/ is very suspect (: make-copy (coops-instance #!rest --> *)) ; (define (make-copy obj . initforms) (let ((class (class-of (check-instance 'make-copy obj)))) (apply make class (shadowed-initforms obj initforms class)) ) ) ;; (define-generic (describe-object obj)) (define-method (describe-object (obj #t) #!optional (out (current-output-port))) (let ((class (class-of obj))) (if (eq? class #t) ;then obj used thru a coops interface (format out "coops instance of class `#t': ~S~%" obj) ;else an instance (let* ( (slots (*class-slots class)) (name-maxlen (apply max (map symbol-printname-length slots))) ) ; (define (slot-per-line slot) (describe-object-slot obj slot name-maxlen out) (newline out) ) ; (format out "coops instance of class `~A':~%" (class-name class)) (for-each (cut slot-per-line <>) slots) ) ) ) ) (define-method (describe-object (prim ) #!optional (out (current-output-port))) (format out "coops instance of primitive class `~A': ~S~%" (class-name (class-of prim)) prim) ) (define-method (describe-object (proc ) #!optional (out (current-output-port))) (format out "~A~%" (if (generic-procedure? proc) "coops instance of `'" "coops instance of primitive class `'")) ) (define-method (describe-object (class ) #!optional (out (current-output-port))) (format out "coops standard-class `~A'~%" (class-name class)) ) ;; (: describe-object-slot (* symbol #!optional fixnum (or boolean output-port) -> *)) ; (define (describe-object-slot obj slot #!optional (name-maxlen MAXIMUM-SLOTNAME-LENGTH) (out (current-output-port))) (let* ( (intd? (slot-initialized? obj slot)) (nam (string-pad (symbol->string slot) name-maxlen)) (fmt (if intd? "~S" "#")) (args (if intd? `(,(slot-value obj slot)) '())) ) (format out "~A: ~?" nam fmt args) ) ) ;; ;(call-with-output-string (lambda (port) (print-closure proc port))) (: print-closure (procedure #!optional (or boolean output-port) -> *)) ; (define (print-closure proc #!optional (out (current-output-port))) (let ((idx 0)) (format out "~A: #x~X~%" idx (closure-C-address (check-closure 'print-closure proc))) (let ((size (##sys#size proc))) (do ((i (fx+ idx 1) (fx+ i 1))) ((fx= i size)) (format out "~A: ~S~%" i (##sys#slot proc i)) ) ) ) ) ) ;coops-extras