#!r6rs ;; Implementation of explicit-naming layer for R6RS Records ;; Based on the SRFI implementation: ; Copyright (C) Michael Sperber (2005). All Rights Reserved. ; ; Permission is hereby granted, free of charge, to any person ; obtaining a copy of this software and associated documentation files ; (the "Software"), to deal in the Software without restriction, ; including without limitation the rights to use, copy, modify, merge, ; publish, distribute, sublicense, and/or sell copies of the Software, ; and to permit persons to whom the Software is furnished to do so, ; subject to the following conditions: ; ; The above copyright notice and this permission notice shall be ; included in all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. (library (r6rs private records-explicit) (export define-record-type record-type-descriptor record-constructor-descriptor fields mutable immutable parent parent-rtd protocol sealed opaque nongenerative) (import (for (rnrs base) run expand) (rnrs records procedural) (for (rnrs syntax-case) expand)) (define-syntax define-aux (syntax-rules () [(_ id) (define-syntax id (syntax-rules ()))] [(_ id ...) (begin (define-aux id) ...)])) (define-aux fields mutable immutable parent parent-rtd protocol sealed opaque nongenerative) ;; ASSQ at the syntax level (define-syntax define-alist-extractor (syntax-rules () ((define-alist-extractor ?name ?name/cps ?tag ?default) (begin (define-syntax ?name/cps (syntax-rules (?tag) ((?name/cps () ?k . ?rands) (?k ?default . ?rands)) ((?name/cps ((?tag ?val) . ?rest) ?k . ?rands) (?k ?val . ?rands)) ((?name/cps ((?another-tag . ?vals) . ?rest) ?k . ?rands) (?name/cps ?rest ?k . ?rands)))) (define-syntax ?name (syntax-rules (?tag) ((?name ()) ?default) ((?name ((?tag ?val) . ?rest)) ?val) ((?name ((?another-tag . ?vals) . ?rest)) (?name ?rest)))))))) (define-syntax extract-parent/sel (syntax-rules (parent parent-rtd) ((_ () ?sel) #f) ((_ ((parent ?val) . ?rest) ?sel) (?sel (record-type-descriptor ?val) (record-constructor-descriptor ?val))) ((_ ((parent-rtd ?rtd ?cons) . ?rest) ?sel) (?sel ?rtd ?cons)) ((_ ((?another-tag . ?vals) . ?rest) ?sel) (extract-parent/sel ?rest ?sel)))) (define-syntax sel-record-type-descriptor (syntax-rules () [(_ ?rtd ?cons) ?rtd])) (define-syntax sel-record-constructor-descriptor (syntax-rules () [(_ ?rtd ?cons) ?cons])) (define-alist-extractor extract-sealed extract-sealed/cps sealed #f) (define-alist-extractor extract-opaque extract-opaque/cps opaque #f) (define-alist-extractor extract-protocol extract-protocol/cps protocol #f) (define-alist-extractor extract-nongenerative extract-nongenerative/cps nongenerative #f) (define-alist-extractor extract-record-name extract-record-name/cps record-name cant-happen) (define-alist-extractor extract-constructor-name extract-constructor-name/cps constructor-name cant-happen) (define-alist-extractor extract-predicate-name extract-predicate-name/cps predicate-name cant-happen) (define-syntax define-record-type (syntax-rules () ((define-record-type (?record-name ?constructor-name ?predicate-name) ?clause ...) (define-record-type-1 ((record-name ?record-name) ; prop alist (constructor-name ?constructor-name) (predicate-name ?predicate-name)) () ; fields ?clause ...)))) (define-syntax define-record-type-1 (syntax-rules (parent parent-rtd protocol sealed nongenerative opaque fields mutable immutable) ;; find PARENT clause ((define-record-type-1 ?props ?field-specs (parent ?parent) ?clause ...) (define-record-type-1 ((parent ?parent) . ?props) ?field-specs ?clause ...)) ((define-record-type-1 ?props ?field-specs (parent-rtd ?parent ?cons) ?clause ...) (define-record-type-1 ((parent-rtd ?parent ?cons) . ?props) ?field-specs ?clause ...)) ;; find PROTOCOL clause ((define-record-type-1 ?props ?field-specs (protocol ?protocol) ?clause ...) (define-record-type-1 ((protocol ?protocol) . ?props) ?field-specs ?clause ...)) ;; find SEALED clause ((define-record-type-1 ?props ?field-specs (sealed #t) ?clause ...) (define-record-type-1 ((sealed #t) . ?props) ?field-specs ?clause ...)) ((define-record-type-1 ?props ?field-specs (sealed #f) ?clause ...) (define-record-type-1 ((sealed #f) . ?props) ?field-specs ?clause ...)) ;; find OPAQUE clause ((define-record-type-1 ?props ?field-specs (opaque #t) ?clause ...) (define-record-type-1 ((opaque #t) . ?props) ?field-specs ?clause ...)) ((define-record-type-1 ?props ?field-specs (opaque #f) ?clause ...) (define-record-type-1 ((opaque #f) . ?props) ?field-specs ?clause ...)) ;; parse FIELDS clause ;; base case ((define-record-type-1 ?props (?field-spec ...) (fields) ?clause ...) (define-record-type-1 ?props (?field-spec ...) ?clause ...)) ;; complete spec ((define-record-type-1 ?props (?field-spec ...) (fields (immutable ?field-name ?accessor) ?rest ...) ?clause ...) (define-record-type-1 ?props (?field-spec ... (immutable ?field-name (?accessor))) (fields ?rest ...) ?clause ...)) ((define-record-type-1 ?props (?field-spec ...) (fields (mutable ?field-name ?accessor ?mutator) ?rest ...) ?clause ...) (define-record-type-1 ?props (?field-spec ... (mutable ?field-name (?accessor ?mutator))) (fields ?rest ...) ?clause ...)) ;; find NONGENERATIVE clause ((define-record-type-1 ?props ?field-specs (nongenerative ?uid) ?clause ...) (define-record-type-1 ((nongenerative '?uid) . ?props) ?field-specs ?clause ...)) ;; generate code ((define-record-type-1 ?props ((?mutability ?field-name ?procs) ...)) (begin ;; where we need LETREC* semantics if this is to work internally (define $rtd (make-record-type-descriptor (extract-record-name/cps ?props quote) (extract-parent/sel ?props sel-record-type-descriptor) (extract-nongenerative ?props) (extract-sealed ?props) (extract-opaque ?props) '#((?mutability ?field-name) ...))) (define $constructor-descriptor (make-record-constructor-descriptor $rtd (extract-parent/sel ?props sel-record-constructor-descriptor) (extract-protocol ?props))) (extract-record-name/cps ?props define-record-type-name $rtd $constructor-descriptor) (extract-constructor-name/cps ?props define (record-constructor $constructor-descriptor)) (extract-predicate-name/cps ?props define (record-predicate $rtd)) (define-record-fields $rtd 0 (?field-name ?procs) ...))))) (define-syntax define-record-type-name (syntax-rules () ((define-record-type-name ?name ?rtd ?constructor-descriptor) (define-syntax ?name (make-variable-transformer (lambda (stx) (syntax-case stx (descriptor constructor-descriptor set!) (?name (identifier? #'?name) #'?rtd) ((set! ?name . rest) (syntax-violation #f "cannot mutate record-type descriptor binding" stx #'name)) ((?name descriptor) #'?rtd) ((?name constructor-descriptor) #'?constructor-descriptor)))))))) (define-syntax no-record-type (syntax-rules (descriptor constructor-descriptor) ((?name descriptor) #f) ((?name constructor-descriptor) #f))) (define-syntax record-type-descriptor (syntax-rules () ((record-type-descriptor ?record-type) (?record-type descriptor)))) (define-syntax record-constructor-descriptor (syntax-rules () ((record-constructor-descriptor ?record-type) (?record-type constructor-descriptor)))) (define-syntax define-record-fields (syntax-rules () ((define-record-fields ?rtd ?index) (begin)) ((define-record-fields ?rtd ?index (?field-name ?procs) . ?rest) (begin (define-record-field ?rtd ?field-name ?index ?procs) (define-record-fields ?rtd (+ 1 ?index) . ?rest))))) (define-syntax define-record-field (syntax-rules () ((define-record-field ?rtd ?field-name ?index (?accessor-name)) (define ?accessor-name (record-accessor ?rtd ?index))) ((define-record-field ?rtd ?field-name ?index (?accessor-name ?mutator-name)) (begin (define ?accessor-name (record-accessor ?rtd ?index)) (define ?mutator-name (record-mutator ?rtd ?index)))))))