made struct library work better with copy-struct; still not perfect

svn: r381
This commit is contained in:
Robby Findler 2005-07-16 04:41:29 +00:00
parent 6fed6ba449
commit 20aa3cef02
2 changed files with 248 additions and 149 deletions

View File

@ -256,6 +256,14 @@ add struct contracts for immutable structs?
(let* ([struct-name (syntax-case struct-name-position ()
[(a b) (syntax a)]
[else struct-name-position])]
[super-id (syntax-case struct-name-position ()
[(a b) (syntax b)]
[else #t])]
[struct-info (extract-struct-info struct-name-position)]
[constructor-id (list-ref struct-info 1)]
[predicate-id (list-ref struct-info 2)]
[selector-ids (reverse (list-ref struct-info 3))]
[mutator-ids (reverse (list-ref struct-info 4))]
[parent-struct-count (let ([parent-info (extract-parent-struct-info struct-name-position)])
(and parent-info
(let ([fields (cadddr parent-info)])
@ -274,69 +282,105 @@ add struct contracts for immutable structs?
field-name
struct-name))
field-names)]
[selector-ids (map (lambda (field-name)
(build-selector-id struct-name field-name))
field-names)]
[mutator-ids (map (lambda (field-name)
(build-mutator-id struct-name field-name))
field-names)]
[predicate-id (build-predicate-id struct-name)]
[constructor-id (build-constructor-id struct-name)])
(with-syntax ([(selector-codes ...)
[struct:struct-name
(datum->syntax-object
struct-name
(string->symbol
(string-append
"struct:"
(symbol->string (syntax-e struct-name)))))])
(let ([unknown-info
(λ (what)
(raise-syntax-error
'provide/contract
(format "cannot determine ~a" what)
provide-stx
struct-name))])
(unless constructor-id (unknown-info "constructor"))
(unless predicate-id (unknown-info "predicate"))
(unless (andmap values selector-ids) (unknown-info "selectors"))
(unless (andmap values mutator-ids) (unknown-info "mutators")))
(with-syntax ([((selector-codes selector-new-names) ...)
(filter
(lambda (x) x)
(map/count (lambda (selector-id field-contract-id index)
(if (or (not parent-struct-count)
(parent-struct-count . <= . index))
(code-for-one-id stx
selector-id
(build-selector-contract struct-name
predicate-id
field-contract-id)
#f)
(code-for-one-id/new-name
stx
selector-id
(build-selector-contract struct-name
predicate-id
field-contract-id)
#f)
#f))
selector-ids
field-contract-ids))]
[(mutator-codes ...)
[((mutator-codes mutator-new-names) ...)
(filter
(lambda (x) x)
(map/count (lambda (mutator-id field-contract-id index)
(if (or (not parent-struct-count)
(parent-struct-count . <= . index))
(code-for-one-id stx
mutator-id
(build-mutator-contract struct-name
predicate-id
field-contract-id)
#f)
(code-for-one-id/new-name stx
mutator-id
(build-mutator-contract struct-name
predicate-id
field-contract-id)
#f)
#f))
mutator-ids
field-contract-ids))]
[predicate-code (code-for-one-id stx predicate-id (syntax (-> any/c boolean?)) #f)]
[constructor-code (code-for-one-id
stx
constructor-id
(build-constructor-contract stx
field-contract-ids
predicate-id)
#f)]
[(predicate-code predicate-new-name)
(code-for-one-id/new-name stx predicate-id (syntax (-> any/c boolean?)) #f)]
[(constructor-code constructor-new-name)
(code-for-one-id/new-name
stx
constructor-id
(build-constructor-contract stx
field-contract-ids
predicate-id)
#f)]
[(field-contracts ...) field-contracts]
[(field-contract-ids ...) field-contract-ids]
[struct-name struct-name]
[struct:struct-name (datum->syntax-object
struct-name
(string->symbol
(string-append
"struct:"
(symbol->string (syntax-e struct-name)))))])
(syntax/loc stx
(begin
(define field-contract-ids field-contracts) ...
selector-codes ...
mutator-codes ...
predicate-code
constructor-code
(provide struct-name struct:struct-name))))))
[(field-contract-ids ...) field-contract-ids])
(with-syntax ([struct-code
(with-syntax ([id-rename (a:mangle-id provide-stx
"provide/contract-struct-expandsion-info-id"
struct-name)]
[struct-name struct-name]
[struct:struct-name struct:struct-name]
;[(selector-id ...) selector-ids]
;[(mutator-id ...) mutator-ids]
;[predicate-id predicate-id]
;[constructor-id constructor-id]
[super-id (if (boolean? super-id)
super-id
(with-syntax ([super-id super-id])
(syntax #'super-id)))])
(syntax (begin
#;
(provide struct-name)
(provide (rename id-rename struct-name))
(define-syntax id-rename
(list-immutable #'struct:struct-name
#'constructor-new-name
#'predicate-new-name
(list-immutable #'selector-new-names ...)
(list-immutable #'mutator-new-names ...)
super-id)))))]
[struct:struct-name struct:struct-name])
(syntax/loc stx
(begin
struct-code
(define field-contract-ids field-contracts) ...
selector-codes ...
mutator-codes ...
predicate-code
constructor-code
(provide struct:struct-name)))))))
;; map/count : (X Y int -> Z) (listof X) (listof Y) -> (listof Z)
(define (map/count f l1 l2)
@ -364,6 +408,19 @@ add struct contracts for immutable structs?
(syntax b))))]
[a #f]))
;; extract-struct-info : syntax -> (union #f (list syntax syntax (listof syntax) ...))
(define (extract-struct-info stx)
(let ([id (syntax-case stx ()
[(a b) (syntax a)]
[_ stx])])
(syntax-local-value
id
(lambda ()
(raise-syntax-error 'provide/contract
"expected a struct name"
provide-stx
id)))))
;; build-constructor-contract : syntax (listof syntax) syntax -> syntax
(define (build-constructor-contract stx field-contract-ids predicate-id)
(with-syntax ([(field-contract-ids ...) field-contract-ids]
@ -393,103 +450,66 @@ add struct contracts for immutable structs?
. -> .
void?))))
;; build-constructor-id : syntax -> syntax
;; constructs the name of the selector for a particular field of a struct
(define (build-constructor-id struct-name)
(datum->syntax-object
struct-name
(string->symbol
(string-append
"make-"
(symbol->string (syntax-object->datum struct-name))))))
;; build-predicate-id : syntax -> syntax
;; constructs the name of the selector for a particular field of a struct
(define (build-predicate-id struct-name)
(datum->syntax-object
struct-name
(string->symbol
(string-append
(symbol->string (syntax-object->datum struct-name))
"?"))))
;; build-selector-id : syntax syntax -> syntax
;; constructs the name of the selector for a particular field of a struct
(define (build-selector-id struct-name field-name)
(datum->syntax-object
struct-name
(string->symbol
(string-append
(symbol->string (syntax-object->datum struct-name))
"-"
(symbol->string (syntax-object->datum field-name))))))
;; build-mutator-id : syntax syntax -> syntax
;; constructs the name of the selector for a particular field of a struct
(define (build-mutator-id struct-name field-name)
(datum->syntax-object
struct-name
(string->symbol
(string-append
"set-"
(symbol->string (syntax-object->datum struct-name))
"-"
(symbol->string (syntax-object->datum field-name))
"!"))))
;; code-for-one-id : syntax syntax syntax (union syntax #f) -> syntax
;; given the syntax for an identifier and a contract,
;; builds a begin expression for the entire contract and provide
;; the first syntax object is used for source locations
(define (code-for-one-id stx id ctrct user-rename-id)
(with-syntax ([(code id) (code-for-one-id/new-name stx id ctrct user-rename-id)])
(syntax code)))
;; code-for-one-id/new-name : syntax syntax syntax (union syntax #f) -> (values syntax syntax)
;; given the syntax for an identifier and a contract,
;; builds a begin expression for the entire contract and provide
;; the first syntax object is used for source locations
(define (code-for-one-id/new-name stx id ctrct user-rename-id)
(with-syntax ([id-rename (a:mangle-id provide-stx "provide/contract-id" id)]
[contract-id (a:mangle-id provide-stx "provide/contract-contract-id" id)]
[pos-module-source (a:mangle-id provide-stx "provide/contract-pos-module-source" id)]
[pos-stx (datum->syntax-object provide-stx 'here)]
[id id]
[ctrct ctrct])
(with-syntax ([provide-clause (if user-rename-id
(with-syntax ([user-rename-id user-rename-id])
(syntax (provide (rename id-rename user-rename-id))))
(syntax (provide (rename id-rename id))))])
(syntax/loc stx
(begin
provide-clause
;; unbound id check
(if #f id)
(define pos-module-source (module-source-as-symbol #'pos-stx))
(define contract-id (let ([id ctrct]) id))
(define-syntax id-rename
(make-set!-transformer
(lambda (stx)
(with-syntax ([neg-stx (datum->syntax-object stx 'here)])
(syntax-case stx (set!)
[(set! _ body) (raise-syntax-error
#f
"cannot set! provide/contract identifier"
stx
(syntax _))]
[(_ arg (... ...))
(syntax
((begin-lifted
(-contract contract-id
id
pos-module-source
(module-source-as-symbol #'neg-stx)
(quote-syntax _)))
arg
(... ...)))]
[_
(identifier? (syntax _))
(syntax
(begin-lifted
(-contract contract-id
id
pos-module-source
(module-source-as-symbol #'neg-stx)
(quote-syntax _))))]))))))))))
[ctrct ctrct]
[external-name (or user-rename-id id)])
(with-syntax ([code
(syntax/loc stx
(begin
(provide (rename id-rename external-name))
;; unbound id check
(if #f id)
(define pos-module-source (module-source-as-symbol #'pos-stx))
(define contract-id (let ([id ctrct]) id))
(define-syntax id-rename
(make-set!-transformer
(lambda (stx)
(with-syntax ([neg-stx (datum->syntax-object stx 'here)])
(syntax-case stx (set!)
[(set! _ body) (raise-syntax-error
#f
"cannot set! provide/contract identifier"
stx
(syntax _))]
[(_ arg (... ...))
(syntax
((begin-lifted
(-contract contract-id
id
pos-module-source
(module-source-as-symbol #'neg-stx)
(quote-syntax _)))
arg
(... ...)))]
[_
(identifier? (syntax _))
(syntax
(begin-lifted
(-contract contract-id
id
pos-module-source
(module-source-as-symbol #'neg-stx)
(quote-syntax _))))])))))))])
(syntax (code id-rename)))))
(with-syntax ([(bodies ...) (code-for-each-clause (syntax->list (syntax (p/c-ele ...))))])
(syntax

View File

@ -1318,26 +1318,44 @@
(test/spec-passed
'provide/contract4
'(let ()
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite4 mzscheme
(require (lib "contract.ss"))
(provide/contract (struct s ((a any/c))))
(define-struct s (a))))
(define-struct s (a))
(provide/contract (struct s ((a any/c))))))
(eval '(require contract-test-suite4))
(eval '(list (make-s 1)
(s-a (make-s 1))
(s? (make-s 1))
(set-s-a! (make-s 1) 2)))))
(test/spec-passed/result
'provide/contract4-b
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite4-b mzscheme
(require (lib "contract.ss"))
(define-struct s (a b))
(provide/contract (struct s ((a any/c) (b any/c))))))
(eval '(require contract-test-suite4-b))
(eval '(let ([an-s (make-s 1 2)])
(list (s-a an-s)
(s-b an-s)
(begin (set-s-a! an-s 3)
(s-a an-s))
(begin (set-s-b! an-s 4)
(s-b an-s))))))
(list 1 2 3 4))
(test/spec-passed
'provide/contract5
'(let ()
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite5 mzscheme
(require (lib "contract.ss"))
(provide/contract (struct s ((a any/c)))
(struct t ((a any/c))))
(define-struct s (a))
(define-struct t (a))))
(define-struct t (a))
(provide/contract (struct s ((a any/c)))
(struct t ((a any/c))))))
(eval '(require contract-test-suite5))
(eval '(list (make-s 1)
(s-a (make-s 1))
@ -1350,17 +1368,45 @@
(test/spec-passed
'provide/contract6
'(let ()
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite6 mzscheme
(require (lib "contract.ss"))
(provide/contract (struct s ((a any/c))))
(define-struct s (a))))
(define-struct s (a))
(provide/contract (struct s ((a any/c))))))
(eval '(require contract-test-suite6))
(eval '(define-struct (t s) ()))))
(test/spec-passed
'provide/contract6
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite6 mzscheme
(require (lib "contract.ss"))
(define-struct s (a))
(provide/contract (struct s ((a any/c))))))
(eval '(require contract-test-suite6))
(eval '(define-struct (t s) ()))))
#;
(test/spec-passed
'provide/contract6b
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite6b mzscheme
(require (lib "contract.ss"))
(provide/contract (struct s_ ((a any/c))))
(define-struct s_ (a))))
(eval '(require contract-test-suite6b))
(eval '(module contract-test-suite6b2 mzscheme
(require contract-test-suite6b)
(require (lib "contract.ss"))
(define-struct (t_ s_) (b))
(provide/contract (struct (t_ s_) ((a any/c) (b any/c))))))
(eval '(require contract-test-suite6b2))
(eval '(define-struct (u_ t_) ()))
(eval '(t_-a (make-u_ 1 2)))))
(test/spec-passed
'provide/contract7
'(let ()
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite7 mzscheme
(require (lib "contract.ss"))
(define-struct s (a b))
@ -1378,7 +1424,7 @@
(test/spec-passed
'provide/contract8
'(let ()
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite8 mzscheme
(require (lib "contract.ss"))
(define-struct i-s (contents))
@ -1389,15 +1435,48 @@
(eval '(i-s-contents (make-i-s 1)))))
(test/spec-passed
'provide/contract8
'(let ()
(eval '(module contract-test-suite8 mzscheme
'provide/contract9
'(parameterize ([current-namespace (make-namespace)])
(eval '(module contract-test-suite9 mzscheme
(require (lib "contract.ss"))
(provide/contract (rename the-internal-name the-external-name integer?))
(define the-internal-name 1)
(+ the-internal-name 1)))
(eval '(require contract-test-suite8))
(eval '(require contract-test-suite9))
(eval '(+ the-external-name 1))))
(test/spec-passed
'provide/contract10
'(parameterize ([current-namespace (make-namespace)])
(eval '(module m mzscheme
(require (lib "contract.ss"))
(define-struct s (a b) (make-inspector))
(provide/contract (struct s ((a number?) (b number?))))))
(eval '(module n mzscheme
(require (lib "struct.ss")
m)
(print-struct #t)
(copy-struct s
(make-s 1 2)
[s-a 3])))
(eval '(require n))))
(test/spec-failed
'provide/contract11
'(parameterize ([current-namespace (make-namespace)])
(eval '(module m mzscheme
(require (lib "contract.ss"))
(define-struct s (a b) (make-inspector))
(provide/contract (struct s ((a number?) (b number?))))))
(eval '(module n mzscheme
(require (lib "struct.ss")
m)
(print-struct #t)
(copy-struct s
(make-s 1 2)
[s-a #f])))
(eval '(require n)))
'n)
;