#lang racket (require racket/syntax) (require racket/set) (require uuid) (require (for-syntax racket/base)) (require finalizer) (provide def-roos %-! roos-new %-> %->> roos-class? roos-object? roos-obj? roos-class roos-classname roos-help with-roos-obj roos-id roos-id! roos-storage! roos-storage-stop-deleting! ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Persistence ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define @@storage@@ (make-hasheq)) (define (@@cache-get obj var default) (let ((cl-hash (hash-ref @@storage@@ (roos-classname obj) (make-hasheq)))) (let ((id (%-> obj roos-id))) (let ((obj-hash (hash-ref cl-hash id (make-hasheq)))) (hash-ref obj-hash var default))))) (define (@@cache-set! obj var val) (let ((cl-hash (hash-ref @@storage@@ (roos-classname obj) #f))) (unless cl-hash (set! cl-hash (make-hasheq)) (hash-set! @@storage@@ (roos-classname obj) cl-hash)) (let ((id (%-> obj roos-id))) (let ((obj-hash (hash-ref cl-hash id #f))) (unless obj-hash (set! obj-hash (make-hasheq)) (hash-set! cl-hash id obj-hash)) (hash-set! obj-hash var val))))) (define @@stop-deleting@@ #f) (define (@@cache-delete! obj) (unless @@stop-deleting@@ (let ((cl-hash (hash-ref @@storage@@ (roos-classname obj) (make-hasheq)))) (hash-remove! cl-hash (%-> obj roos-id))))) (define (@@cache-stop-deleting yn) (set! @@stop-deleting@@ yn)) (define (roos-storage! getter setter deleter stop-deleting) (set! @@cache-get getter) (set! @@cache-set! setter) (set! @@cache-delete! deleter) (set! @@cache-stop-deleting stop-deleting) ) (define (roos-storage-stop-deleting! yn) (@@cache-stop-deleting yn)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Class definition syntax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (struct roos-class* (closure name members super-inits decl)) (struct roos-object* (this supers classname the-class set-caller (caller #:mutable))) (define (@@new-id) (string->symbol (string-append "roos-" (uuid-string)))) (define-syntax @@mk-supers (syntax-rules () ((_ supers) (define supers (list))) ((_ supers s1 ...) (define supers (list s1 ...))) )) (define-syntax @@mk-lit (syntax-rules () ((_ (f ...)) '(f ...)) ((_ (f . a)) '(f . a)) )) (define-syntax @@mk-name (syntax-rules () ((_ (f . args)) 'f) ((_ f . args) 'f) )) (define-syntax @@mk-proc (syntax-rules () ((_ (f . args)) f) ((_ f . args) f) )) (define-syntax @@mk-super-infos (syntax-rules () ((_ supers) '()) ((_ supers s1 ...) (list 's1 ...)) )) (define-syntax (@@mk-mem-info* stx) (syntax-case stx () ((@@mk-mem-info* persist doc a b) #'(list 'a 'a (string-append " " doc))) ((@@mk-mem-info* doc a b) (if (eq? (syntax->datum #'doc) 'persist) #'(list 'a 'a "") #'(list 'a 'a doc) )) )) (define-syntax @@mk-member-info* (syntax-rules () ((_ ((f) expr ...)) (list (@@mk-name f) (@@mk-lit (f)) "")) ((_ ((f . b) expr ...)) (list (@@mk-name f . b) (@@mk-lit (f . b)) "")) ((_ ((f a ...) expr ...)) (list (@@mk-name f a ...) (@@mk-lit (f a ...)) "")) ((_ ((f a ... . b) expr ...)) (list (@@mk-name f a ... . b) (@@mk-lit (f a ... . b)) "")) ((_ (doc ((f) expr ...))) (list (@@mk-name f) (@@mk-lit (f)) doc)) ((_ (doc ((f . a) expr ...))) (list (@@mk-name f . a) (@@mk-lit (f . a)) doc)) ((_ (doc ((f a ...) expr ...))) (list (@@mk-name f a ...) (@@mk-lit (f a ...)) doc)) ((_ (doc ((f a ... . b) expr ...))) (list (@@mk-name f a ... . b) (@@mk-lit (f a ... . b)) doc)) ((_ (persist doc (a b))) (@@mk-mem-info* persist doc a b)) ((_ (doc (a b))) (@@mk-mem-info* doc a b)) ((_ (a b)) (list 'a 'a "")) )) (define-syntax (@@mk-member-info stx) (syntax-case stx () ((_ (keyw)) (let ((kw (syntax->datum #'keyw))) (if (or (eq? kw 'init) (eq? kw 'finalize)) #'(list 'keyw 'keyw (format "has empty '~a'" 'keyw)) #'(@@mk-member-info* keyw)))) ((_ (keyw b1 ...)) (let ((kw (syntax->datum #'keyw))) (if (or (eq? kw 'init) (eq? kw 'finalize)) #'(list 'keyw 'keyw (format "has defined '~a'" 'keyw)) #'(@@mk-member-info* (keyw b1 ...))))) ((_ x) #'(@@mk-member-info* x)) )) (define-syntax @@mk-member-infos (syntax-rules () ((_ b1 ...) (list (@@mk-member-info b1) ...)) )) (define-syntax @@mk-super-init (syntax-rules () ((_ (roos-new cl ...)) (if (roos-class? (@@mk-proc cl ...)) (@@mk-proc cl ...) roos-new)) ((_ (f ...)) (@@mk-proc f ...)) ((_ f) f) )) (define-syntax @@mk-super-inits (syntax-rules () ((_ supers) (list)) ((_ supers s1 ...) (list (@@mk-super-init s1) ...)) )) (define-syntax @@mk-persist-def (syntax-rules () ((_ this supers (persist doc (a b))) (begin (hash-set! this 'a (lambda () (@@cache-get this 'a b))) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (@@cache-set! this 'a v) v)))) ((_ this supers (persist (a b))) (begin (hash-set! this 'a (lambda () (@@cache-get this 'a b))) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (@@cache-set! this 'a v) v)))) )) (define-syntax @@mk-var-def (syntax-rules () ((_ this supers (doc (a b))) (begin (define a b) (hash-set! this 'a (lambda () a)) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (set! a v) a)))) ((_ this supers (a b)) (begin (define a b) (hash-set! this 'a (lambda () a)) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (set! a v) a)))) )) (define-for-syntax (@@guard-persist-doc pd stx) (unless (or (eq? pd 'persist) (string? pd)) (let ((ind (if (symbol? pd) pd (string->symbol (format "~a" pd))))) (raise-syntax-error #f "keyword 'persist' or documentation expected" (cadddr (syntax->datum stx)))))) (define-for-syntax (@@guard-persist p stx) (unless (eq? p 'persist) (let ((ind (if (symbol? p) p (string->symbol (format "~a" p))))) (raise-syntax-error #f "keyword 'persist' expected" (cadddr (syntax->datum stx)))))) (define-for-syntax (@@guard-doc d stx) (unless (string? d) (raise-syntax-error #f "documentation expected" (cadddr (syntax->datum stx))))) (define-for-syntax (@@guard-identifier i stx) (unless (and (identifier? i) (not (symbol? i))) (raise-syntax-error #f "identifier expected" (cadddr (syntax->datum stx))))) (define-for-syntax (@@guard-func-identifier f-def stx) (let ((i (car (syntax-e f-def)))) (unless (and (identifier? i) (not (symbol? i))) (raise-syntax-error #f "identifier expected" (cadddr (syntax->datum stx)))))) (define-syntax (@@mk-persist stx) (syntax-case stx () [(@@mk-persist this supers (p doc (a b))) (let ((pp (syntax->datum #'p)) (dd (syntax->datum #'doc))) (@@guard-persist pp stx) (@@guard-doc dd stx) (if (eq? pp 'persist) #'(begin (hash-set! this 'a (lambda () (@@cache-get this 'a b))) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (@@cache-set! this 'a v) v))) #'(begin (define a b) (hash-set! this 'a (lambda () a)) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (set! a v) v))) ))] [(@@mk-persist this supers (p (a b))) (let ((pp (syntax->datum #'p))) (@@guard-persist-doc pp stx) (if (eq? pp 'persist) #'(begin (hash-set! this 'a (lambda () (@@cache-get this 'a b))) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (@@cache-set! this 'a v) v))) #'(begin (define a b) (hash-set! this 'a (lambda () a)) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (set! a v) v))) ))] [(@@mk-persist this supers (a b)) (begin (@@guard-identifier #'a stx) #'(begin (define a b) (hash-set! this 'a (lambda () a)) (hash-set! this (string->symbol (format "~a!" 'a)) (lambda (v) (set! a v) v)))) ] )) (define-syntax (@@mk-doc-method stx) (syntax-case stx () [(@@mk-method this supers (doc ((f ...) expr ...))) (let ((dd (syntax->datum #'doc)) (ff #'(f ...))) ;(display "form1:")(display (syntax->datum ff))(newline) (@@guard-doc dd stx) (@@guard-func-identifier ff stx) #'(begin (define (f ...) expr ...) (hash-set! this (@@mk-name f ...) (@@mk-proc f ...)) ))] [(@@mk-method this supers (doc ((f ... . b) expr ...))) (let ((dd (syntax->datum #'doc))) ;(display "form4:")(display (syntax->datum #'(f ...)))(newline) (@@guard-doc dd stx) (@@guard-func-identifier #'(f ...) stx) #'(begin (define (f ... . b) expr ...) (hash-set! this (@@mk-name f ...) (@@mk-proc f ...)) ))] )) (define-syntax (@@mk-method stx) (syntax-case stx () [(@@mk-method this supers ((f ...) expr ...)) (begin ;(display "form2:")(display (syntax->datum #'(f ...)))(newline) (@@guard-func-identifier #'(f ...) stx) #'(begin (define (f ...) expr ...) (hash-set! this (@@mk-name f ...) (@@mk-proc f ...)) ))] [(@@mk-method this supers ((f ... . b) expr ...)) (begin ;(display "form3:")(display (syntax->datum #'(f ...)))(newline) (@@guard-func-identifier #'(f ...) stx) #'(begin (define (f ... . b) expr ...) (hash-set! this (@@mk-name f ...) (@@mk-proc f ...)) ))] )) (define-syntax @@mk-body* (syntax-rules () ((_ this supers (doc ((f) expr ...))) (@@mk-doc-method this supers (doc ((f) expr ...)))) ((_ this supers (doc ((f . b) expr ...))) (@@mk-doc-method this supers (doc ((f . b) expr ...)))) ((_ this supers (doc ((f a ... . b) expr ...))) (@@mk-doc-method this supers (doc ((f a ... . b) expr ...)))) ((_ this supers ((f) expr ...)) (@@mk-method this supers ((f) expr ...))) ((_ this supers ((f a ...) expr ...)) (@@mk-method this supers ((f a ...) expr ...))) ((_ this supers ((f a ... . b) expr ...)) (@@mk-method this supers ((f a ... . b) expr ...))) ((_ this supers ((f . b) expr ...)) (@@mk-method this supers ((f . b) expr ...))) ((_ this supers (doc ((f a ...) expr ...))) (@@mk-doc-method this supers (doc ((f a ...) expr ...)))) ((_ this supers (persist doc (a b))) (@@mk-persist this supers (persist doc (a b)))) ((_ this supers (doc (a b))) (@@mk-persist this supers (doc (a b)))) ((_ this supers (a b)) (@@mk-persist this supers (a b))) )) (define-syntax (@@mk-keyw stx) (syntax-case stx () ((_ this keyw) (begin ;(printf "mk-keyw: ~a" (syntax->datum #'keyw)) #'(hash-set! this 'keyw (lambda () #f)))) ((_ this keyw body ...) (begin ;(printf "mk-keyw: ~a" (syntax->datum #'keyw)) #'(hash-set! this 'keyw (lambda () body ...)))) )) (define-syntax (@@mk-body stx) (syntax-case stx () ((_ this supers (keyw)) (let ((kw (syntax->datum #'keyw))) (if (or (eq? kw 'init) (eq? kw 'finalize)) #'(@@mk-keyw this keyw) #'(@@mk-body* this supers (keyw))))) ((_ this supers (keyw a ...)) (let ((kw (syntax->datum #'keyw))) (if (or (eq? kw 'init) (eq? kw 'finalize)) #'(@@mk-keyw this keyw a ...) #'(@@mk-body* this supers (keyw a ...))))) ((_ this supers any) #'(@@mk-body* this supers any)) )) (define-syntax @@mk-bodies (syntax-rules () ((_ this supers (b1 ...)) (begin (@@mk-body this supers b1) ...)))) (define-syntax @@mk-result (syntax-rules () ((_ (cl . args) val) (set! cl val)))) (define (@@find-func f objs) (if (null? objs) #f (let ((h (roos-object*-this (car objs)))) (if (hash-ref h f #f) (hash-ref h f) (let ((ff (@@find-func f (roos-object*-supers (car objs))))) (if ff ff (@@find-func f (cdr objs)))))))) (define-syntax (@@guard-this stx) (syntax-case stx () ((_ this) (begin (unless (eq? (syntax->datum #'this) 'this) (raise-syntax-error #f "Keyword 'this' expected" (cadr (syntax->datum stx)))) #'#t )))) (define-syntax (@@guard-supers stx) (syntax-case stx () ((_ supers) (begin (unless (eq? (syntax->datum #'supers) 'supers) (raise-syntax-error #f "Keyword 'supers' expected" (cadr (syntax->datum stx)))) #'#t )))) (define-syntax @@check-keywords (syntax-rules () ((_ this supers . args) (begin (@@guard-this this) (@@guard-supers supers))))) (define (@@has-persist syntax count) ;(display "has-persist ")(display count)(display " ")(display syntax)(newline) (if (null? syntax) #f (let ((b (car syntax))) (if (list? b) (if (null? b) (@@has-persist (cdr syntax) (+ count 1)) (if (eq? (car b) 'persist) #t (@@has-persist (cdr syntax) (+ count 1)))) (@@has-persist (cdr syntax) (+ count 1)))))) (define-syntax @@finalize (syntax-rules () ((_ this (body ...)) (let ((has-persist (@@has-persist '(body ...) 0))) (if has-persist (let ((our-finalizer (hash-ref (roos-object*-this this) 'finalize))) (when (not our-finalizer) (set! our-finalizer (lambda () #t))) (hash-set! (roos-object*-this this) 'finalize 'finalizer-registered) (register-finalizer this (lambda (obj) ; First call our own finalizer (our-finalizer) ; Next delete from storage (@@cache-delete! obj)))) (let ((f (hash-ref (roos-object*-this this) 'finalize))) (unless (eq? f #f) (register-finalizer this (lambda (obj) (f))))))) ) )) (define-syntax def-roos-body (syntax-rules () ((_ cl-decl this (supers ...) body ...) (begin (@@check-keywords this supers ...) (define this (make-hasheq)) (hash-set! this 'finalize #f) (@@mk-body this (supers ...) (roos-id (@@new-id))) (@@mk-supers supers ...) (@@mk-bodies this (supers ...) (body ...)) (define (@set-caller@ c) (set-roos-object*-caller! this c) (for-each (lambda (s) ((roos-object*-set-caller s) c)) (roos-object*-supers this))) (define (@caller@ f . args) (let ((ff (@@find-func f (list this)))) (if ff (apply ff args) (error (format "~a: ~a - no such member." (roos-object*-classname this) f))))) (set! this (roos-object* this (@@mk-proc supers ...) (@@mk-name cl-decl) (@@mk-proc cl-decl) @set-caller@ @caller@)) (@set-caller@ @caller@) (@@finalize this (body ...)) (unless (eq? (hash-ref (roos-object*-this this) 'init #f) #f) ((hash-ref (roos-object*-this this) 'init))) this ) ) )) (define-syntax def-roos (syntax-rules () ((_ (cl) this (supers ...) body ...) (begin (define (cl) (def-roos-body cl this (supers ...) body ...)) (@@mk-result (cl) (roos-class* (@@mk-proc cl) (@@mk-name cl) (@@mk-member-infos body ...) (@@mk-super-infos supers ...) '(cl))))) ((_ (cl . a) this (supers ...) body ...) (begin (define (cl . a) (def-roos-body (cl . a) this (supers ...) body ...)) (@@mk-result (cl . a) (roos-class* (@@mk-proc cl) (@@mk-name cl) (@@mk-member-infos body ...) (@@mk-super-infos supers ...) '(cl . a))))) ((_ (cl a ...) this (supers ...) body ...) (begin (define (cl a ...) (def-roos-body (cl a ...) this (supers ...) body ...)) (@@mk-result (cl a ...) (roos-class* (@@mk-proc cl) (@@mk-name cl) (@@mk-member-infos body ...) (@@mk-super-infos supers ...) '(cl a ...))))) ((_ (cl a ... . b) this (supers ...) body ...) (begin (define (cl a ... . b) (def-roos-body (cl a ... . b) this (supers ...) body ...)) (@@mk-result (cl a ... . b) (roos-class* (@@mk-proc cl) (@@mk-name cl) (@@mk-member-infos body ...) (@@mk-super-infos supers ...) '(cl a ... . b))))) ((_ cl this supers body ...) (error (string-append "Wrong roos definition\n" "Define roos classes as follows:\n\n" "(def-roos (cl ...) this (supers ...)\n" " (attr value)\n" " (persist (attr value))\n" " (\"documentation\" (attr value))\n" " (persist \"documentation\" (attr value))\n" "\n" " ((method ...) body ...)\n" " (\"documentation\" ((method ...) body ...))\n" "\n" " (init expr ...) ; optional initializer\n" " (finalize expr ...) ; optional finalizer\n" ")\n"))) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Class Instantiation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-syntax @-* (syntax-rules () ((_ cl . args) (roos-class*-closure cl)))) (define-syntax %-! (syntax-rules () ((_ cl) (if (roos-class*? cl) ((@-* cl)) (error "Not a roos class"))) ((_ cl a ...) (if (roos-class*? cl) ((@-* cl) a ...) (error "Not a roos class"))) )) (define-syntax roos-new (syntax-rules () ((_ cl ...) (%-! cl ...)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Calling methods / attributes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (@@is-supers*? objs) (if (null? objs) #t (if (roos-object*? (car objs)) (@@is-supers*? (cdr objs)) #f))) (define (@@is-supers? objs) (if (list? objs) (if (null? objs) #f (@@is-supers*? objs)) #f)) (define-syntax %->> (syntax-rules () ((_ obj f) (if (roos-object*? obj) (let ((f (@@find-func 'f (list obj)))) (if f f (if (@@is-supers? obj) (let ((f (@@find-func 'f obj))) (if f f (error (format "~a: ~a - no such member" (roos-object*-classname obj) 'f )))) (error "Not a list of roos objects (supers)")))) (error "Not a roos object"))))) (define-syntax with-roos-obj (syntax-rules () ((_ obj (m1 ...) body ...) (let* ((m1 (%->> obj m1)) ...) body ...)))) (define-syntax @@mk-call (syntax-rules () ((_ g (f)) (g)) ((_ g (f a ...)) (g a ...)) )) (define (@@find-> obj name) (if (roos-object*? obj) (let ((f (@@find-func name (list obj)))) (if f f (error (format "~a: ~a - no such member" (roos-object*-classname obj) name)))) (if (@@is-supers? obj) (let ((f (@@find-func name obj))) (if f f (error (format "~a: ~a - no such member" (roos-object*-classname obj) name)))) (error "Not a roos object of roos supers")))) (define-syntax @-> (syntax-rules () ((_ caller f) (caller 'f)) ((_ caller f a ...) (caller 'f a ...)) )) (define-syntax %-> (syntax-rules () ((_ obj f ...) (if (roos-object*? obj) (@-> (roos-object*-caller obj) f ...) (let ((g (@@find-> obj (@@mk-name f ...)))) (@@mk-call g (f ...))))) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Introspection / Predicates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define roos-obj? roos-object*?) (define roos-object? roos-object*?) (define roos-class? roos-class*?) (define (roos-id obj) (%-> obj roos-id)) (define (roos-id! obj id) (%-> obj roos-id! id)) (define (roos-class cl-obj) (if (roos-object*? cl-obj) (roos-object*-the-class cl-obj) (if (roos-class*? cl-obj) cl-obj (error "Not a roos object or class")))) (define-syntax roos-classname (syntax-rules () ((_ cl-obj) (if (roos-object*? cl-obj) (roos-object*-classname cl-obj) (if (roos-class*? cl-obj) 'cl-obj (error "Not a roos object or class")))) )) (define (@@get-members-cl cl funcs) (let ((filter-f (if (null? funcs) (lambda x #t) (let ((s (list->seteq funcs))) (lambda (e) (set-member? s (car e))))))) (filter filter-f (roos-class*-members cl)))) (define (@@get-super-members-obj s-objs s) (if (null? s-objs) '() (let ((s-obj (car s-objs))) (let ((members (roos-class*-members (roos-object*-the-class s-obj)))) (let ((s-obj-members (filter (lambda (e) (not (set-member? s (car e)))) members))) (for-each (lambda (m) (set-add! s (car m))) s-obj-members) (append s-obj-members (@@get-super-members-obj (roos-object*-supers s-obj) s) (@@get-super-members-obj (cdr s-objs) s)) ))) )) (define (@@get-members-obj obj . funcs) (let ((filter-f (if (null? funcs) (lambda x #t) (let ((s (list->seteq funcs))) (lambda (e) (set-member? s (car e))))))) (let ((cl (roos-object*-the-class obj))) (let* ((m (roos-class*-members cl)) (s (list->mutable-seteq (map (lambda (e) (car e)) m)))) (let ((supers (@@get-super-members-obj (roos-object*-supers obj) s))) (filter filter-f (append m supers))))))) (define (@@travel-obj-hierarchy f obj) (letrec ((g (lambda (depth obj) (f depth obj) (for-each (lambda (o) (g (+ depth 1) o)) (roos-object*-supers obj))))) (g 0 obj))) (define-syntax @@mk-hlp-mems (syntax-rules () ((_ cl-obj) '()) ((_ cl-obj f ...) (list 'f ...)))) (define (roos-help* cl-obj . symbols) (let* ((is-class (roos-class*? cl-obj)) (is-obj (roos-object*? cl-obj)) (funcs symbols) (no-funcs (null? funcs))) (let ((cln (if is-class (roos-class*-name cl-obj) (roos-object*-classname cl-obj))) (cl (if is-class cl-obj (roos-object*-the-class cl-obj))) ) (when no-funcs (begin (printf "Roos class: ~a\n" cln) (let ((re #px"^[(](.*)[)]$")) (printf " Instantiation: (-! ~a)\n" (cadr (regexp-match re (format "~a" (roos-class*-decl cl)))))) (let ((inits (roos-class*-super-inits cl))) (unless (null? inits) (printf " Supers initializators:~a\n" (apply string-append (map (lambda (x) (format " ~a" x)) inits))))) (when is-obj (begin (printf " Object class hierarchy:\n") (@@travel-obj-hierarchy (lambda (depth obj) (printf " ~a~a~a~a\n" (make-string depth #\space) (if (= depth 0) "" #\|) (make-string (* depth 3) #\-) (roos-object*-classname obj))) cl-obj))) (printf " ~a members:\n" (if is-class "Class" "Object")))) (if is-class (let ((ind (if no-funcs " " ""))) (for-each (lambda (m) (printf "~a~a~a\n" ind (cadr m) (if (string=? (caddr m) "") "" (format ": ~a" (caddr m))))) (@@get-members-cl cl-obj funcs))) (let ((s (mutable-seteq))) (@@travel-obj-hierarchy (lambda (_depth obj) (let ((cl (roos-object*-the-class obj)) (cln (roos-object*-classname obj)) (ind (if no-funcs " " "")) (depth (if no-funcs _depth 0))) (let ((members (filter (lambda (m) (not (set-member? s (car m)))) (@@get-members-cl cl funcs)))) (for-each (lambda (m) (set-add! s (car m))) members) (unless (null? members) (let ((starter (format "~a~a~a~a" (make-string depth #\space) (if (= depth 0) "" "|") (make-string (* depth 3) #\-) cln))) (printf "~a~a - ~a~a\n" ind starter (cadr (car members)) (if (string=? (caddr (car members)) "") "" (format ": ~a" (caddr (car members))))) (let ((indent (make-string ( * depth 3) #\space)) (line (make-string (string-length (symbol->string cln)) #\-))) (for-each (lambda (m) (if no-funcs (printf "~a~a |~a ~a~a\n" ind indent line (cadr m) (if (string=? (caddr m) "") "" (format ": ~a" (caddr m)))) (printf "~a~a - ~a~a\n" ind starter (cadr m) (if (string=? (caddr m) "") "" (format ": ~a" (caddr m)))) )) (cdr members)))))))) cl-obj) (let ((cr "")) (for-each (lambda (func) (unless (set-member? s func) (begin (printf "~a~a is not a member\n" cr func) (set! cr "")))) funcs) ) )) ; let s ))) (define-syntax roos-help (syntax-rules () ((_ cl-obj) (roos-help* cl-obj)) ((_ cl-obj a ...) (roos-help* cl-obj 'a ...)) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Testing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (module+ test (require rackunit) (define test-nr 0) (define-syntax tst (syntax-rules () ((_ tst) (begin (set! test-nr (+ test-nr 1)) (printf "test ~a. ~a: " test-nr 'tst) (let ((chk (check-true tst "failed"))) (printf "~a\n" (if chk "OK" "not oke")) chk))) ((_ tst msg) (begin (set! test-nr (+ test-nr 1)) (printf "test ~a. ~a: " test-nr msg) (let ((chk (check-true tst "failed"))) (printf "~a\n" (if chk "OK" "not oke")) chk))) )) (test-case "Simple ROOS declaration and usage" (def-roos (t1) this (supers) (a 10)) (let ((obj (%-! t1))) (check-true (= (%-> obj a) 10)) (%-> obj a! 12) (check-true (= (%-> obj a) 12))) ) (test-case "ROOS declaration with supers" (def-roos (a x) this (supers) (y (+ x 4)) ((g a) (* a (%-> this y)))) (def-roos (b) this (supers (roos-new a 2)) (y 55) ;("The v function gets and sets the y member of the super object of class a" ((v . a) (if (null? a) (%-> supers y) (begin (%-> supers y! (car a)) (%-> supers y)))) ;) ) (let ((bb (roos-new b))) (tst (= (%-> bb y) 55)) (tst (= (%-> bb g 2) 110)) (tst (= (%-> bb v) 6)) (tst (= (%-> bb v 10) 10)) (tst (= (%-> bb g 3) 165)) (tst (= (%-> bb y! 10) 10)) (tst (= (%-> bb g 2) 20))) ) (test-case "ROOS al declaration variants" (def-roos (decl) this (supers) (a1 1) (persist (a2 2)) ("a3 doc" (a3 3)) (persist "a4 doc" (a4 4)) ((f1) (+ 2 3) (* 3 3)) ("f2-doc" ((f2) (* 3 3) (+ 2 2))) ((f3 a b) (* a b)) ((f4 a . b) (cons a b)) ("f5-doc" ((f5 a b) (* a b))) ("f6-doc" ((f6 a) (* a a a))) ("f7-doc" ((f7 a . b) (cons a (cons (length b) (cons a b))))) ("f8-doc" ((f8 . b) (append b b))) ((f9 . c) (append c c)) ((f10 a b . d) (cons (list a b) d)) ("f11-doc" ((f11 a b c d e . h) (cons (* a b c d e) h))) ) (let ((o (%-! decl))) (tst (= (%-> o a1) 1)) (tst (begin (%-> o a1! 33) (= (%-> o a1) 33))) (tst (symbol? (%-> o roos-id))) (tst (begin (printf "roos-id: ~a " (%-> o roos-id)) #t) "Displaying roos id of object") (tst (eq? (%-> o roos-id! 'my-id) 'my-id)) (tst (begin (printf "roos-id: ~a " (%-> o roos-id)) #t) "Displaying roos id of object after set") (%-> o a2! 99) (tst (= (%-> o a2) 99)) (tst (begin (printf "storage: ~a " @@storage@@) #t)) (tst (= (hash-ref (hash-ref (hash-ref @@storage@@ 'decl) 'my-id ) 'a2) 99)) (let ((o1 (%-! decl))) (tst (eq? (%-> o1 roos-id! 'my-id) 'my-id) "Don't do this at home: giving new object same id as existing object") (tst (begin (printf "o1 %-> a2: ~a " (%-> o1 a2)) #t) "a2 = o1 %-> a2") (tst (= (%-> o1 a2) (%-> o a2))) (tst (equal? (%-> o1 a2! "hoi") "hoi")) (tst (string=? (%-> o a2) "hoi")) ) (collect-garbage) (tst (= (%-> o a2) 2) "After collection of o1, o will be deleted from storage") ) (def-roos (t1) this (supers) (x 8)) (def-roos (t2 a) this (supers) (x a)) (tst (= (%-> (%-! t2 5) x) 5)) (def-roos (t3 . a) this (supers) ((f y) (map (lambda (x) (* x y)) a))) (tst (equal? (%-> (%-! t3 4 5 6) f 2) '(8 10 12))) (def-roos (t4 a b c . d) this (supers (%-! t3 a b c)) ((g y) (cons (map (lambda (x) (+ x y)) (%-> supers f y)) (map (lambda (x) (* x y)) d))) ) (tst (let ((r (%-> (%-! t4 2 3 4 12 13) g 2)) (R '((6 8 10) 24 26))) (equal? r R))) ) )