mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Implementation and test cases for the R6RS (rnrs records procedural) library,
along with its dependencies. * module/Makefile.am: Add new R6RS libraries below to RNRS_SOURCES. * module/rnrs/6/conditions.scm, exceptions.scm, syntax-case.scm: New files. * module/rnrs/io/6/simple.scm: New file. * module/rnrs/records/6/procedural.scm, syntactic.scm: New files. * test-suite/Makefile.am: Add tests/r6rs-records-procedural.test to SCM_TESTS. * test-suite/tests/r6rs-records-procedural.test: New file.
This commit is contained in:
parent
aa439b3908
commit
ce543a9f70
9 changed files with 1061 additions and 1 deletions
|
@ -257,10 +257,16 @@ SRFI_SOURCES = \
|
|||
|
||||
RNRS_SOURCES = \
|
||||
rnrs/6/base.scm \
|
||||
rnrs/6/conditions.scm \
|
||||
rnrs/6/control.scm \
|
||||
rnrs/6/exceptions.scm \
|
||||
rnrs/6/syntax-case.scm \
|
||||
rnrs/arithmetic/6/bitwise.scm \
|
||||
rnrs/bytevector.scm \
|
||||
rnrs/io/ports.scm
|
||||
rnrs/records/6/procedural.scm \
|
||||
rnrs/records/6/syntactic.scm \
|
||||
rnrs/io/ports.scm \
|
||||
rnrs/io.simple.scm
|
||||
|
||||
EXTRA_DIST += scripts/ChangeLog-2008
|
||||
EXTRA_DIST += scripts/README
|
||||
|
|
201
module/rnrs/6/conditions.scm
Normal file
201
module/rnrs/6/conditions.scm
Normal file
|
@ -0,0 +1,201 @@
|
|||
;;; conditions.scm --- The R6RS conditions library
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(library (rnrs conditions (6))
|
||||
(export &condition
|
||||
condition
|
||||
simple-conditions
|
||||
condition?
|
||||
condition-predicate
|
||||
condition-accessor
|
||||
define-condition-type
|
||||
|
||||
&message
|
||||
make-message-condition
|
||||
message-condition?
|
||||
condition-message
|
||||
|
||||
&warning
|
||||
make-warning
|
||||
warning?
|
||||
|
||||
&serious
|
||||
make-serious-condition
|
||||
serious-condition?
|
||||
|
||||
&error
|
||||
make-error
|
||||
error?
|
||||
|
||||
&violation
|
||||
make-violation
|
||||
violation?
|
||||
|
||||
&assertion
|
||||
make-assertion-violation
|
||||
assertion-violation?
|
||||
|
||||
&irritants
|
||||
make-irritants-condition
|
||||
irritants-condition?
|
||||
condition-irritants
|
||||
|
||||
&who
|
||||
make-who-condition
|
||||
who-condition?
|
||||
condition-who
|
||||
|
||||
&non-continuable
|
||||
make-non-continuable-violation
|
||||
non-continuable-violation?
|
||||
|
||||
&implementation-restriction
|
||||
make-implementation-restriction
|
||||
implementation-restriction-violation?
|
||||
|
||||
&lexical
|
||||
make-lexical-violation
|
||||
lexical-violation?
|
||||
|
||||
&syntax
|
||||
make-syntax-violation
|
||||
syntax-violation?
|
||||
syntax-violation-form
|
||||
syntax-violation-subform
|
||||
|
||||
&undefined
|
||||
make-undefined-violation
|
||||
undefined-violation?)
|
||||
(import (rnrs base (6))
|
||||
(rnrs io simple (6))
|
||||
(rnrs records procedural (6))
|
||||
(rnrs records syntactic (6))
|
||||
(rnrs syntax-case (6)))
|
||||
|
||||
(define &compound-condition (make-record-type-descriptor
|
||||
'&compound-condition #f #f #f #f
|
||||
'#((immutable components))))
|
||||
(define compound-condition? (record-predicate &compound-condition))
|
||||
|
||||
(define make-compound-condition
|
||||
(record-constructor (make-record-constructor-descriptor
|
||||
&compound-condition #f #f)))
|
||||
(define compound-condition-components (record-accessor &compound-condition 0))
|
||||
|
||||
(define-syntax define-condition-type
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
((_ condition-type supertype constructor predicate
|
||||
(field accessor) ...)
|
||||
(let
|
||||
((fields (let* ((field-spec-syntax #'((field accessor) ...))
|
||||
(field-specs (syntax->datum field-spec-syntax)))
|
||||
(datum->syntax stx
|
||||
(cons 'fields
|
||||
(map (lambda (field-spec)
|
||||
(cons 'immutable field-spec))
|
||||
field-specs))))))
|
||||
#`(define-record-type (condition-type constructor predicate)
|
||||
(parent supertype)
|
||||
#,fields))))))
|
||||
|
||||
(define &condition (@@ (rnrs records procedural) &condition))
|
||||
(define &condition-constructor-descriptor
|
||||
(make-record-constructor-descriptor &condition #f #f))
|
||||
(define condition-internal? (record-predicate &condition))
|
||||
|
||||
(define condition
|
||||
(lambda conditions
|
||||
(define (flatten cond)
|
||||
(if (compound-condition? cond)
|
||||
(fold append '() (map flatten (compound-condition-components cond)))
|
||||
cond))
|
||||
(or (for-all condition? conditions)
|
||||
(raise (make-assertion-violation)))
|
||||
(make-compound-condition (flatten conditions))))
|
||||
|
||||
(define (simple-conditions condition) (record-accessor &compound-condition 0))
|
||||
(define (condition? obj)
|
||||
(or (compound-condition? obj) (condition-internal? obj)))
|
||||
(define (condition-predicate rtd)
|
||||
(let ((rtd-predicate (record-predicate rtd)))
|
||||
(lambda (obj)
|
||||
(cond ((compound-condition? obj)
|
||||
(find rtd-predicate (compound-condition-components obj)))
|
||||
((condition-internal? obj) (rtd-predicate obj))
|
||||
(else #f)))))
|
||||
|
||||
(define (condition-accessor rtd proc)
|
||||
(let ((rtd-predicate (record-predicate rtd)))
|
||||
(lambda (obj)
|
||||
(cond ((rtd-predicate obj) (proc obj))
|
||||
((compound-condition? obj)
|
||||
(and=> (find rtd-predicate simple-conditions obj) proc))
|
||||
(else #f)))))
|
||||
|
||||
(define-condition-type &message &condition
|
||||
make-message-condition message-condition?
|
||||
(message condition-message))
|
||||
|
||||
(define-condition-type &warning &condition make-warning warning?)
|
||||
|
||||
(define &serious (@@ (rnrs records procedural) &serious))
|
||||
(define make-serious-condition
|
||||
(@@ (rnrs records procedural) make-serious-condition))
|
||||
(define serious-condition? (@@ (rnrs records procedural) serious-condition?))
|
||||
|
||||
(define-condition-type &error &serious make-error error?)
|
||||
|
||||
(define &violation (@@ (rnrs records procedural) &violation))
|
||||
(define make-violation (@@ (rnrs records procedural) make-violation))
|
||||
(define violation? (@@ (rnrs records procedural) violation?))
|
||||
|
||||
(define &assertion (@@ (rnrs records procedural) &assertion))
|
||||
(define make-assertion-violation
|
||||
(@@ (rnrs records procedural) make-assertion-violation))
|
||||
(define assertion-violation?
|
||||
(@@ (rnrs records procedural) assertion-violation?))
|
||||
|
||||
(define-condition-type &irritants &condition
|
||||
make-irritants-condition irritants-condition?
|
||||
(irritants condition-irritants))
|
||||
|
||||
(define-condition-type &who &condition
|
||||
make-who-condition who-condition?
|
||||
(who condition-who))
|
||||
|
||||
(define-condition-type &non-continuable &violation
|
||||
make-non-continuable-violation
|
||||
non-continuable-violation?)
|
||||
|
||||
(define-condition-type &implementation-restriction
|
||||
&violation
|
||||
make-implementation-restriction-violation
|
||||
implementation-restriction-violation?)
|
||||
|
||||
(define-condition-type &lexical &violation
|
||||
make-lexical-violation lexical-violation?)
|
||||
|
||||
(define-condition-type &syntax &violation
|
||||
make-syntax-violation syntax-violation
|
||||
(form syntax-violation-form)
|
||||
(subform syntax-violation-subform))
|
||||
|
||||
(define-condition-type &undefined &violation
|
||||
make-undefined-violation undefined-violation?))
|
51
module/rnrs/6/exceptions.scm
Normal file
51
module/rnrs/6/exceptions.scm
Normal file
|
@ -0,0 +1,51 @@
|
|||
;;; exceptions.scm --- The R6RS exceptions library
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(library (rnrs exceptions (6))
|
||||
(export with-exception-handler raise raise-continuable)
|
||||
(import (rnrs base (6))
|
||||
(rnrs conditions (6))
|
||||
(rnrs records procedural (6))
|
||||
(only (guile) with-throw-handler))
|
||||
|
||||
(define raise (@@ (rnrs records procedural) r6rs-raise))
|
||||
(define raise-continuable
|
||||
(@@ (rnrs records procedural) r6rs-raise-continuable))
|
||||
(define raise-object-wrapper?
|
||||
(@@ (rnrs records procedural) raise-object-wrapper?))
|
||||
(define raise-object-wrapper-obj
|
||||
(@@ (rnrs records procedural) raise-object-wrapper-obj))
|
||||
(define raise-object-wrapper-continuation
|
||||
(@@ (rnrs records procedural) raise-object-wrapper-continuation))
|
||||
|
||||
(define (with-exception-handler handler thunk)
|
||||
(with-throw-handler 'r6rs:exception
|
||||
thunk
|
||||
(lambda (key . args)
|
||||
(if (and (not (null? args))
|
||||
(raise-object-wrapper? (car args)))
|
||||
(let* ((cargs (car args))
|
||||
(obj (raise-object-wrapper-obj cargs))
|
||||
(continuation (raise-object-wrapper-continuation cargs))
|
||||
(handler-return (handler obj)))
|
||||
(if continuation
|
||||
(continuation handler-return)
|
||||
(raise (make-non-continuable-violation))))
|
||||
*unspecified*))))
|
||||
)
|
55
module/rnrs/6/syntax-case.scm
Normal file
55
module/rnrs/6/syntax-case.scm
Normal file
|
@ -0,0 +1,55 @@
|
|||
;;; syntax-case.scm --- R6RS support for `syntax-case' macros
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(library (rnrs syntax-case (6))
|
||||
(export make-variable-transformer
|
||||
syntax-case
|
||||
syntax
|
||||
|
||||
identifier?
|
||||
bound-identifier=?
|
||||
free-identifier=?
|
||||
|
||||
syntax->datum
|
||||
datum->syntax
|
||||
generate-temporaries
|
||||
with-syntax
|
||||
|
||||
quasisyntax
|
||||
unsyntax
|
||||
unsyntax-splicing
|
||||
|
||||
syntax-violation)
|
||||
(import (only (guile) syntax-case
|
||||
syntax
|
||||
|
||||
identifier?
|
||||
bound-identifier=?
|
||||
free-identifier=?
|
||||
|
||||
syntax->datum
|
||||
datum->syntax
|
||||
generate-temporaries
|
||||
with-syntax
|
||||
|
||||
quasisyntax
|
||||
unsyntax
|
||||
unsyntax-splicing
|
||||
|
||||
syntax-violation)))
|
77
module/rnrs/io/6/simple.scm
Normal file
77
module/rnrs/io/6/simple.scm
Normal file
|
@ -0,0 +1,77 @@
|
|||
;;; simple.scm --- The R6RS simple I/O library
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(library (rnrs io simple (6))
|
||||
(export eof-object
|
||||
eof-object?
|
||||
|
||||
call-with-input-file
|
||||
call-with-output-file
|
||||
|
||||
input-port?
|
||||
output-port?
|
||||
|
||||
current-input-port
|
||||
current-output-port
|
||||
current-error-port
|
||||
|
||||
with-input-from-file
|
||||
with-output-to-file
|
||||
|
||||
open-input-file
|
||||
open-output-file
|
||||
|
||||
close-input-port
|
||||
close-output-port
|
||||
|
||||
read-char
|
||||
peek-char
|
||||
read
|
||||
write-char
|
||||
newline
|
||||
display
|
||||
write)
|
||||
(import (only (rnrs io ports) eof-object
|
||||
eof-object?
|
||||
|
||||
input-port?
|
||||
output-port?)
|
||||
(only (guile) call-with-input-file
|
||||
call-with-output-file
|
||||
|
||||
current-input-port
|
||||
current-output-port
|
||||
current-error-port
|
||||
|
||||
with-input-file
|
||||
with-output-file
|
||||
|
||||
open-input-file
|
||||
open-output-file
|
||||
|
||||
close-input-port
|
||||
close-output-port
|
||||
|
||||
read-char
|
||||
peek-char
|
||||
read
|
||||
write-char
|
||||
newline
|
||||
display
|
||||
write)))
|
256
module/rnrs/records/6/procedural.scm
Normal file
256
module/rnrs/records/6/procedural.scm
Normal file
|
@ -0,0 +1,256 @@
|
|||
;;; procedural.scm --- Procedural interface to R6RS records
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(library (rnrs records procedural (6))
|
||||
(export make-record-type-descriptor
|
||||
record-type-descriptor?
|
||||
make-record-constructor-descriptor
|
||||
|
||||
record-constructor
|
||||
record-predicate
|
||||
record-accessor
|
||||
record-mutator)
|
||||
|
||||
(import (rnrs base (6))
|
||||
(only (guile) and=>
|
||||
throw
|
||||
display
|
||||
make-struct
|
||||
make-vtable
|
||||
map
|
||||
simple-format
|
||||
string-append
|
||||
|
||||
struct?
|
||||
struct-ref
|
||||
struct-set!
|
||||
struct-vtable
|
||||
vtable-index-layout
|
||||
|
||||
make-hash-table
|
||||
hashq-ref
|
||||
hashq-set!
|
||||
|
||||
vector->list)
|
||||
(ice-9 receive)
|
||||
(only (srfi :1) fold-right split-at take))
|
||||
|
||||
(define (record-rtd record) (struct-ref record 1))
|
||||
(define (record-type-name rtd) (struct-ref rtd 0))
|
||||
(define (record-type-parent rtd) (struct-ref rtd 2))
|
||||
(define (record-type-uid rtd) (struct-ref rtd 1))
|
||||
(define (record-type-generative? rtd) (not (record-type-uid rtd)))
|
||||
(define (record-type-sealed? rtd) (struct-ref rtd 3))
|
||||
(define (record-type-opaque? rtd) (struct-ref rtd 4))
|
||||
(define (record-type-field-names rtd) (struct-ref rtd 6))
|
||||
|
||||
(define record-type-vtable
|
||||
(make-vtable "prprprprprprprprpr"
|
||||
(lambda (obj port)
|
||||
(display "#<r6rs:record-type-vtable>" port))))
|
||||
|
||||
(define record-constructor-vtable
|
||||
(make-vtable "prprpr"
|
||||
(lambda (obj port)
|
||||
(display "#<r6rs:record-constructor-vtable>" port))))
|
||||
|
||||
(define uid-table (make-hash-table))
|
||||
|
||||
(define (make-record-type-descriptor name parent uid sealed? opaque? fields)
|
||||
(define fields-vtable
|
||||
(make-vtable (fold-right (lambda (x p)
|
||||
(string-append p (case (car x)
|
||||
((immutable) "pr")
|
||||
((mutable) "pw"))))
|
||||
"prpr" (vector->list fields))
|
||||
(lambda (obj port)
|
||||
(simple-format
|
||||
port "#<r6rs:record-field-layout-vtable:~A>" name))))
|
||||
(define field-names (map cadr (vector->list fields)))
|
||||
(define late-rtd #f)
|
||||
(define (private-record-predicate obj)
|
||||
(and (struct? obj)
|
||||
(let* ((vtable (struct-vtable obj))
|
||||
(layout (symbol->string
|
||||
(struct-ref vtable vtable-index-layout))))
|
||||
(and (>= (string-length layout) 3)
|
||||
(let ((rtd (struct-ref obj 1)))
|
||||
(and (record-type-descriptor? rtd)
|
||||
(or (eq? (struct-ref rtd 7) fields-vtable)
|
||||
(and=> (struct-ref obj 0)
|
||||
private-record-predicate))))))))
|
||||
|
||||
(define (field-binder parent-struct . args)
|
||||
(apply make-struct (append (list fields-vtable 0
|
||||
parent-struct
|
||||
late-rtd)
|
||||
args)))
|
||||
(if (and parent (record-type-sealed? parent))
|
||||
(r6rs-raise (make-assertion-violation)))
|
||||
|
||||
(let ((matching-rtd (and uid (hashq-ref uid-table uid))))
|
||||
(if matching-rtd
|
||||
(if (equal? (list name
|
||||
parent
|
||||
sealed?
|
||||
opaque?
|
||||
field-names
|
||||
(struct-ref fields-vtable vtable-index-layout))
|
||||
(list (record-type-name matching-rtd)
|
||||
(record-type-parent matching-rtd)
|
||||
(record-type-sealed? matching-rtd)
|
||||
(record-type-opaque? matching-rtd)
|
||||
(record-type-field-names matching-rtd)
|
||||
(struct-ref (struct-ref matching-rtd 7)
|
||||
vtable-index-layout)))
|
||||
matching-rtd
|
||||
(r6rs-raise (make-assertion-violation)))
|
||||
|
||||
(let ((rtd (make-struct record-type-vtable 0
|
||||
|
||||
name
|
||||
uid
|
||||
parent
|
||||
sealed?
|
||||
opaque?
|
||||
|
||||
private-record-predicate
|
||||
field-names
|
||||
fields-vtable
|
||||
field-binder)))
|
||||
(set! late-rtd rtd)
|
||||
(if uid (hashq-set! uid-table uid rtd))
|
||||
rtd))))
|
||||
|
||||
(define (record-type-descriptor? obj)
|
||||
(and (struct? obj) (eq? (struct-vtable obj) record-type-vtable)))
|
||||
|
||||
(define (make-record-constructor-descriptor rtd
|
||||
parent-constructor-descriptor
|
||||
protocol)
|
||||
(define rtd-arity (length (struct-ref rtd 6)))
|
||||
(define (default-inherited-protocol n)
|
||||
(lambda args
|
||||
(receive
|
||||
(n-args p-args)
|
||||
(split-at args (- (length args) rtd-arity))
|
||||
(let ((p (apply n n-args)))
|
||||
(apply p p-args)))))
|
||||
(define (default-protocol p) p)
|
||||
|
||||
(let* ((prtd (struct-ref rtd 1))
|
||||
(pcd (or parent-constructor-descriptor
|
||||
(and=> prtd (lambda (d) (make-record-constructor-descriptor
|
||||
prtd #f #f)))))
|
||||
(prot (or protocol (if pcd
|
||||
default-inherited-protocol
|
||||
default-protocol))))
|
||||
(make-struct record-constructor-vtable 0 rtd pcd prot)))
|
||||
|
||||
(define (record-constructor rctd)
|
||||
(let* ((rtd (struct-ref rctd 0))
|
||||
(parent-rctd (struct-ref rctd 1))
|
||||
(protocol (struct-ref rctd 2)))
|
||||
(protocol
|
||||
(if parent-rctd
|
||||
(let ((parent-record-constructor (record-constructor parent-rctd))
|
||||
(parent-rtd (struct-ref parent-rctd 0)))
|
||||
(lambda args
|
||||
(let ((struct (apply parent-record-constructor args)))
|
||||
(lambda args
|
||||
(apply (struct-ref rtd 8)
|
||||
(cons struct args))))))
|
||||
(lambda args (apply (struct-ref rtd 8) (cons #f args)))))))
|
||||
|
||||
(define (record-predicate rtd) (struct-ref rtd 5))
|
||||
|
||||
(define (record-accessor rtd k)
|
||||
(define (record-accessor-inner obj)
|
||||
(and obj
|
||||
(or (and (eq? (struct-ref obj 1) rtd) (struct-ref obj (+ k 2)))
|
||||
(record-accessor-inner (struct-ref obj 0)))))
|
||||
(lambda (obj) (record-accessor-inner obj)))
|
||||
|
||||
(define (record-mutator rtd k)
|
||||
(define (record-mutator-inner obj val)
|
||||
(and obj
|
||||
(or (and (eq? (struct-ref obj 1) rtd) (struct-set! obj (+ k 2) val))
|
||||
(record-mutator-inner (struct-ref obj 0) val))))
|
||||
(let* ((rtd-vtable (struct-ref rtd 7))
|
||||
(field-layout (symbol->string
|
||||
(struct-ref rtd-vtable vtable-index-layout))))
|
||||
(if (not (eqv? (string-ref field-layout (+ (* (+ k 2) 2) 1)) #\w))
|
||||
(r6rs-raise (make-assertion-violation))))
|
||||
(lambda (obj val) (record-mutator-inner obj val)))
|
||||
|
||||
;; Condition types that are used in the current library. These are defined
|
||||
;; here and not in (rnrs conditions) to avoid a circular dependency.
|
||||
|
||||
(define &condition (make-record-type-descriptor '&condition #f #f #f #f '#()))
|
||||
(define &condition-constructor-descriptor
|
||||
(make-record-constructor-descriptor &condition #f #f))
|
||||
|
||||
(define &serious (make-record-type-descriptor
|
||||
'&serious &condition #f #f #f '#()))
|
||||
(define &serious-constructor-descriptor
|
||||
(make-record-constructor-descriptor
|
||||
&serious &condition-constructor-descriptor #f))
|
||||
|
||||
(define make-serious-condition
|
||||
(record-constructor &serious-constructor-descriptor))
|
||||
(define serious-condition? (record-predicate &serious))
|
||||
|
||||
(define &violation (make-record-type-descriptor
|
||||
'&violation &serious #f #f #f '#()))
|
||||
(define &violation-constructor-descriptor
|
||||
(make-record-constructor-descriptor
|
||||
&violation &serious-constructor-descriptor #f))
|
||||
(define make-violation (record-constructor &violation-constructor-descriptor))
|
||||
(define violation? (record-predicate &violation))
|
||||
|
||||
(define &assertion (make-record-type-descriptor
|
||||
'&assertion &violation #f #f #f '#()))
|
||||
(define make-assertion-violation
|
||||
(record-constructor
|
||||
(make-record-constructor-descriptor
|
||||
&assertion &violation-constructor-descriptor #f)))
|
||||
(define assertion-violation? (record-predicate &assertion))
|
||||
|
||||
;; Exception wrapper type, along with a wrapping `throw' implementation.
|
||||
;; These are used in the current library, and so they are defined here and not
|
||||
;; in (rnrs exceptions) to avoid a circular dependency.
|
||||
|
||||
(define &raise-object-wrapper
|
||||
(make-record-type-descriptor '&raise-object-wrapper #f #f #f #f
|
||||
'#((immutable obj) (immutable continuation))))
|
||||
(define make-raise-object-wrapper
|
||||
(record-constructor (make-record-constructor-descriptor
|
||||
&raise-object-wrapper #f #f)))
|
||||
(define raise-object-wrapper? (record-predicate &raise-object-wrapper))
|
||||
(define raise-object-wrapper-obj (record-accessor &raise-object-wrapper 0))
|
||||
(define raise-object-wrapper-continuation
|
||||
(record-accessor &raise-object-wrapper 1))
|
||||
|
||||
(define (r6rs-raise obj)
|
||||
(throw 'r6rs:exception (make-raise-object-wrapper obj #f)))
|
||||
(define (r6rs-raise-continuable obj)
|
||||
(define (r6rs-raise-continuable-internal continuation)
|
||||
(raise (make-raise-object-wrapper obj continuation)))
|
||||
(call/cc r6rs-raise-continuable-internal))
|
||||
)
|
200
module/rnrs/records/6/syntactic.scm
Normal file
200
module/rnrs/records/6/syntactic.scm
Normal file
|
@ -0,0 +1,200 @@
|
|||
;;; syntactic.scm --- Syntactic support for R6RS records
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(library (rnrs records syntactic (6))
|
||||
(export define-record-type)
|
||||
(import (only (guile) *unspecified* unspecified? @ @@)
|
||||
(rnrs base (6))
|
||||
(rnrs lists (6))
|
||||
(rnrs records procedural (6))
|
||||
(rnrs syntax-case (6))
|
||||
(only (srfi :1) take))
|
||||
|
||||
(define-syntax define-record-type
|
||||
(lambda (stx)
|
||||
(define (guess-constructor-name record-name)
|
||||
(string->symbol (string-append "make-" (symbol->string record-name))))
|
||||
(define (guess-predicate-name record-name)
|
||||
(string->symbol (string-append (symbol->string record-name) "?")))
|
||||
(syntax-case stx ()
|
||||
((_ (record-name constructor-name predicate-name) record-clause ...)
|
||||
#'(define-record-type0
|
||||
(record-name constructor-name predicate-name)
|
||||
record-clause ...))
|
||||
((_ record-name record-clause ...)
|
||||
(let* ((record-name-sym (syntax->datum #'record-name))
|
||||
(constructor-name
|
||||
(datum->syntax
|
||||
#'record-name (guess-constructor-name record-name-sym)))
|
||||
(predicate-name
|
||||
(datum->syntax
|
||||
#'record-name (guess-predicate-name record-name-sym))))
|
||||
#`(define-record-type0
|
||||
(record-name #,constructor-name #,predicate-name)
|
||||
record-clause ...))))))
|
||||
|
||||
(define-syntax define-record-type0
|
||||
(lambda (stx)
|
||||
(define (sequence n)
|
||||
(define (seq-inner n) (if (= n 0) '(0) (cons n (seq-inner (- n 1)))))
|
||||
(reverse (seq-inner n)))
|
||||
(define (number-fields fields)
|
||||
(define (number-fields-inner fields counter)
|
||||
(if (null? fields)
|
||||
'()
|
||||
(cons (cons fields counter)
|
||||
(number-fields-inner (cdr fields) (+ counter 1)))))
|
||||
(number-fields-inner fields 0))
|
||||
|
||||
(define (process-fields record-name fields)
|
||||
(define record-name-str (symbol->string record-name))
|
||||
(define (guess-accessor-name field-name)
|
||||
(string->symbol (string-append
|
||||
record-name-str "-" (symbol->string field-name))))
|
||||
(define (guess-mutator-name field-name)
|
||||
(string->symbol
|
||||
(string-append
|
||||
record-name-str "-" (symbol->string field-name) "-set!")))
|
||||
|
||||
(define (f x)
|
||||
(cond ((symbol? x) (list 'immutable x (guess-accessor-name x) #f))
|
||||
((not (list? x)) (error))
|
||||
((eq? (car x) 'immutable)
|
||||
(cons 'immutable
|
||||
(case (length x)
|
||||
((2) (list (cadr x) (guess-accessor-name (cadr x)) #f))
|
||||
((3) (list (cadr x) (caddr x) #f))
|
||||
(else (error)))))
|
||||
((eq? (car x) 'mutable)
|
||||
(cons 'mutable
|
||||
(case (length x)
|
||||
((2) (list (cadr x)
|
||||
(guess-accessor-name (cadr x))
|
||||
(guess-mutator-name (cadr x))))
|
||||
((4) (cdr x))
|
||||
(else (error)))))
|
||||
(else (error))))
|
||||
(map f fields))
|
||||
|
||||
(syntax-case stx ()
|
||||
((_ (record-name constructor-name predicate-name) record-clause ...)
|
||||
(let loop ((fields *unspecified*)
|
||||
(parent *unspecified*)
|
||||
(protocol *unspecified*)
|
||||
(sealed *unspecified*)
|
||||
(opaque *unspecified*)
|
||||
(nongenerative *unspecified*)
|
||||
(constructor *unspecified*)
|
||||
(parent-rtd *unspecified*)
|
||||
(record-clauses (syntax->datum #'(record-clause ...))))
|
||||
(if (null? record-clauses)
|
||||
(let
|
||||
((field-names
|
||||
(datum->syntax
|
||||
#'record-name
|
||||
(if (unspecified? fields) '()
|
||||
(list->vector (map (lambda (x) (take x 2)) fields)))))
|
||||
(field-accessors
|
||||
(fold-left (lambda (x c lst)
|
||||
(cons #`(define #,(datum->syntax
|
||||
#'record-name (caddr x))
|
||||
(record-accessor record-name #,c))
|
||||
lst))
|
||||
'() fields (sequence (length fields))))
|
||||
(field-mutators
|
||||
(fold-left (lambda (x c lst)
|
||||
(if (cadddr x)
|
||||
(cons #`(define #,(datum->syntax
|
||||
#'record-name (cadddr x))
|
||||
(record-mutator record-name #,c))
|
||||
lst)
|
||||
lst))
|
||||
'() fields (sequence (length fields))))
|
||||
(parent (datum->syntax
|
||||
#'record-name (if (unspecified? parent) #f parent)))
|
||||
(protocol (datum->syntax
|
||||
#'record-name (if (unspecified? protocol)
|
||||
#f protocol)))
|
||||
(uid (datum->syntax
|
||||
#'record-name (if (unspecified? nongenerative)
|
||||
#f nongenerative)))
|
||||
(sealed? (if (unspecified? sealed) #f sealed))
|
||||
(opaque? (if (unspecified? opaque) #f opaque))
|
||||
(parent-cd (datum->syntax
|
||||
#'record-name (if (unspecified? parent-rtd)
|
||||
#f (caddr parent-rtd))))
|
||||
(parent-rtd (datum->syntax
|
||||
#'record-name (if (unspecified? parent-rtd)
|
||||
#f (cadr parent-rtd)))))
|
||||
|
||||
#`(begin
|
||||
(define record-name
|
||||
(make-record-type-descriptor
|
||||
#,(datum->syntax
|
||||
stx (list 'quote (syntax->datum #'record-name)))
|
||||
#,parent #,uid #,sealed? #,opaque?
|
||||
#,field-names))
|
||||
(define constructor-name
|
||||
(record-constructor
|
||||
(make-record-constructor-descriptor
|
||||
record-name #,parent-cd #,protocol)))
|
||||
(define predicate-name (record-predicate record-name))
|
||||
#,@field-accessors
|
||||
#,@field-mutators))
|
||||
(let ((cr (car record-clauses)))
|
||||
(case (car cr)
|
||||
((fields)
|
||||
(if (unspecified? fields)
|
||||
(loop (process-fields (syntax->datum #'record-name)
|
||||
(cdr cr))
|
||||
parent protocol sealed opaque nongenerative
|
||||
constructor parent-rtd (cdr record-clauses))
|
||||
(error)))
|
||||
((parent) (if (unspecified? parent)
|
||||
(loop fields (cadr cr) protocol sealed opaque
|
||||
nongenerative constructor parent-rtd
|
||||
(cdr record-clauses))
|
||||
(error)))
|
||||
((protocol) (if (unspecified? protocol)
|
||||
(loop fields parent (cadr cr) sealed opaque
|
||||
nongenerative constructor parent-rtd
|
||||
(cdr record-clauses))
|
||||
(error)))
|
||||
((sealed) (if (unspecified? sealed)
|
||||
(loop fields parent protocol (cadr cr) opaque
|
||||
nongenerative constructor parent-rtd
|
||||
(cdr record-clauses))
|
||||
(error)))
|
||||
((opaque) (if (unspecified? opaque)
|
||||
(loop fields parent protocol sealed (cadr cr)
|
||||
nongenerative constructor parent-rtd
|
||||
(cdr record-clauses))
|
||||
(error)))
|
||||
((nongenerative) (if (unspecified? nongenerative)
|
||||
(loop fields parent protocol sealed
|
||||
opaque (cadr cr) constructor
|
||||
parent-rtd (cdr record-clauses))
|
||||
(error)))
|
||||
((parent-rtd) (if (unspecified? parent-rtd)
|
||||
(loop fields parent protocol sealed opaque
|
||||
nongenerative constructor parent-rtd
|
||||
(cdr record-clauses))
|
||||
(error)))
|
||||
(else (error))))))))))
|
||||
)
|
|
@ -79,6 +79,7 @@ SCM_TESTS = tests/00-initial-env.test \
|
|||
tests/r6rs-arithmetic-bitwise.test \
|
||||
tests/r6rs-control.test \
|
||||
tests/r6rs-ports.test \
|
||||
tests/r6rs-records-procedural.test \
|
||||
tests/rnrs-libraries.test \
|
||||
tests/ramap.test \
|
||||
tests/reader.test \
|
||||
|
|
213
test-suite/tests/r6rs-records-procedural.test
Normal file
213
test-suite/tests/r6rs-records-procedural.test
Normal file
|
@ -0,0 +1,213 @@
|
|||
;;; r6rs-control.test --- Test suite for R6RS (rnrs control)
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; This library is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU Lesser General Public
|
||||
;; License as published by the Free Software Foundation; either
|
||||
;; version 3 of the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This library is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; Lesser General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU Lesser General Public
|
||||
;; License along with this library; if not, write to the Free Software
|
||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
(define-module (test-suite test-rnrs-records-procedural)
|
||||
:use-module ((rnrs conditions) :version (6))
|
||||
:use-module ((rnrs exceptions) :version (6))
|
||||
:use-module ((rnrs records procedural) :version (6))
|
||||
:use-module (test-suite lib))
|
||||
|
||||
(define :point (make-record-type-descriptor
|
||||
'point #f #f #f #f '#((mutable x) (mutable y))))
|
||||
(define :point-cd (make-record-constructor-descriptor :point #f #f))
|
||||
|
||||
(define :voxel (make-record-type-descriptor
|
||||
'voxel :point #f #f #f '#((mutable z))))
|
||||
(define :voxel-cd (make-record-constructor-descriptor :voxel :point-cd #f))
|
||||
|
||||
(with-test-prefix "make-record-type-descriptor"
|
||||
(pass-if "simple"
|
||||
(let* ((:point-cd (make-record-constructor-descriptor :point #f #f))
|
||||
(make-point (record-constructor :point-cd))
|
||||
(point? (record-predicate :point))
|
||||
(point-x (record-accessor :point 0))
|
||||
(point-y (record-accessor :point 1))
|
||||
(point-x-set! (record-mutator :point 0))
|
||||
(point-y-set! (record-mutator :point 1))
|
||||
(p1 (make-point 1 2)))
|
||||
(point? p1)
|
||||
(eqv? (point-x p1) 1)
|
||||
(eqv? (point-y p1) 2)
|
||||
(unspecified? (point-x-set! p1 5))
|
||||
(eqv? (point-x p1) 5)))
|
||||
|
||||
(pass-if "sealed records cannot be subtyped"
|
||||
(let* ((:sealed-point (make-record-type-descriptor
|
||||
'sealed-point #f #f #t #f '#((mutable x)
|
||||
(mutable y))))
|
||||
(success #f))
|
||||
(call/cc
|
||||
(lambda (continuation)
|
||||
(with-exception-handler
|
||||
(lambda (condition)
|
||||
(set! success (assertion-violation? condition))
|
||||
(continuation))
|
||||
(lambda () (make-record-type-descriptor
|
||||
'sealed-point-subtype :sealed-point #f #f #f
|
||||
'#((mutable z)))))))
|
||||
success))
|
||||
|
||||
(pass-if "non-generative records with same uid are eq"
|
||||
(let* ((:rtd-1 (make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid #f #f '#((mutable foo) (immutable bar))))
|
||||
(:rtd-2 (make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid #f #f '#((mutable foo) (immutable bar)))))
|
||||
(eq? :rtd-1 :rtd-2)))
|
||||
|
||||
(pass-if "&assertion raised on conflicting non-generative types"
|
||||
(let* ((:rtd-1 (make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid-2 #f #f '#((mutable foo) (immutable bar))))
|
||||
(success 0)
|
||||
(check-definition
|
||||
(lambda (thunk)
|
||||
(call/cc
|
||||
(lambda (continuation)
|
||||
(with-exception-handler
|
||||
(lambda (condition)
|
||||
(if (assertion-violation? condition)
|
||||
(set! success (+ success 1)))
|
||||
(continuation))
|
||||
thunk))))))
|
||||
(check-definition
|
||||
(lambda ()
|
||||
(make-record-type-descriptor
|
||||
'rtd1a #f 'my-uid-2 #f #f '#((mutable foo) (immutable bar)))))
|
||||
(check-definition
|
||||
(lambda ()
|
||||
(make-record-type-descriptor
|
||||
'rtd1 :point 'my-uid-2 #f #f '#((mutable foo) (immutable bar)))))
|
||||
(check-definition
|
||||
(lambda ()
|
||||
(make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid-2 #t #f '#((mutable foo) (immutable bar)))))
|
||||
(check-definition
|
||||
(lambda ()
|
||||
(make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid-2 #f #t '#((mutable foo) (immutable bar)))))
|
||||
(check-definition
|
||||
(lambda () (make-record-type-descriptor 'rtd1 #f 'my-uid-2 #f #f '#())))
|
||||
(check-definition
|
||||
(lambda ()
|
||||
(make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid-2 #f #f '#((mutable foo) (immutable baz)))))
|
||||
(check-definition
|
||||
(lambda ()
|
||||
(make-record-type-descriptor
|
||||
'rtd1 #f 'my-uid-2 #f #f '#((immutable foo) (immutable bar)))))
|
||||
(eqv? success 7))))
|
||||
|
||||
(with-test-prefix "record-type-descriptor?"
|
||||
(pass-if "simple"
|
||||
(record-type-descriptor?
|
||||
(make-record-type-descriptor 'test #f #f #f #f '#()))))
|
||||
|
||||
(with-test-prefix "record-constructor"
|
||||
(pass-if "simple"
|
||||
(let* ((make-point (record-constructor :point-cd))
|
||||
(point? (record-predicate :point))
|
||||
(point-x (record-accessor :point 0))
|
||||
(point-y (record-accessor :point 1))
|
||||
(point (make-point 1 2)))
|
||||
(and (point? point)
|
||||
(eqv? (point-x point) 1)
|
||||
(eqv? (point-y point) 2))))
|
||||
|
||||
(pass-if "construct record subtype"
|
||||
(let* ((make-voxel (record-constructor :voxel-cd))
|
||||
(voxel? (record-predicate :voxel))
|
||||
(voxel-z (record-accessor :voxel 0))
|
||||
(voxel (make-voxel 1 2 3)))
|
||||
(and (voxel? voxel)
|
||||
(eqv? (voxel-z voxel) 3)))))
|
||||
|
||||
(with-test-prefix "record-predicate"
|
||||
(pass-if "simple"
|
||||
(let* ((make-point (record-constructor :point-cd))
|
||||
(point (make-point 1 2))
|
||||
(point? (record-predicate :point)))
|
||||
(point? point)))
|
||||
|
||||
(pass-if "predicate returns true on subtype"
|
||||
(let* ((make-voxel (record-constructor :voxel-cd))
|
||||
(voxel (make-voxel 1 2 3))
|
||||
(point? (record-predicate :point)))
|
||||
(point? voxel)))
|
||||
|
||||
(pass-if "predicate returns false on supertype"
|
||||
(let* ((make-point (record-constructor :point-cd))
|
||||
(point (make-point 1 2))
|
||||
(voxel? (record-predicate :voxel)))
|
||||
(not (voxel? point)))))
|
||||
|
||||
(with-test-prefix "record-accessor"
|
||||
(pass-if "simple"
|
||||
(let* ((make-point (record-constructor :point-cd))
|
||||
(point (make-point 1 2))
|
||||
(point-x (record-accessor :point 0))
|
||||
(point-y (record-accessor :point 1)))
|
||||
(and (eqv? (point-x point) 1)
|
||||
(eqv? (point-y point) 2))))
|
||||
|
||||
(pass-if "accessor for supertype applied to subtype"
|
||||
(let* ((make-voxel (record-constructor :voxel-cd))
|
||||
(voxel (make-voxel 1 2 3))
|
||||
(point-x (record-accessor :point 0))
|
||||
(point-y (record-accessor :point 1)))
|
||||
(and (eqv? (point-x voxel) 1)
|
||||
(eqv? (point-y voxel) 2)))))
|
||||
|
||||
(with-test-prefix "record-mutator"
|
||||
(pass-if "simple"
|
||||
(let* ((make-point (record-constructor :point-cd))
|
||||
(point (make-point 1 2))
|
||||
(point-set-x! (record-mutator :point 0))
|
||||
(point-set-y! (record-mutator :point 1))
|
||||
(point-x (record-accessor :point 0))
|
||||
(point-y (record-accessor :point 1)))
|
||||
(point-set-x! point 3)
|
||||
(point-set-y! point 4)
|
||||
(and (eqv? (point-x point) 3)
|
||||
(eqv? (point-y point) 4))))
|
||||
|
||||
(pass-if "&assertion raised on request for immutable field"
|
||||
(let* ((:immutable-point (make-record-type-descriptor
|
||||
'point #f #f #f #f '#((immutable x)
|
||||
(immutable y))))
|
||||
(success #f))
|
||||
(call/cc
|
||||
(lambda (continuation)
|
||||
(with-exception-handler
|
||||
(lambda (condition)
|
||||
(set! success (assertion-violation? condition))
|
||||
(continuation))
|
||||
(lambda () (record-mutator :immutable-point 0)))))
|
||||
success))
|
||||
|
||||
(pass-if "mutator for supertype applied to subtype"
|
||||
(let* ((make-voxel (record-constructor :voxel-cd))
|
||||
(voxel (make-voxel 1 2 3))
|
||||
(point-set-x! (record-mutator :point 0))
|
||||
(point-set-y! (record-mutator :point 1))
|
||||
(point-x (record-accessor :point 0))
|
||||
(point-y (record-accessor :point 1)))
|
||||
(point-set-x! voxel 3)
|
||||
(point-set-y! voxel 4)
|
||||
(and (eqv? (point-x voxel) 3)
|
||||
(eqv? (point-y voxel) 4)))))
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue