Allowing _all_ types of tagged-sig-specs in unit/c, though whether that

makes sense or not, we'll see.  Easy enough to set up, and it also sets
up the plan for a new form I'd like to add, which is why I've factored out
the syntax classes into their own file.

svn: r13570
This commit is contained in:
Stevie Strickland 2009-02-14 07:40:50 +00:00
parent 4f12a1e364
commit ebe06e9572
3 changed files with 176 additions and 173 deletions

View File

@ -0,0 +1,42 @@
#lang scheme/base
(require stxclass
"unit-compiletime.ss"
(for-template "unit-keywords.ss"))
(provide import-clause export-clause)
(define-syntax-class sig-id
#:attributes ()
(pattern x
#:declare x (static-of 'signature
(λ (x)
(signature? (set!-trans-extract x))))))
(define-syntax-class sig-spec #:literals (prefix rename only except)
#:attributes ()
#:transparent
(pattern s:sig-id)
(pattern (prefix i:identifier s:sig-spec))
(pattern (rename s:sig-spec [int:identifier ext:identifier] ...))
(pattern (only s:sig-spec i:identifier ...))
(pattern (except s:sig-spec i:identifier ...)))
(define-syntax-class tagged-sig-spec #:literals (tag)
#:attributes ()
#:transparent
(pattern s:sig-spec)
(pattern (tag i:identifier s:sig-spec)))
(define-syntax-class unit/c-clause
#:transparent
(pattern (s:tagged-sig-spec [x:identifier c:expr] ...))
(pattern s:tagged-sig-spec ;; allow a non-wrapped sig, which is the same as (sig)
#:with (x ...) null
#:with (c ...) null))
(define-syntax-class import-clause #:literals (import)
#:transparent
(pattern (import i:unit/c-clause ...)))
(define-syntax-class export-clause #:literals (export)
#:transparent
(pattern (export e:unit/c-clause ...)))

View File

@ -3,10 +3,9 @@
(require (for-syntax scheme/base
stxclass
syntax/boundmap
"unit-compiletime.ss")
"unit-compiletime.ss"
"unit-contract-syntax.ss")
scheme/contract
scheme/pretty
"unit-keywords.ss"
"unit-utils.ss"
"unit-runtime.ss")
@ -80,175 +79,136 @@
(define-for-syntax contract-exports (contract-imports/exports #f))
(define-syntax/err-param (unit/c stx)
(begin
(define-syntax-class sig-id
(pattern x
#:declare x (static-of 'signature
(λ (x)
(signature? (set!-trans-extract x))))))
(define-syntax-class unit/c-clause
#:transparent
(pattern (s:sig-id [x:identifier c:expr] ...))
(pattern s:sig-id ;; allow a non-wrapped sig-id, which is the same as (sig-id)
#:with (x ...) null
#:with (c ...) null))
(define-syntax-class import-clause #:literals (import)
#:transparent
(pattern (import i:unit/c-clause ...)))
(define-syntax-class export-clause #:literals (export)
#:transparent
(pattern (export e:unit/c-clause ...)))
(syntax-parse stx
[(_ (import i:unit/c-clause ...)
(export e:unit/c-clause ...) bad-expr . rest)
(raise-syntax-error 'unit/c
"extra form"
#'bad-expr)]
[(_ :import-clause :export-clause)
(begin
(define-values (isig tagged-import-sigs import-tagged-infos
import-tagged-sigids import-sigs)
(process-unit-import #'(i.s ...)))
(define-values (esig tagged-export-sigs export-tagged-infos
export-tagged-sigids export-sigs)
(process-unit-export #'(e.s ...)))
(define contract-table
(make-bound-identifier-mapping))
(define (process-sig name sig xs cs)
(define xs-list (syntax->list xs))
(let ([dup (check-duplicate-identifier xs-list)])
(when dup
(raise-syntax-error 'unit/c
(format "duplicate identifier found for signature ~a"
(syntax->datum name))
dup)))
(let ([ids (map car (car sig))])
(for-each (λ (id)
(unless (memf (λ (i) (bound-identifier=? id i)) ids)
(raise-syntax-error 'unit/c
(format "identifier not member of signature ~a"
(syntax-e name))
id)))
xs-list))
(for ([x (in-list xs-list)]
[c (in-list (syntax->list cs))])
(bound-identifier-mapping-put! contract-table x c)))
(check-duplicate-sigs import-tagged-infos isig null null)
(check-duplicate-subs export-tagged-infos esig)
(check-unit-ie-sigs import-sigs export-sigs)
(for-each process-sig
isig
import-sigs
(syntax->list #'((i.x ...) ...))
(syntax->list #'((i.c ...) ...)))
(for-each process-sig
esig
export-sigs
(syntax->list #'((e.x ...) ...))
(syntax->list #'((e.c ...) ...)))
(with-syntax ([((import-key ...) ...)
(map tagged-info->keys import-tagged-infos)]
[((export-key ...) ...)
(map tagged-info->keys export-tagged-infos)]
[(import-name ...)
(map (lambda (tag/info) (car (siginfo-names (cdr tag/info))))
import-tagged-infos)]
[(export-name ...)
(map (lambda (tag/info) (car (siginfo-names (cdr tag/info))))
export-tagged-infos)])
(quasisyntax/loc stx
(begin
(make-proj-contract
(list 'unit/c
(cons 'import
(list (cons 'i.s
(map list (list 'i.x ...)
(build-compound-type-name 'i.c ...)))
...))
(cons 'export
(list (cons 'e.s
(map list (list 'e.x ...)
(build-compound-type-name 'e.c ...)))
...)))
(λ (pos neg src-info name)
(λ (unit-tmp)
(unless (unit? unit-tmp)
(raise-contract-error unit-tmp src-info pos name
"value is not a unit"))
(contract-check-sigs
unit-tmp
(vector-immutable
(cons 'import-name
(vector-immutable import-key ...)) ...)
(vector-immutable
(cons 'export-name
(vector-immutable export-key ...)) ...)
src-info pos name)
(make-unit
#f
(vector-immutable (cons 'import-name
(vector-immutable import-key ...)) ...)
(vector-immutable (cons 'export-name
(vector-immutable export-key ...)) ...)
(unit-deps unit-tmp)
(λ ()
(let-values ([(unit-fn export-table) ((unit-go unit-tmp))])
(values (lambda (import-table)
(unit-fn #,(contract-imports
#'import-table
import-tagged-infos
import-sigs
contract-table
#'pos
#'neg
#'src-info
#'name)))
#,(contract-exports
#'export-table
export-tagged-infos
export-sigs
contract-table
#'pos
#'neg
#'src-info
#'name)))))))
(λ (v)
(and (unit? v)
(with-handlers ([exn:fail:contract? (λ () #f)])
(contract-check-sigs
v
(vector-immutable
(cons 'import-name
(vector-immutable import-key ...)) ...)
(vector-immutable
(cons 'export-name
(vector-immutable export-key ...)) ...)
(list #f "not-used") 'not-used null))
#t)))))))]
[(_ (import i:unit/c-clause ...) bad-e . body)
(raise-syntax-error 'unit/c
"expected an export description"
#'bad-e)]
[(_ (import i:unit/c-clause ...))
(raise-syntax-error 'unit/c
"expected an export description"
stx)]
[(_ bad-i . rest)
(raise-syntax-error 'unit/c
"expected an import description"
#'bad-i)]
[(_)
(raise-syntax-error 'unit/c
"expected an import description"
stx)])))
(syntax-parse stx
[(_ :import-clause :export-clause)
(begin
(define-values (isig tagged-import-sigs import-tagged-infos
import-tagged-sigids import-sigs)
(process-unit-import #'(i.s ...)))
(define-values (esig tagged-export-sigs export-tagged-infos
export-tagged-sigids export-sigs)
(process-unit-export #'(e.s ...)))
(define contract-table
(make-bound-identifier-mapping))
(define (process-sig name sig xs cs)
(define xs-list (syntax->list xs))
(let ([dup (check-duplicate-identifier xs-list)])
(when dup
(raise-syntax-error 'unit/c
(format "duplicate identifier found for signature ~a"
(syntax->datum name))
dup)))
(let ([ids (map car (car sig))])
(for-each (λ (id)
(unless (memf (λ (i) (bound-identifier=? id i)) ids)
(raise-syntax-error 'unit/c
(format "identifier not member of signature ~a"
(syntax-e name))
id)))
xs-list))
(for ([x (in-list xs-list)]
[c (in-list (syntax->list cs))])
(bound-identifier-mapping-put! contract-table x c)))
(check-duplicate-sigs import-tagged-infos isig null null)
(check-duplicate-subs export-tagged-infos esig)
(check-unit-ie-sigs import-sigs export-sigs)
(for-each process-sig
isig
import-sigs
(syntax->list #'((i.x ...) ...))
(syntax->list #'((i.c ...) ...)))
(for-each process-sig
esig
export-sigs
(syntax->list #'((e.x ...) ...))
(syntax->list #'((e.c ...) ...)))
(with-syntax ([((import-key ...) ...)
(map tagged-info->keys import-tagged-infos)]
[((export-key ...) ...)
(map tagged-info->keys export-tagged-infos)]
[(import-name ...)
(map (lambda (tag/info) (car (siginfo-names (cdr tag/info))))
import-tagged-infos)]
[(export-name ...)
(map (lambda (tag/info) (car (siginfo-names (cdr tag/info))))
export-tagged-infos)])
(quasisyntax/loc stx
(begin
(make-proj-contract
(list 'unit/c
(cons 'import
(list (cons 'isig
(map list (list 'i.x ...)
(build-compound-type-name 'i.c ...)))
...))
(cons 'export
(list (cons 'esig
(map list (list 'e.x ...)
(build-compound-type-name 'e.c ...)))
...)))
(λ (pos neg src-info name)
(λ (unit-tmp)
(unless (unit? unit-tmp)
(raise-contract-error unit-tmp src-info pos name
"value is not a unit"))
(contract-check-sigs
unit-tmp
(vector-immutable
(cons 'import-name
(vector-immutable import-key ...)) ...)
(vector-immutable
(cons 'export-name
(vector-immutable export-key ...)) ...)
src-info pos name)
(make-unit
#f
(vector-immutable (cons 'import-name
(vector-immutable import-key ...)) ...)
(vector-immutable (cons 'export-name
(vector-immutable export-key ...)) ...)
(unit-deps unit-tmp)
(λ ()
(let-values ([(unit-fn export-table) ((unit-go unit-tmp))])
(values (lambda (import-table)
(unit-fn #,(contract-imports
#'import-table
import-tagged-infos
import-sigs
contract-table
#'pos
#'neg
#'src-info
#'name)))
#,(contract-exports
#'export-table
export-tagged-infos
export-sigs
contract-table
#'pos
#'neg
#'src-info
#'name)))))))
(λ (v)
(and (unit? v)
(with-handlers ([exn:fail:contract? (λ () #f)])
(contract-check-sigs
v
(vector-immutable
(cons 'import-name
(vector-immutable import-key ...)) ...)
(vector-immutable
(cons 'export-name
(vector-immutable export-key ...)) ...)
(list #f "not-used") 'not-used null))
#t)))))))]))
(define (contract-check-helper sub-sig super-sig import? val src-info blame ctc)
(define t (make-hash))

View File

@ -635,7 +635,8 @@ Expands to a @scheme[provide] of all identifiers implied by the
@defform/subs[#:literals (import export)
(unit/c (import sig-block ...) (export sig-block ...))
([sig-block (sig-id [id contract] ...) sig-id])]{
([sig-block (tagged-sig-spec [id contract] ...)
tagged-sig-spec])]{
A @deftech{unit contract} wraps a unit and checks both its imported and
exported identifiers to ensure that they match the appropriate contracts.