;;; (define-record-type ...) ;;; ::= ( ) ;;; | ;;; ::= (fields ...) ;;; | (protocol ) ;;; | (parent ) ;;; | (sealed ) ; defaults to #f ;;; | (opaque ) ; defaults to #f ;;; | (nongenerative ) ; use uid ;;; | (nongenerative) ; compile-time generative ;;; ;;; ::= (immutable ) ;;; | (mutable ) ;;; | (immutable ) ;;; | (mutable ) ;;; | ; defaults to immutable ;;; ;;; (record-type-descriptor ) => rtd ;;; (record-constructor-descriptor ) => rcd (library (ikarus r6rs records syntactic) (export ---) (import ---) (define-syntax define-record-type (lambda (x) (define (id ctxt . str*) (datum->syntax ctxt (string->symbol (apply string-append (map (lambda (x) (cond [(symbol? x) (symbol->string x)] [(string? x) x] [else (error 'define-record-type "BUG")])) str*))))) (define (get-record-name spec) (syntax-case spec () [(foo make-foo foo?) #'foo] [foo #'foo])) (define (get-record-constructor-name spec ctxt) (syntax-case spec () [(foo make-foo foo?) #'make-foo] [foo (id ctxt "make-" (syntax->datum #'foo))])) (define (get-record-predicate-name spec ctxt) (syntax-case spec () [(foo make-foo foo?) #'foo?] [foo (id ctxt (syntax->datum #'foo) "?")])) (define (get-clause id ls) (syntax-case ls () [() #f] [((x . rest) . ls) (if (free-identifier=? id #'x) #'(x . rest) (get-clause id #'ls))])) (define (foo-rtd-code ctxt name clause*) (define (convert-field-spec* ls) (list #'quote (list->vector (map (lambda (x) (syntax-case x (mutable immutable) [(mutable name . rest) #'(mutable name)] [(immutable name . rest) #'(immutable name)] [name #'(immutable name)])) ls)))) (with-syntax ([name name] [parent-rtd-code (syntax-case (get-clause #'parent clause*) () [(_ name) #'(record-type-descriptor name)] [_ #'#f])] [uid-code (syntax-case (get-clause #'nongenerative clause*) () [(_) (datum->syntax ctxt (gensym))] [(_ uid) #''uid] [_ #'#f])] [sealed? (syntax-case (get-clause #'sealed? clause*) () [(_ #t) #'#t] [_ #'#f])] [opaque? (syntax-case (get-clause #'opaque? clause*) () [(_ #t) #'#t] [_ #'#f])] [fields (syntax-case (get-clause #'fields clause*) () [(_ field-spec* ...) (convert-field-spec* #'(field-spec* ...))] [_ #''#()])]) #'(make-record-type-descriptor 'name parent-rtd-code uid-code sealed? opaque? fields))) (define (foo-rcd-code clause*) (with-syntax ([parent-rcd-code (syntax-case (get-clause #'parent clause*) () [(_ name) #'(record-constructor-descriptor name)] [_ #'#f])]) #'(make-record-constructor-descriptor foo-rtd parent-rcd-code protocol))) (define (get-protocol-code clause*) (syntax-case (get-clause #'protocol clause*) () [(_ expr) #'expr] [_ #'#f])) (define (do-define-record ctxt namespec clause*) (let ([foo (get-record-name namespec)]) (with-syntax ([foo foo] [make-foo (get-record-constructor-name namespec ctxt)] [foo? (get-record-predicate-name namespec ctxt)] [foo-rtd-code (foo-rtd-code ctxt name clause*)] [protocol-code (get-protocol-code clause*)]) #'(begin (define foo-rtd foo-rtd-code) (define protocol protocol-code) (define foo-rcd foo-rcd-code) (define-syntax foo (list '$rtd #'foo-rtd #'foo-rcd)) (define foo? (record-predicate foo-rtd)) (define make-foo (record-constructor foo-rcd)) (define foo-x* (record-accessor foo-rtd idx*)) ... (define set-foo-x!* (record-mutator foo-rtd mutable-idx*)) ...)))) (syntax-case x () [(ctxt namespec clause* ...) (do-define-record #'ctxt #'namespec #'(clause* ...))]))) ) (define-record foo (bar baz)) == (define-record-type foo (fields bar baz) (nongenerative)) (define-record-type foo (fields x y) (nongenerative)) == (begin (define-syntax foo `($rtd )) ;;; = #[rcd #f #f] ;;; = #[rtd foo #(x y) ---] (define (make-foo x y) ($record ' x y)) (define (foo? x) ($record/rtd? x ')) (define (foo-x x) (if ($record/rtd? x ') ($record-ref x 0) (error ---))) (define (foo-y x) (if ($record/rtd? x ') ($record-ref x 1) (error ---)))) (record-type-descriptor foo) == ' (record-constructor-descriptor foo) == ' (record-constructor ') => (default-rtd-constructor ') => (lambda (x y) ($record ' x y)) (define-record-type foo (fields x y) (generative)) == (begin (define foo-rtd (make-rtd --- ---)) (define foo-rcd (make-rcd foo-rtd #f #f)) (define-syntax foo `($rtd #'foo-rtd #'foo-rcd)) (define (make-foo x y) ($record foo-rtd x y)) (define (foo? x) ($record/rtd? x foo-rtd)) (define (foo-x x) (if ($record/rtd? x foo-rtd) ($record-ref x 0) (error ---))) (define (foo-y x) (if ($record/rtd? x foo-rtd) ($record-ref x 1) (error ---)))) (define-record-type foo (fields x y) (parent pfoo) ;;; pfoo = `($rtd ) (nongenerative)) == (begin (define-syntax foo `($rtd )) ;;; = #[rcd #f #f] ;;; = #[rcd #f #f] ;;; = #[rtd foo #(x y) ---] (define (make-foo x y) ($record ' x y)) (define (foo? x) ($record/rtd? x ')) (define (foo-x x) (if ($record/rtd? x ') ($record-ref x 2) (error ---))) (define (foo-y x) (if ($record/rtd? x ') ($record-ref x 3) (error ---)))) (define-record-type bar (fields c) (parent foo) (protocol (lambda (p) (lambda (a b c) ((p a b) c)))) (sealed #f) (opaque #t) == (begin (define protocol-0 (lambda (p) (lambda (a b c) ((p a b) c)))) (define bars-rtd ') (define-syntax bar `($rtd ))