merged units branch

svn: r5033

original commit: 3459c3a58f1cdc52fbc916acf306b29408468912
This commit is contained in:
Eli Barzilay 2006-12-05 20:31:14 +00:00
parent 187a45b1ab
commit 5401208e73
43 changed files with 3494 additions and 1941 deletions

View File

@ -0,0 +1,29 @@
(module a-signature mzscheme
(require-for-syntax "private/unit-compiletime.ss"
"private/unit-syntax.ss")
(require "unit.ss")
(provide (rename module-begin #%module-begin)
(all-from-except mzscheme #%module-begin)
(all-from "unit.ss"))
(define-for-syntax (make-name s)
(string->symbol
(string-append (regexp-replace "-sig$" (symbol->string s) "")
"^")))
(define-syntax (module-begin stx)
(parameterize ((error-syntax stx))
(with-syntax ((name (make-name (syntax-property stx 'enclosing-module-name))))
(syntax-case stx ()
((_ . x)
(with-syntax ((((reqs ...) . (body ...))
(split-requires (checked-syntax->list #'x))))
(datum->syntax-object
stx
(syntax-e #'(#%module-begin
reqs ...
(provide name)
(define-signature name (body ...))))
stx))))))))

28
collects/mzlib/a-unit.ss Normal file
View File

@ -0,0 +1,28 @@
(module a-unit mzscheme
(require-for-syntax "private/unit-compiletime.ss"
"private/unit-syntax.ss")
(require "unit.ss")
(provide (rename module-begin #%module-begin)
(all-from-except mzscheme #%module-begin)
(all-from "unit.ss"))
(define-for-syntax (make-name s)
(string->symbol
(string-append (regexp-replace "-unit$" (symbol->string s) "")
"@")))
(define-syntax (module-begin stx)
(parameterize ((error-syntax stx))
(with-syntax ((name (make-name (syntax-property stx 'enclosing-module-name))))
(syntax-case stx ()
((_ . x)
(with-syntax ((((reqs ...) . (body ...))
(split-requires (checked-syntax->list #'x))))
(datum->syntax-object
stx
(syntax-e #'(#%module-begin
reqs ...
(provide name)
(define-unit name body ...)))
stx))))))))

View File

@ -12,7 +12,7 @@
(provide deflate gzip-through-ports gzip)
(require "unit.ss")
(require "unit200.ss")
(define-syntax INSERT_STRING
(syntax-rules ()

View File

@ -1,7 +1,7 @@
(module sigmatch mzscheme
(require "../unit.ss")
(require "../unit200.ss")
(define (hash-sig src-sig table)
(and (pair? src-sig)

View File

@ -8,7 +8,7 @@
(lib "context.ss" "syntax"))
(require "sigmatch.ss")
(require "../unit.ss")
(require "../unit200.ss")
(require "../list.ss")
(define-struct signature (name ; sym

View File

@ -0,0 +1,26 @@
(module unit-exptime mzscheme
(require "private/unit-syntax.ss"
"private/unit-compiletime.ss")
(provide unit-static-signatures
signature-members)
(define (unit-static-signatures name err-stx)
(parameterize ((error-syntax err-stx))
(let ((ui (lookup-def-unit name)))
(values (apply list-immutable (unit-info-import-sig-ids ui))
(apply list-immutable (unit-info-export-sig-ids ui))))))
(define (signature-members name err-stx)
(parameterize ((error-syntax err-stx))
(let ([s (lookup-signature name)])
(values
;; extends:
(and (pair? (cdr (siginfo-names (signature-siginfo s))))
(cadr (siginfo-names (signature-siginfo s))))
;; vars
(apply list-immutable (signature-vars s))
;; defined vars
(apply list-immutable (apply append (map car (signature-val-defs s))))
;; defined stxs
(apply list-immutable (apply append (map car (signature-stx-defs s)))))))))

File diff suppressed because it is too large Load Diff

869
collects/mzlib/unit200.ss Normal file
View File

@ -0,0 +1,869 @@
;; Unit system
(module unit200 mzscheme
(require-for-syntax (lib "kerncase.ss" "syntax")
(lib "stx.ss" "syntax")
(lib "name.ss" "syntax")
(lib "context.ss" "syntax")
"list.ss"
"private/unitidmap.ss")
;; ----------------------------------------------------------------------
;; Structures and helpers
(define undefined (letrec ([x x]) x)) ; initial value
(define insp (current-inspector)) ; for named structures
(define-struct unit (num-imports exports go)) ; unit value
(define-struct (exn:fail:unit exn:fail) ()) ; run-time exception
;; For units with inferred names, generate a struct that prints using the name:
(define (make-naming-constructor type name)
(let-values ([(struct: make- ? -accessor -mutator)
(make-struct-type name type 0 0 #f null insp)])
make-))
;; Make a unt value (call by the macro expansion of `unit')
(define (make-a-unit name num-imports exports go)
((if name
(make-naming-constructor
struct:unit
(string->symbol (format "unit:~a" name)))
make-unit)
num-imports exports go))
;; ----------------------------------------------------------------------
;; The `unit' syntactic form
(define-syntaxes (:unit unit/no-expand)
(let ([do-unit
(lambda (stx expand?)
(syntax-case stx (import export)
[(_ (import ivar ...)
(export evar ...)
defn&expr ...)
(let ([check-id (lambda (v)
(unless (identifier? v)
(raise-syntax-error
#f
"import is not an identifier"
stx
v)))]
[check-renamed-id
(lambda (v)
(syntax-case v ()
[id (identifier? (syntax id)) (list v)]
[(lid eid) (and (identifier? (syntax lid))
(identifier? (syntax eid)))
(list #'lid #'eid)]
[else (raise-syntax-error
#f
"export is not an identifier or renamed identifier"
stx
v)]))]
[expand-context (generate-expand-context)]
[def-ctx (and expand?
(syntax-local-make-definition-context))]
[localify (lambda (ids def-ctx)
(if (andmap identifier? ids)
;; In expand mode, add internal defn context
(if expand?
(begin
;; Treat imports as internal-defn names:
(syntax-local-bind-syntaxes ids #f def-ctx)
(cdr (syntax->list
(local-expand #`(stop #,@ids)
'expression
(list #'stop)
def-ctx))))
ids)
;; Let later checking report an error:
ids))])
(let ([ivars (localify (syntax->list (syntax (ivar ...))) def-ctx)]
[evars (syntax->list (syntax (evar ...)))])
(for-each check-id ivars)
(for-each check-renamed-id evars)
;; Get import/export declared names:
(let* ([exported-names
(localify
(map (lambda (v)
(syntax-case v ()
[(lid eid) (syntax lid)]
[id (syntax id)]))
evars)
def-ctx)]
[extnames (map (lambda (v)
(syntax-case v ()
[(lid eid) (syntax eid)]
[id (syntax id)]))
evars)]
[imported-names ivars]
[declared-names (append imported-names exported-names)])
;; Check that all exports are distinct (as symbols)
(let ([ht (make-hash-table)])
(for-each (lambda (name)
(when (hash-table-get ht (syntax-e name) (lambda () #f))
(raise-syntax-error
#f
"duplicate export"
stx
name))
(hash-table-put! ht (syntax-e name) #t))
extnames))
;; Expand all body expressions
;; so that all definitions are exposed.
(letrec ([expand-all
(if expand?
(lambda (defns&exprs)
(apply
append
(map
(lambda (defn-or-expr)
(let ([defn-or-expr
(local-expand
defn-or-expr
expand-context
(append
(kernel-form-identifier-list (quote-syntax here))
declared-names)
def-ctx)])
(syntax-case defn-or-expr (begin define-values define-syntaxes)
[(begin . l)
(let ([l (syntax->list (syntax l))])
(unless l
(raise-syntax-error
#f
"bad syntax (illegal use of `.')"
defn-or-expr))
(expand-all (map (lambda (s)
(syntax-track-origin s defn-or-expr #'begin))
l)))]
[(define-syntaxes (id ...) rhs)
(andmap identifier? (syntax->list #'(id ...)))
(with-syntax ([rhs (local-transformer-expand
#'rhs
'expression
null)])
(syntax-local-bind-syntaxes (syntax->list #'(id ...)) #'rhs def-ctx)
(list #'(define-syntaxes (id ...) rhs)))]
[(define-values (id ...) rhs)
(andmap identifier? (syntax->list #'(id ...)))
(begin
(syntax-local-bind-syntaxes (syntax->list #'(id ...)) #f def-ctx)
(list defn-or-expr))]
[else (list defn-or-expr)])))
defns&exprs)))
values)])
(let ([all-expanded (expand-all (syntax->list (syntax (defn&expr ...))))])
;; Get all the defined names, sorting out variable definitions
;; from syntax definitions.
(let* ([definition?
(lambda (id)
(and (identifier? id)
(or (module-identifier=? id (quote-syntax define-values))
(module-identifier=? id (quote-syntax define-syntaxes)))))]
[all-defined-names/kinds
(apply
append
(map
(lambda (defn-or-expr)
(syntax-case defn-or-expr (define-values define-syntaxes)
[(dv (id ...) expr)
(definition? (syntax dv))
(let ([l (syntax->list (syntax (id ...)))])
(for-each (lambda (i)
(unless (identifier? i)
(raise-syntax-error
#f
"not an identifier in definition"
defn-or-expr
i)))
l)
(let ([key (if (module-identifier=? (syntax dv) (quote-syntax define-syntaxes))
'stx
'val)])
(map (lambda (id) (cons key id)) l)))]
[(define-values . l)
(raise-syntax-error
#f
"bad definition form"
defn-or-expr)]
[(define-syntaxes . l)
(raise-syntax-error
#f
"bad syntax definition form"
defn-or-expr)]
[else null]))
all-expanded))]
[all-defined-names (map cdr all-defined-names/kinds)]
[all-defined-val-names (map cdr
(filter (lambda (i) (eq? (car i) 'val))
all-defined-names/kinds))])
;; Check that all defined names (var + stx) are distinct:
(let ([name (check-duplicate-identifier
(append imported-names all-defined-names))])
(when name
(raise-syntax-error
#f
"variable imported and/or defined twice"
stx
name)))
;; Check that all exported names are defined (as var):
(let ([ht (make-hash-table)]
[stx-ht (make-hash-table)])
(for-each
(lambda (kind+name)
(let ([name (cdr kind+name)])
(let ([l (hash-table-get ht (syntax-e name) (lambda () null))])
(hash-table-put! (if (eq? (car kind+name) 'val) ht stx-ht)
(syntax-e name)
(cons name l)))))
all-defined-names/kinds)
(for-each
(lambda (n)
(let ([v (hash-table-get ht (syntax-e n) (lambda () null))])
(unless (ormap (lambda (i) (bound-identifier=? i n)) v)
;; Either not defined, or defined as syntax:
(let ([stx-v (hash-table-get stx-ht (syntax-e n) (lambda () null))])
(if (ormap (lambda (i) (bound-identifier=? i n)) stx-v)
(raise-syntax-error
#f
"cannot export syntax from a unit"
stx
n)
(raise-syntax-error
#f
"exported variable is not defined"
stx
n))))))
exported-names))
;; Compute defined but not exported:
(let ([ht (make-hash-table)])
(for-each
(lambda (name)
(let ([l (hash-table-get ht (syntax-e name) (lambda () null))])
(hash-table-put! ht (syntax-e name) (cons name l))))
exported-names)
(let ([internal-names
(let loop ([l all-defined-val-names])
(cond
[(null? l) null]
[(let ([v (hash-table-get ht (syntax-e (car l)) (lambda () null))])
(ormap (lambda (i) (bound-identifier=? i (car l))) v))
(loop (cdr l))]
[else (cons (car l) (loop (cdr l)))]))])
;; Generate names for import/export boxes, etc:
(with-syntax ([(ivar ...) ivars]
[(iloc ...) (generate-temporaries ivars)]
[(eloc ...) (generate-temporaries evars)]
[(extname ...) extnames]
[(expname ...) exported-names]
[(intname ...) internal-names])
;; Change all definitions to set!s. Convert evars to set-box!,
;; because set! on exported variables is not allowed.
(with-syntax ([(defn&expr ...)
(let ([elocs (syntax->list (syntax (eloc ...)))])
(filter
values
(map (lambda (defn-or-expr)
(syntax-case defn-or-expr (define-values define-syntaxes)
[(define-values ids expr)
(let* ([ids (syntax->list (syntax ids))])
(if (null? ids)
(syntax/loc defn-or-expr (set!-values ids expr))
(let ([do-one
(lambda (id tmp name)
(let loop ([evars exported-names]
[elocs elocs])
(cond
[(null? evars)
;; not an exported id
(with-syntax ([id id][tmp tmp])
(syntax/loc
defn-or-expr
(set! id tmp)))]
[(bound-identifier=? (car evars) id)
;; set! exported id:
(with-syntax
([loc (car elocs)]
[tmp
(if name
(with-syntax
([tmp tmp]
[name name])
(syntax
(let ([name tmp])
name)))
tmp)])
(syntax/loc defn-or-expr
(set-box! loc tmp)))]
[else (loop (cdr evars)
(cdr elocs))])))])
(if (null? (cdr ids))
(do-one (car ids) (syntax expr) (car ids))
(let ([tmps (generate-temporaries ids)])
(with-syntax ([(tmp ...) tmps]
[(set ...)
(map (lambda (id tmp)
(do-one id tmp #f))
ids tmps)])
(syntax/loc defn-or-expr
(let-values ([(tmp ...) expr])
set ...))))))))]
[(define-syntaxes . l) #f]
[else defn-or-expr]))
all-expanded)))]
[(stx-defn ...)
(filter
values
(map (lambda (defn-or-expr)
(syntax-case defn-or-expr (define-syntaxes)
[(define-syntaxes . l) #'l]
[else #f]))
all-expanded))])
;; Build up set! redirection chain:
(with-syntax ([redirections
(let ([varlocs
(syntax->list
(syntax ((ivar iloc) ... (expname eloc) ...)))])
(with-syntax ([vars (map stx-car varlocs)]
[rhss
(map
(lambda (varloc)
(with-syntax ([(var loc) varloc])
(syntax
(make-id-mapper (quote-syntax (unbox loc))
(quote-syntax var)))))
varlocs)])
(syntax
([vars (values . rhss)]))))]
[num-imports (datum->syntax-object
(quote-syntax here)
(length (syntax->list (syntax (iloc ...))))
#f)]
[name (syntax-local-infer-name stx)])
(syntax/loc stx
(make-a-unit
'name
num-imports
(list (quote extname) ...)
(lambda ()
(let ([eloc (box undefined)] ...)
(list (vector eloc ...)
(lambda (iloc ...)
(letrec-syntaxes+values
(stx-defn ... . redirections)
([(intname) undefined] ...)
(void) ; in case the body would be empty
defn&expr ...))))))))))))))))))]))])
(values (lambda (stx) (do-unit stx #t))
(lambda (stx) (do-unit stx #f)))))
;; ----------------------------------------------------------------------
;; check-expected-interface: used by the expansion of `compound-unit'
(define (check-expected-interface tag unit num-imports exports)
(unless (unit? unit)
(raise
(make-exn:fail:unit
(string->immutable-string
(format "compound-unit: result of expression for tag ~s not a unit: ~e" tag unit))
(current-continuation-marks))))
(unless (= num-imports (unit-num-imports unit))
(raise
(make-exn:fail:unit
(string->immutable-string
(format "compound-unit: unit for tag ~s expects ~a imports, given ~a"
tag
(unit-num-imports unit)
num-imports))
(current-continuation-marks))))
(list->vector
(map (lambda (ex)
(let loop ([l (unit-exports unit)][i 0])
(cond
[(null? l)
(raise
(make-exn:fail:unit
(string->immutable-string
(format "compound-unit: unit for tag ~s has no ~s export"
tag ex))
(current-continuation-marks)))]
[(eq? (car l) ex)
i]
[else (loop (cdr l) (add1 i))])))
exports)))
;; ----------------------------------------------------------------------
;; The `compound-unit' syntactic form
(define-syntax compound-unit
(lambda (stx)
(syntax-case stx (import export link)
[(_ (import ivar ...)
(link [tag (unit-expr linkage ...)] ...)
(export exportage ...))
(let ([check-id (lambda (v)
(unless (identifier? v)
(raise-syntax-error
#f
"import is not an identifier"
stx
v)))]
[check-tag (lambda (v)
(unless (identifier? v)
(raise-syntax-error
#f
"tag is not an identifier"
stx
v)))]
[check-linkage (lambda (v)
(syntax-case v ()
[id (identifier? (syntax id)) #t]
[(tag id ...)
(for-each (lambda (v)
(unless (identifier? v)
(raise-syntax-error
#f
"non-identifier in linkage"
stx
v)))
(syntax->list v))]
[else
(raise-syntax-error
#f
"ill-formed linkage"
stx
v)]))]
[check-exportage (lambda (v)
(syntax-case v ()
[(tag ex ...)
(begin
(unless (identifier? (syntax tag))
(raise-syntax-error
#f
"export tag is not an identifier"
stx
(syntax tag)))
(for-each
(lambda (e)
(syntax-case e ()
[id (identifier? (syntax id)) #t]
[(iid eid)
(begin
(unless (identifier? (syntax iid))
(raise-syntax-error
#f
"export internal name is not an identifier"
stx
(syntax iid)))
(unless (identifier? (syntax eid))
(raise-syntax-error
#f
"export internal name is not an identifier"
stx
(syntax eid))))]
[else
(raise-syntax-error
#f
(format "ill-formed export with tag ~a"
(syntax-e (syntax tag)))
stx
e)]))
(syntax->list (syntax (ex ...)))))]
[else
(raise-syntax-error
#f
"ill-formed export"
stx
v)]))]
[imports (syntax->list (syntax (ivar ...)))]
[tags (syntax->list (syntax (tag ...)))]
[linkages (map syntax->list (syntax->list (syntax ((linkage ...) ...))))]
[exports (syntax->list (syntax (exportage ...)))])
;; Syntax checks:
(for-each check-id imports)
(for-each check-tag tags)
(for-each (lambda (l) (for-each check-linkage l)) linkages)
(for-each check-exportage exports)
;; Check for duplicate imports
(let ([dup (check-duplicate-identifier imports)])
(when dup
(raise-syntax-error
#f
"duplicate import"
stx
dup)))
;; Check for duplicate tags
(let ([dup (check-duplicate-identifier tags)])
(when dup
(raise-syntax-error
#f
"duplicate tag"
stx
dup)))
;; Check referenced imports and tags
(let ([check-linkage-refs (lambda (v)
(syntax-case v ()
[(tag . exs)
(unless (ormap (lambda (t)
(bound-identifier=? t (syntax tag)))
tags)
(raise-syntax-error
#f
"linkage tag is not bound"
stx
(syntax tag)))]
[id (unless (ormap (lambda (i)
(bound-identifier=? i (syntax id)))
imports)
(raise-syntax-error
#f
"no imported identified for linkage"
stx
(syntax id)))]))]
[check-export-refs (lambda (v)
(syntax-case v ()
[(tag . r)
(unless (ormap (lambda (t)
(bound-identifier=? t (syntax tag)))
tags)
(raise-syntax-error
#f
"export tag is not bound"
stx
(syntax tag)))]))])
(for-each (lambda (l) (for-each check-linkage-refs l))
linkages)
(for-each check-export-refs exports)
;; Get all export names, and check for duplicates
(let ([export-names
(apply
append
(map
(lambda (v)
(syntax-case v ()
[(tag . exs)
(map
(lambda (e)
(syntax-case e ()
[(iid eid) (syntax eid)]
[id e]))
(syntax->list (syntax exs)))]))
exports))])
(let ([dup (check-duplicate-identifier export-names)])
(when dup
(raise-syntax-error
#f
"duplicate export"
stx
dup)))
(let ([constituents (generate-temporaries tags)]
[unit-export-positionss (generate-temporaries tags)]
[unit-setups (generate-temporaries tags)]
[unit-extracts (generate-temporaries tags)]
[unit-export-lists
;; For each tag, get all expected exports
(let* ([hts (map (lambda (x) (make-hash-table)) tags)]
[get-add-name
(lambda (tag)
(ormap (lambda (t ht)
(and (bound-identifier=? t tag)
(lambda (name)
(hash-table-put! ht (syntax-e name) name))))
tags hts))])
;; Walk though linkages
(for-each
(lambda (linkage-list)
(for-each
(lambda (linkage)
(syntax-case linkage ()
[(tag . ids)
(let ([add-name (get-add-name (syntax tag))])
(for-each add-name (syntax->list (syntax ids))))]
[else (void)]))
linkage-list))
linkages)
;; Walk through exports
(for-each
(lambda (v)
(syntax-case v ()
[(tag . exs)
(let ([add-name (get-add-name (syntax tag))])
(for-each
(lambda (e)
(syntax-case e ()
[(iid eid) (add-name (syntax iid))]
[id (add-name (syntax id))]))
(syntax->list (syntax exs))))]))
exports)
;; Extract names from hash tables
(map (lambda (ht)
(hash-table-map ht (lambda (k v) v)))
hts))])
;; Map exports to imports and indices based on expected unit exports
(let ([map-tag (lambda (t l)
(let loop ([tags tags][l l])
(if (bound-identifier=? (car tags) t)
(car l)
(loop (cdr tags) (cdr l)))))]
[unit-export-hts (map (lambda (export-list)
(let ([ht (make-hash-table)])
(let loop ([l export-list][p 0])
(unless (null? l)
(hash-table-put! ht (syntax-e (car l)) p)
(loop (cdr l) (add1 p))))
ht))
unit-export-lists)]
[interned-integer-lists null]
[interned-id-lists null])
(let ([make-mapping
(lambda (v)
(syntax-case v ()
[(tag . exs)
(let ([extract (map-tag (syntax tag)
unit-extracts)]
[ht (map-tag (syntax tag)
unit-export-hts)])
(with-syntax ([extract extract]
[pos-name
(let ([il
(map
(lambda (e)
(hash-table-get
ht
(syntax-e
(syntax-case e ()
[(iid eid) (syntax iid)]
[id e]))))
(syntax->list (syntax exs)))])
(or (ormap (lambda (i)
(and (equal? il (cadadr i))
(car i)))
interned-integer-lists)
(let ([name (car (generate-temporaries
(list (syntax tag))))])
(set! interned-integer-lists
(cons `(,name ',il)
interned-integer-lists))
name)))])
(syntax (map extract pos-name))))]
[import v]))]
[collapse (lambda (l)
(let loop ([l l])
(cond
[(null? l) null]
[(identifier? (car l))
(let-values ([(ids rest)
(let loop ([l l][ids null])
(if (or (null? l)
(not (identifier? (car l))))
(values (reverse ids) l)
(loop (cdr l) (cons (car l) ids))))])
(let ([name
(let ([id-syms (map syntax-e ids)])
(or (ormap (lambda (i)
(and (equal? id-syms (cadr i))
(car i)))
interned-id-lists)
(let ([name
(car (generate-temporaries (list 'ids)))])
(set! interned-id-lists
(cons (list* name id-syms ids)
interned-id-lists))
name)))])
(cons name
(loop rest))))]
[else (cons (car l) (loop (cdr l)))])))])
(let ([export-mapping (collapse (map make-mapping exports))]
[import-mappings (map (lambda (linkage-list)
(collapse
(map make-mapping linkage-list)))
linkages)])
(with-syntax ([(constituent ...) constituents]
[(unit-export-positions ...) unit-export-positionss]
[(unit-setup ...) unit-setups]
[(unit-extract ...) unit-extracts]
[interned-integer-lists interned-integer-lists]
[interned-id-lists (map (lambda (i)
(with-syntax ([name (car i)]
[ids (cddr i)])
(syntax [name (list . ids)])))
interned-id-lists)]
[(unit-export-list ...) unit-export-lists]
[(import-mapping ...) import-mappings]
[(unit-import-count ...)
(map (lambda (l)
(datum->syntax-object
(quote-syntax here)
(apply
+
(map (lambda (v)
(if (identifier? v)
1
(length (cdr (syntax->list v)))))
l))
#f))
linkages)]
[num-imports (datum->syntax-object
(quote-syntax here)
(length imports)
#f)]
[export-names export-names]
[export-mapping export-mapping]
[name (syntax-local-infer-name stx)])
(syntax/loc
stx
(let ([constituent unit-expr]
...)
(let ([unit-export-positions
(check-expected-interface
'tag
constituent
unit-import-count
'unit-export-list)]
...)
(make-a-unit
'name
num-imports
(quote export-names)
(lambda ()
(let ([unit-setup ((unit-go constituent))] ...)
(let ([unit-extract
(lambda (pos)
(vector-ref (car unit-setup)
(vector-ref unit-export-positions pos)))]
...
.
interned-integer-lists)
(list (list->vector (append . export-mapping))
(lambda (ivar ...)
(let interned-id-lists
(void) ;; in case there are no units
(apply (list-ref unit-setup 1)
(append . import-mapping))
...))))))))))))))))))])))
;; ----------------------------------------------------------------------
;; check-unit: used by the expansion of `invoke-unit'
(define (check-unit u n)
(unless (unit? u)
(raise
(make-exn:fail:unit
(string->immutable-string
(format "invoke-unit: result of unit expression was not a unit: ~e" u))
(current-continuation-marks))))
(unless (= (unit-num-imports u) n)
(raise
(make-exn:fail:unit
(string->immutable-string
(format "invoke-unit: expected a unit with ~a imports, given one with ~a imports"
n (unit-num-imports u)))
(current-continuation-marks)))))
;; ----------------------------------------------------------------------
;; The `invoke-unit' syntactic form
(define-syntax invoke-unit
(lambda (stx)
(syntax-case stx (import export)
[(_ unit-expr expr ...)
(let ([exprs (syntax (expr ...))])
(with-syntax ([(bx ...) (generate-temporaries (syntax (expr ...)))]
[num (datum->syntax-object
(quote-syntax here)
(length (syntax->list exprs))
#f)])
(syntax/loc
stx
(let ([u unit-expr])
(check-unit u num)
(let ([bx (box expr)] ...)
((list-ref ((unit-go u)) 1)
bx ...))))))])))
(define-syntaxes (define-values/invoke-unit
namespace-variable-bind/invoke-unit)
(let ([mk
(lambda (global?)
(lambda (stx)
(syntax-case stx ()
[(_ exports unite . prefix+imports)
(let* ([badsyntax (lambda (s why)
(raise-syntax-error
#f
(format "bad syntax (~a)" why)
stx
s))]
[symcheck (lambda (s)
(or (identifier? s)
(badsyntax s "not an identifier")))])
(unless (stx-list? (syntax exports))
(badsyntax (syntax exports) "not a sequence of identifiers"))
(for-each symcheck (syntax->list (syntax exports)))
(let ([prefix (if (stx-null? (syntax prefix+imports))
#f
(stx-car (syntax prefix+imports)))])
(unless (or (not prefix)
(not (syntax-e prefix))
(identifier? prefix))
(badsyntax prefix "prefix is not an identifier"))
(for-each symcheck (let ([v (syntax prefix+imports)])
(cond
[(stx-null? v) null]
[(stx-list? v) (cdr (syntax->list v))]
[else
(badsyntax (syntax prefix+imports) "illegal use of `.'")])))
(with-syntax ([(tagged-export ...)
(if (and prefix (syntax-e prefix))
(let ([prefix (string-append
(symbol->string
(syntax-e prefix))
":")])
(map (lambda (s)
(datum->syntax-object
s
(string->symbol
(string-append
prefix
(symbol->string (syntax-e s))))
s))
(syntax->list (syntax exports))))
(syntax exports))]
[extract-unit (syntax (:unit
(import . exports)
(export)
(values . exports)))])
(with-syntax ([invoke-unit (with-syntax ([(x . imports)
(if prefix
(syntax prefix+imports)
`(#f))])
(syntax (invoke-unit
(compound-unit
(import . imports)
(link [unit-to-invoke (unite . imports)]
[export-extractor
(extract-unit (unit-to-invoke . exports))])
(export))
. imports)))])
(if global?
(syntax (let-values ([(tagged-export ...) invoke-unit])
(namespace-set-variable-value! 'tagged-export tagged-export)
...
(void)))
(syntax (define-values (tagged-export ...) invoke-unit)))))))])))])
(values (mk #f) (mk #t))))
(provide (rename :unit unit) unit/no-expand
compound-unit invoke-unit unit?
(struct exn:fail:unit ())
define-values/invoke-unit
namespace-variable-bind/invoke-unit))

View File

@ -1,360 +1,4 @@
;; This implementation of `unit/sig' was ported from the old v100
;; implementation, and then hacked a bit to produce more compact
;; output, and finally mangled to handle the v200 `struct' (with
;; compile-time information). It's in dire need of an overhaul.
(module unitsig mzscheme
(require "unit.ss")
(require "private/sigmatch.ss")
(require-for-syntax "private/sigutil.ss")
(require-for-syntax "private/sigmatch.ss")
(require-for-syntax (lib "kerncase.ss" "syntax"))
(define-struct signed-unit (unit imports exports))
(define-syntax define-signature
(lambda (expr)
(syntax-case expr ()
[(_ name sig)
(identifier? (syntax name))
(let ([sig (get-sig 'define-signature expr (syntax-e (syntax name))
(syntax sig) #f)])
(with-syntax ([content (explode-sig sig #f)])
(syntax (define-syntax name
(make-sig (quote content))))))])))
(define-syntax let-signature
(lambda (expr)
(syntax-case expr ()
[(_ name sig . body)
(identifier? (syntax name))
(let ([sig (get-sig 'let-signature expr (syntax-e (syntax name))
(syntax sig) #f)])
(with-syntax ([content (explode-sig sig #f)])
(syntax (letrec-syntax ([name (make-sig (quote content))])
. body))))])))
(define-syntax unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ sig . rest)
(let ([sig (get-sig 'unit/sig expr #f (syntax sig) #f)])
(let ([a-unit (parse-unit expr (syntax rest) sig
(kernel-form-identifier-list (quote-syntax here))
(quote-syntax define-values)
(quote-syntax define-syntaxes)
(quote-syntax begin))])
(check-signature-unit-body sig a-unit (parsed-unit-renames a-unit) 'unit/sig expr)
(with-syntax ([imports (parsed-unit-import-vars a-unit)]
[exports (datum->syntax-object
expr
(let ([vars (make-hash-table)])
(for-each (lambda (var)
(hash-table-put! vars (syntax-e var) var))
(parsed-unit-vars a-unit))
(map
(lambda (name)
(list (let ([name (do-rename name (parsed-unit-renames a-unit))])
(hash-table-get vars name name))
name))
(signature-vars sig)))
expr)]
[body (append
(reverse! (parsed-unit-body a-unit))
((parsed-unit-stx-checks a-unit) expr))]
[import-sigs (explode-named-sigs (parsed-unit-imports a-unit) #f)]
[export-sig (explode-sig sig #f)])
(syntax/loc expr
(make-signed-unit
(unit/no-expand
(import . imports)
(export . exports)
. body)
(quote import-sigs)
(quote export-sig))))))])))
(define-syntax compound-unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ . body)
(let-values ([(tags
exprs
exploded-link-imports
exploded-link-exports
flat-imports
link-imports
flat-exports
exploded-imports
exploded-exports
boxed-interned-symbol-vectors)
(parse-compound-unit expr (syntax body))]
[(t) (lambda (l) (datum->syntax-object expr l expr))])
(with-syntax ([(tag ...) (t tags)]
[(uexpr ...) (t exprs)]
[(tagx ...) (t (map (lambda (t) (string->symbol (format "u:~a" t))) tags))]
[exploded-link-imports (t exploded-link-imports)]
[exploded-link-exports (t exploded-link-exports)]
[flat-imports (t flat-imports)]
[(link-import ...) (t link-imports)]
[flat-exports (t flat-exports)]
[exploded-imports (t exploded-imports)]
[exploded-exports (t exploded-exports)]
[interned-vectors (t (map (lambda (x) `(,(car x) (quote ,(cadr x))))
(unbox boxed-interned-symbol-vectors)))])
(syntax/loc
expr
(let ([tagx uexpr] ... . interned-vectors)
(alt-verify-linkage-signature-match
'compound-unit/sig
'(tag ...)
(list tagx ...)
`exploded-link-imports
`exploded-link-exports)
;; All checks done. Make the unit:
(make-signed-unit
(compound-unit
(import . flat-imports)
(link [tag ((signed-unit-unit tagx)
. link-import)]
...)
(export . flat-exports))
`exploded-imports
`exploded-exports)))))])))
(define-syntax invoke-unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ u sig ...)
(let ([sigs (parse-invoke-vars 'invoke-unit/sig (syntax (sig ...)) expr)])
(with-syntax ([exploded-sigs (datum->syntax-object
expr
(explode-named-sigs sigs #f)
expr)]
[flat-sigs (datum->syntax-object
expr
(flatten-signatures sigs #f)
expr)])
(syntax/loc
expr
(let ([unt u])
(alt-verify-linkage-signature-match
(quote invoke-unit/sig)
(quote (invoke))
(list unt)
(quote ((#() . #())))
(quote (exploded-sigs)))
(invoke-unit (signed-unit-unit unt)
. flat-sigs)))))])))
(define-syntax unit->unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ e (im-sig ...) ex-sig)
(let ([im-sigs (map (lambda (sig)
(get-sig 'unit->unit/sig expr #f sig #f))
(syntax->list (syntax (im-sig ...))))]
[ex-sig (get-sig 'unit->unit/sig expr #f (syntax ex-sig) #f)])
(with-syntax ([exploded-imports (datum->syntax-object
expr
(explode-named-sigs im-sigs #f)
expr)]
[exploded-exports (datum->syntax-object
expr
(explode-sig ex-sig #f)
expr)])
(syntax
(make-signed-unit
e
(quote exploded-imports)
(quote exploded-exports)))))])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define -verify-linkage-signature-match
(let ([make-exn make-exn:fail:unit]
[p-suffix (lambda (pos) (case pos [(1) 'st][(2) 'nd][(3) 'rd][else 'th]))])
(lambda (who tags units esigs isigs wrapped? unwrap)
(for-each
(lambda (u tag)
(unless (signed-unit? u)
(raise
(make-exn
(string->immutable-string
(format
"~s: expression for \"~s\" is not a signed unit: ~e"
who tag u))
(current-continuation-marks)))))
units tags)
(for-each
(lambda (u tag esig)
(-verify-signature-match
who #f
(format "specified export signature for ~a" tag)
esig
(format "export signature for actual ~a sub-unit" tag)
(signed-unit-exports u)
wrapped? unwrap))
units tags esigs)
(for-each
(lambda (u tag isig)
(let ([n (length (signed-unit-imports u))]
[c (length isig)])
(unless (= c n)
(raise
(make-exn
(string->immutable-string
(format
"~s: ~a unit imports ~a units, but ~a units were provided"
who tag n c))
(current-continuation-marks))))))
units tags isigs)
(for-each
(lambda (u tag isig)
(let loop ([isig isig][expecteds (signed-unit-imports u)][pos 1])
(unless (null? isig)
(let ([expected (car expecteds)]
[provided (car isig)])
(-verify-signature-match
who #t
(format "~a unit's ~s~s import (which is ~a)" tag
pos (p-suffix pos)
(car expected))
(cdr expected)
(format "~a's ~s~s linkage (which is ~a)"
tag
pos (p-suffix pos)
(car provided))
(cdr provided)
wrapped? unwrap)
(loop (cdr isig) (cdr expecteds) (add1 pos))))))
units tags isigs))))
(define verify-linkage-signature-match
(lambda (who tags units esigs isigs)
(-verify-linkage-signature-match who tags units esigs isigs values values)))
(define alt-verify-linkage-signature-match
(lambda (who tags units esigs isigs)
(-verify-linkage-signature-match who tags units esigs isigs pair? car)))
(define-syntax signature->symbols
(lambda (stx)
(syntax-case stx ()
[(_ name)
(identifier? (syntax name))
(let ([sig (get-sig 'signature->symbols stx #f (syntax name) #f)])
(with-syntax ([e (let cleanup ([p (explode-sig sig #f)])
;; Strip struct info:
(list->vector
(map (lambda (i)
(if (symbol? i)
i
(cons (car i) (cleanup (cdr i)))))
(vector->list (car p)))))])
(syntax 'e)))])))
;; Internal:
(define-syntax do-define-values/invoke-unit/sig
(lambda (stx)
(syntax-case stx ()
[(_ global? signame unite prefix imports orig)
(let* ([formname (if (syntax-e (syntax global?))
'namespace-variable-bind/invoke-unit/sig
'define-values/invoke-unit/sig)]
[badsyntax (lambda (s why)
(raise-syntax-error
#f
(format "bad syntax (~a)" why)
(syntax orig)
s))])
(unless (or (not (syntax-e (syntax prefix)))
(identifier? (syntax prefix)))
(badsyntax (syntax prefix) "prefix is not an identifier"))
(let ([ex-sig (get-sig formname (syntax orig) #f (syntax signame) (syntax signame))])
(let ([ex-exploded (explode-sig ex-sig #f)]
[ex-flattened (flatten-signature #f ex-sig #'signame)])
(let ([im-sigs
(parse-invoke-vars formname (syntax imports) (syntax orig))])
(let ([im-explodeds (explode-named-sigs im-sigs #f)]
[im-flattened (flatten-signatures im-sigs #f)]
[d->s (lambda (x) (datum->syntax-object (syntax orig) x (syntax orig)))])
(with-syntax ([dv/iu (if (syntax-e (syntax global?))
(quote-syntax namespace-variable-bind/invoke-unit)
(quote-syntax define-values/invoke-unit))]
[ex-flattened ex-flattened]
[ex-exploded (d->s ex-exploded)]
[im-explodeds (d->s im-explodeds)]
[im-flattened (d->s im-flattened)]
[formname formname]
[stx-decls (if (syntax-e (syntax global?))
null
(make-struct-stx-decls ex-sig #f #f (syntax signame) #f))])
(syntax/loc stx
(begin
(dv/iu
ex-flattened
(let ([unit-var unite])
(alt-verify-linkage-signature-match
'formname
'(invoke)
(list unit-var)
'(ex-exploded)
'(im-explodeds))
(signed-unit-unit unit-var))
prefix
. im-flattened)
. stx-decls))))))))])))
(define-syntax define-values/invoke-unit/sig
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ signame unit prefix . imports)
(syntax (do-define-values/invoke-unit/sig #f signame unit prefix imports orig))]
[(_ signame unit)
(syntax (do-define-values/invoke-unit/sig #f signame unit #f () orig))]))))
(define-syntax namespace-variable-bind/invoke-unit/sig
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ signame unit prefix . imports)
(syntax (do-define-values/invoke-unit/sig #t signame unit prefix imports orig))]
[(_ signame unit)
(syntax (do-define-values/invoke-unit/sig #t signame unit #f () orig))]))))
(define-syntax provide-signature-elements
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ signame)
(let ([sig (get-sig 'provide-signature-elements stx #f (syntax signame) (syntax signame))])
(let ([flattened (flatten-signature #f sig (syntax signame))]
[structs (map struct-def-name (signature-structs sig))])
(with-syntax ([flattened (map (lambda (x) (datum->syntax-object (syntax signame) x #f))
(append flattened structs))])
(syntax/loc stx
(provide . flattened)))))]))))
(define (unit/sig? x) (signed-unit? x))
(define (unit/sig->unit x) (signed-unit-unit x))
(provide define-signature
let-signature
unit/sig
compound-unit/sig
invoke-unit/sig
unit->unit/sig
signature->symbols
verify-signature-match
verify-linkage-signature-match
(struct signed-unit (unit imports exports))
unit/sig? unit/sig->unit
define-values/invoke-unit/sig
namespace-variable-bind/invoke-unit/sig
provide-signature-elements))
(require (lib "unitsig200.ss"))
(provide (all-from (lib "unitsig200.ss"))))

View File

@ -0,0 +1,359 @@
;; This implementation of `unit/sig' was ported from the old v100
;; implementation, and then hacked a bit to produce more compact
;; output, and finally mangled to handle the v200 `struct' (with
;; compile-time information). It's in dire need of an overhaul.
(module unitsig200 mzscheme
(require "unit200.ss")
(require "private/sigmatch.ss")
(require-for-syntax "private/sigutil.ss")
(require-for-syntax "private/sigmatch.ss")
(require-for-syntax (lib "kerncase.ss" "syntax"))
(define-struct signed-unit (unit imports exports))
(define-syntax define-signature
(lambda (expr)
(syntax-case expr ()
[(_ name sig)
(identifier? (syntax name))
(let ([sig (get-sig 'define-signature expr (syntax-e (syntax name))
(syntax sig) #f)])
(with-syntax ([content (explode-sig sig #f)])
(syntax (define-syntax name
(make-sig (quote content))))))])))
(define-syntax let-signature
(lambda (expr)
(syntax-case expr ()
[(_ name sig . body)
(identifier? (syntax name))
(let ([sig (get-sig 'let-signature expr (syntax-e (syntax name))
(syntax sig) #f)])
(with-syntax ([content (explode-sig sig #f)])
(syntax (letrec-syntax ([name (make-sig (quote content))])
. body))))])))
(define-syntax unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ sig . rest)
(let ([sig (get-sig 'unit/sig expr #f (syntax sig) #f)])
(let ([a-unit (parse-unit expr (syntax rest) sig
(kernel-form-identifier-list (quote-syntax here))
(quote-syntax define-values)
(quote-syntax define-syntaxes)
(quote-syntax begin))])
(check-signature-unit-body sig a-unit (parsed-unit-renames a-unit) 'unit/sig expr)
(with-syntax ([imports (parsed-unit-import-vars a-unit)]
[exports (datum->syntax-object
expr
(let ([vars (make-hash-table)])
(for-each (lambda (var)
(hash-table-put! vars (syntax-e var) var))
(parsed-unit-vars a-unit))
(map
(lambda (name)
(list (let ([name (do-rename name (parsed-unit-renames a-unit))])
(hash-table-get vars name name))
name))
(signature-vars sig)))
expr)]
[body (append
(reverse! (parsed-unit-body a-unit))
((parsed-unit-stx-checks a-unit) expr))]
[import-sigs (explode-named-sigs (parsed-unit-imports a-unit) #f)]
[export-sig (explode-sig sig #f)])
(syntax/loc expr
(make-signed-unit
(unit/no-expand
(import . imports)
(export . exports)
. body)
(quote import-sigs)
(quote export-sig))))))])))
(define-syntax compound-unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ . body)
(let-values ([(tags
exprs
exploded-link-imports
exploded-link-exports
flat-imports
link-imports
flat-exports
exploded-imports
exploded-exports
boxed-interned-symbol-vectors)
(parse-compound-unit expr (syntax body))]
[(t) (lambda (l) (datum->syntax-object expr l expr))])
(with-syntax ([(tag ...) (t tags)]
[(uexpr ...) (t exprs)]
[(tagx ...) (t (map (lambda (t) (string->symbol (format "u:~a" t))) tags))]
[exploded-link-imports (t exploded-link-imports)]
[exploded-link-exports (t exploded-link-exports)]
[flat-imports (t flat-imports)]
[(link-import ...) (t link-imports)]
[flat-exports (t flat-exports)]
[exploded-imports (t exploded-imports)]
[exploded-exports (t exploded-exports)]
[interned-vectors (t (map (lambda (x) `(,(car x) (quote ,(cadr x))))
(unbox boxed-interned-symbol-vectors)))])
(syntax/loc
expr
(let ([tagx uexpr] ... . interned-vectors)
(alt-verify-linkage-signature-match
'compound-unit/sig
'(tag ...)
(list tagx ...)
`exploded-link-imports
`exploded-link-exports)
;; All checks done. Make the unit:
(make-signed-unit
(compound-unit
(import . flat-imports)
(link [tag ((signed-unit-unit tagx)
. link-import)]
...)
(export . flat-exports))
`exploded-imports
`exploded-exports)))))])))
(define-syntax invoke-unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ u sig ...)
(let ([sigs (parse-invoke-vars 'invoke-unit/sig (syntax (sig ...)) expr)])
(with-syntax ([exploded-sigs (datum->syntax-object
expr
(explode-named-sigs sigs #f)
expr)]
[flat-sigs (datum->syntax-object
expr
(flatten-signatures sigs #f)
expr)])
(syntax/loc
expr
(let ([unt u])
(alt-verify-linkage-signature-match
(quote invoke-unit/sig)
(quote (invoke))
(list unt)
(quote ((#() . #())))
(quote (exploded-sigs)))
(invoke-unit (signed-unit-unit unt)
. flat-sigs)))))])))
(define-syntax unit->unit/sig
(lambda (expr)
(syntax-case expr ()
[(_ e (im-sig ...) ex-sig)
(let ([im-sigs (map (lambda (sig)
(get-sig 'unit->unit/sig expr #f sig #f))
(syntax->list (syntax (im-sig ...))))]
[ex-sig (get-sig 'unit->unit/sig expr #f (syntax ex-sig) #f)])
(with-syntax ([exploded-imports (datum->syntax-object
expr
(explode-named-sigs im-sigs #f)
expr)]
[exploded-exports (datum->syntax-object
expr
(explode-sig ex-sig #f)
expr)])
(syntax
(make-signed-unit
e
(quote exploded-imports)
(quote exploded-exports)))))])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define -verify-linkage-signature-match
(let ([make-exn make-exn:fail:unit]
[p-suffix (lambda (pos) (case pos [(1) 'st][(2) 'nd][(3) 'rd][else 'th]))])
(lambda (who tags units esigs isigs wrapped? unwrap)
(for-each
(lambda (u tag)
(unless (signed-unit? u)
(raise
(make-exn
(string->immutable-string
(format
"~s: expression for \"~s\" is not a signed unit: ~e"
who tag u))
(current-continuation-marks)))))
units tags)
(for-each
(lambda (u tag esig)
(-verify-signature-match
who #f
(format "specified export signature for ~a" tag)
esig
(format "export signature for actual ~a sub-unit" tag)
(signed-unit-exports u)
wrapped? unwrap))
units tags esigs)
(for-each
(lambda (u tag isig)
(let ([n (length (signed-unit-imports u))]
[c (length isig)])
(unless (= c n)
(raise
(make-exn
(string->immutable-string
(format
"~s: ~a unit imports ~a units, but ~a units were provided"
who tag n c))
(current-continuation-marks))))))
units tags isigs)
(for-each
(lambda (u tag isig)
(let loop ([isig isig][expecteds (signed-unit-imports u)][pos 1])
(unless (null? isig)
(let ([expected (car expecteds)]
[provided (car isig)])
(-verify-signature-match
who #t
(format "~a unit's ~s~s import (which is ~a)" tag
pos (p-suffix pos)
(car expected))
(cdr expected)
(format "~a's ~s~s linkage (which is ~a)"
tag
pos (p-suffix pos)
(car provided))
(cdr provided)
wrapped? unwrap)
(loop (cdr isig) (cdr expecteds) (add1 pos))))))
units tags isigs))))
(define verify-linkage-signature-match
(lambda (who tags units esigs isigs)
(-verify-linkage-signature-match who tags units esigs isigs values values)))
(define alt-verify-linkage-signature-match
(lambda (who tags units esigs isigs)
(-verify-linkage-signature-match who tags units esigs isigs pair? car)))
(define-syntax signature->symbols
(lambda (stx)
(syntax-case stx ()
[(_ name)
(identifier? (syntax name))
(let ([sig (get-sig 'signature->symbols stx #f (syntax name) #f)])
(with-syntax ([e (let cleanup ([p (explode-sig sig #f)])
;; Strip struct info:
(list->vector
(map (lambda (i)
(if (symbol? i)
i
(cons (car i) (cleanup (cdr i)))))
(vector->list (car p)))))])
(syntax 'e)))])))
;; Internal:
(define-syntax do-define-values/invoke-unit/sig
(lambda (stx)
(syntax-case stx ()
[(_ global? signame unite prefix imports orig)
(let* ([formname (if (syntax-e (syntax global?))
'namespace-variable-bind/invoke-unit/sig
'define-values/invoke-unit/sig)]
[badsyntax (lambda (s why)
(raise-syntax-error
#f
(format "bad syntax (~a)" why)
(syntax orig)
s))])
(unless (or (not (syntax-e (syntax prefix)))
(identifier? (syntax prefix)))
(badsyntax (syntax prefix) "prefix is not an identifier"))
(let ([ex-sig (get-sig formname (syntax orig) #f (syntax signame) (syntax signame))])
(let ([ex-exploded (explode-sig ex-sig #f)]
[ex-flattened (flatten-signature #f ex-sig #'signame)])
(let ([im-sigs
(parse-invoke-vars formname (syntax imports) (syntax orig))])
(let ([im-explodeds (explode-named-sigs im-sigs #f)]
[im-flattened (flatten-signatures im-sigs #f)]
[d->s (lambda (x) (datum->syntax-object (syntax orig) x (syntax orig)))])
(with-syntax ([dv/iu (if (syntax-e (syntax global?))
(quote-syntax namespace-variable-bind/invoke-unit)
(quote-syntax define-values/invoke-unit))]
[ex-flattened ex-flattened]
[ex-exploded (d->s ex-exploded)]
[im-explodeds (d->s im-explodeds)]
[im-flattened (d->s im-flattened)]
[formname formname]
[stx-decls (if (syntax-e (syntax global?))
null
(make-struct-stx-decls ex-sig #f #f (syntax signame) #f))])
(syntax/loc stx
(begin
(dv/iu
ex-flattened
(let ([unit-var unite])
(alt-verify-linkage-signature-match
'formname
'(invoke)
(list unit-var)
'(ex-exploded)
'(im-explodeds))
(signed-unit-unit unit-var))
prefix
. im-flattened)
. stx-decls))))))))])))
(define-syntax define-values/invoke-unit/sig
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ signame unit prefix . imports)
(syntax (do-define-values/invoke-unit/sig #f signame unit prefix imports orig))]
[(_ signame unit)
(syntax (do-define-values/invoke-unit/sig #f signame unit #f () orig))]))))
(define-syntax namespace-variable-bind/invoke-unit/sig
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ signame unit prefix . imports)
(syntax (do-define-values/invoke-unit/sig #t signame unit prefix imports orig))]
[(_ signame unit)
(syntax (do-define-values/invoke-unit/sig #t signame unit #f () orig))]))))
(define-syntax provide-signature-elements
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ signame)
(let ([sig (get-sig 'provide-signature-elements stx #f (syntax signame) (syntax signame))])
(let ([flattened (flatten-signature #f sig (syntax signame))]
[structs (map struct-def-name (signature-structs sig))])
(with-syntax ([flattened (map (lambda (x) (datum->syntax-object (syntax signame) x #f))
(append flattened structs))])
(syntax/loc stx
(provide . flattened)))))]))))
(define (unit/sig? x) (signed-unit? x))
(define (unit/sig->unit x) (signed-unit-unit x))
(provide define-signature
let-signature
unit/sig
compound-unit/sig
invoke-unit/sig
unit->unit/sig
signature->symbols
verify-signature-match
verify-linkage-signature-match
(struct signed-unit (unit imports exports))
unit/sig? unit/sig->unit
define-values/invoke-unit/sig
namespace-variable-bind/invoke-unit/sig
provide-signature-elements))

View File

@ -1,13 +1,7 @@
(module base64-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:base64^)
(define-signature net:base64^
(base64-filename-safe
base64-encode-stream
base64-decode-stream
base64-encode
base64-decode)))
(module base64-sig (lib "a-signature.ss")
base64-filename-safe
base64-encode-stream
base64-decode-stream
base64-encode
base64-decode)

View File

@ -1,14 +1,8 @@
(module base64-unit mzscheme
(require (lib "unitsig.ss"))
(module base64-unit (lib "a-unit.ss")
(require "base64-sig.ss")
(provide net:base64@)
(define net:base64@
(unit/sig net:base64^
(import)
(import)
(export base64^)
(define base64-digit (make-vector 256))
(let loop ([n 0])
@ -142,5 +136,5 @@
(let ([s (open-output-bytes)])
(base64-encode-stream (open-input-bytes src) s
(bytes 13 10))
(get-output-bytes s))))))
(get-output-bytes s))))

View File

@ -1,30 +1,23 @@
(module cgi-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:cgi^)
(define-signature net:cgi^
(
;; -- exceptions raised --
(struct cgi-error ())
(struct incomplete-%-suffix (chars))
(struct invalid-%-suffix (char))
;; -- cgi methods --
get-bindings
get-bindings/post
get-bindings/get
output-http-headers
generate-html-output
generate-error-output
bindings-as-html
extract-bindings
extract-binding/single
get-cgi-method
;; -- general HTML utilities --
string->html
generate-link-text
)))
(module cgi-sig (lib "a-signature.ss")
;; -- exceptions raised --
(struct cgi-error ())
(struct incomplete-%-suffix (chars))
(struct invalid-%-suffix (char))
;; -- cgi methods --
get-bindings
get-bindings/post
get-bindings/get
output-http-headers
generate-html-output
generate-error-output
bindings-as-html
extract-bindings
extract-binding/single
get-cgi-method
;; -- general HTML utilities --
string->html
generate-link-text
)

View File

@ -1,10 +1,9 @@
(module cgi-unit mzscheme
(require (lib "unitsig.ss") "cgi-sig.ss" (lib "etc.ss"))
(module cgi-unit (lib "a-unit.ss")
(require (lib "etc.ss")
"cgi-sig.ss")
(provide net:cgi@)
(define net:cgi@
(unit/sig net:cgi^
(import)
(import)
(export cgi^)
;; type bindings = list ((symbol . string))
@ -239,5 +238,5 @@
(define (generate-link-text url anchor-text)
(string-append "<a href=\"" url "\">" anchor-text "</a>"))
)))
)

View File

@ -1,19 +1,16 @@
(module cookie-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:cookie^)
(module cookie-sig (lib "a-signature.ss")
(define-signature net:cookie^
(set-cookie
cookie:add-comment
cookie:add-domain
cookie:add-max-age
cookie:add-path
cookie:secure
cookie:version
;; To actually return a cookie (string formated as a cookie):
print-cookie
;; To parse the Cookies header:
get-cookie
get-cookie/single
;; exceptions
(struct cookie-error ()))))
set-cookie
cookie:add-comment
cookie:add-domain
cookie:add-max-age
cookie:add-path
cookie:secure
cookie:version
;; To actually return a cookie (string formated as a cookie):
print-cookie
;; To parse the Cookies header:
get-cookie
get-cookie/single
;; exceptions
(struct cookie-error ()))

View File

@ -47,304 +47,297 @@
;;
;; You should think of this procedures as a `format' for cookies.
(module cookie-unit mzscheme
(require (lib "unitsig.ss")
(lib "etc.ss")
(module cookie-unit (lib "a-unit.ss")
(require (lib "etc.ss")
(lib "list.ss")
(lib "string.ss" "srfi" "13")
(lib "char-set.ss" "srfi" "14")
"cookie-sig.ss")
(provide cookie@)
(import)
(export cookie^)
(define-struct cookie (name value comment domain max-age path secure version))
(define-struct (cookie-error exn:fail) ())
;; The syntax for the Set-Cookie response header is
;; set-cookie = "Set-Cookie:" cookies
;; cookies = 1#cookie
;; cookie = NAME "=" VALUE *(";" cookie-av)
;; NAME = attr
;; VALUE = value
;; cookie-av = "Comment" "=" value
;; | "Domain" "=" value
;; | "Max-Age" "=" value
;; | "Path" "=" value
;; | "Secure"
;; | "Version" "=" 1*DIGIT
(define set-cookie
(lambda (name pre-value)
(let ([value (to-rfc2109:value pre-value)])
(unless (rfc2068:token? name)
(raise (build-cookie-error (format "Invalid cookie name: ~a / ~a" name value))))
(make-cookie name value
#f;; comment
#f;; current domain
#f;; at the end of session
#f;; current path
#f;; normal (non SSL)
#f;; default version
))))
;;!
;;
;; (function (print-cookie cookie))
;;
;; (param cookie Cookie-structure "The cookie to return as a string")
;;
;; Formats the cookie contents in a string ready to be appended to a
;; "Set-Cookie: " header, and sent to a client (browser).
(define print-cookie
(lambda (cookie)
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(string-join
(filter (lambda (s)
(not (string-null? s)))
(list (format "~a=~a" (cookie-name cookie) (cookie-value cookie))
(let ((c (cookie-comment cookie))) (if c (format "Comment=~a" c) ""))
(let ((d (cookie-domain cookie))) (if d (format "Domain=~a" d) ""))
(let ((age (cookie-max-age cookie))) (if age (format "Max-Age=~a" age) ""))
(let ((p (cookie-path cookie))) (if p (format "Path=~a" p) ""))
(let ((s (cookie-secure cookie))) (if s "Secure" ""))
(let ((v (cookie-version cookie))) (format "Version=~a" (if v v 1)))))
"; ")))
(define cookie:add-comment
(lambda (cookie pre-comment)
(let ([comment (to-rfc2109:value pre-comment)])
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-comment! cookie comment)
cookie)))
(define cookie:add-domain
(lambda (cookie domain)
(unless (valid-domain? domain)
(raise (build-cookie-error (format "Invalid domain: ~a" domain))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-domain! cookie domain)
cookie))
(define cookie:add-max-age
(lambda (cookie seconds)
(unless (and (integer? seconds) (not (negative? seconds)))
(raise (build-cookie-error (format "Invalid Max-Age for cookie: ~a" seconds))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-max-age! cookie seconds)
cookie))
(define cookie:add-path
(lambda (cookie pre-path)
(let ([path (to-rfc2109:value pre-path)])
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-path! cookie path)
cookie)))
(define cookie:secure
(lambda (cookie secure?)
(unless (boolean? secure?)
(raise (build-cookie-error (format "Invalid argument (boolean expected), received: ~a" secure?))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-secure! cookie secure?)
cookie))
(define cookie:version
(lambda (cookie version)
(unless (integer? version)
(raise (build-cookie-error (format "Unsupported version: ~a" version))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-version! cookie version)
cookie))
(define cookie@
(unit/sig net:cookie^
(import)
(define-struct cookie (name value comment domain max-age path secure version))
(define-struct (cookie-error exn:fail) ())
;; The syntax for the Set-Cookie response header is
;; set-cookie = "Set-Cookie:" cookies
;; cookies = 1#cookie
;; cookie = NAME "=" VALUE *(";" cookie-av)
;; NAME = attr
;; VALUE = value
;; cookie-av = "Comment" "=" value
;; | "Domain" "=" value
;; | "Max-Age" "=" value
;; | "Path" "=" value
;; | "Secure"
;; | "Version" "=" 1*DIGIT
(define set-cookie
(lambda (name pre-value)
(let ([value (to-rfc2109:value pre-value)])
(unless (rfc2068:token? name)
(raise (build-cookie-error (format "Invalid cookie name: ~a / ~a" name value))))
(make-cookie name value
#f;; comment
#f;; current domain
#f;; at the end of session
#f;; current path
#f;; normal (non SSL)
#f;; default version
))))
;; Parsing the Cookie header:
;;!
;;
;; (function (print-cookie cookie))
;;
;; (param cookie Cookie-structure "The cookie to return as a string")
;;
;; Formats the cookie contents in a string ready to be appended to a
;; "Set-Cookie: " header, and sent to a client (browser).
(define print-cookie
(lambda (cookie)
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(string-join
(filter (lambda (s)
(not (string-null? s)))
(list (format "~a=~a" (cookie-name cookie) (cookie-value cookie))
(let ((c (cookie-comment cookie))) (if c (format "Comment=~a" c) ""))
(let ((d (cookie-domain cookie))) (if d (format "Domain=~a" d) ""))
(let ((age (cookie-max-age cookie))) (if age (format "Max-Age=~a" age) ""))
(let ((p (cookie-path cookie))) (if p (format "Path=~a" p) ""))
(let ((s (cookie-secure cookie))) (if s "Secure" ""))
(let ((v (cookie-version cookie))) (format "Version=~a" (if v v 1)))))
"; ")))
(define char-set:all-but=
(char-set-difference char-set:full (string->char-set "=")))
(define cookie:add-comment
(lambda (cookie pre-comment)
(let ([comment (to-rfc2109:value pre-comment)])
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-comment! cookie comment)
cookie)))
(define char-set:all-but-semicolon
(char-set-difference char-set:full (string->char-set ";")))
(define cookie:add-domain
(lambda (cookie domain)
(unless (valid-domain? domain)
(raise (build-cookie-error (format "Invalid domain: ~a" domain))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-domain! cookie domain)
cookie))
;;!
;;
;; (function (get-all-results name cookies))
;;
;; Auxiliar procedure that returns all values associated with
;; `name' in the association list (cookies).
(define get-all-results
(lambda (name cookies)
(let loop ((c cookies))
(cond ((null? c) ())
(else
(let ((pair (car c)))
(if (string=? name (car pair))
;; found an instance of cookie named `name'
(cons (cadr pair) (loop (cdr c)))
(loop (cdr c)))))))))
(define cookie:add-max-age
(lambda (cookie seconds)
(unless (and (integer? seconds) (not (negative? seconds)))
(raise (build-cookie-error (format "Invalid Max-Age for cookie: ~a" seconds))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-max-age! cookie seconds)
cookie))
;; which tipically looks like: (cookie . "test5=\"5\"; test1=\"1\"; test0=\"0\"; test1=\"20\"")
;; note that it can be multi-valued: `test1' has values: "1", and "20".
;; Of course, in the same spirit, we only receive the "string content".
(define get-cookie
(lambda (name cookies)
(let ((cookies (map (lambda (p)
(map string-trim-both
(string-tokenize p char-set:all-but=)))
(string-tokenize cookies char-set:all-but-semicolon))))
(get-all-results name cookies))))
(define cookie:add-path
(lambda (cookie pre-path)
(let ([path (to-rfc2109:value pre-path)])
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-path! cookie path)
cookie)))
(define cookie:secure
(lambda (cookie secure?)
(unless (boolean? secure?)
(raise (build-cookie-error (format "Invalid argument (boolean expected), received: ~a" secure?))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-secure! cookie secure?)
cookie))
(define cookie:version
(lambda (cookie version)
(unless (integer? version)
(raise (build-cookie-error (format "Unsupported version: ~a" version))))
(unless (cookie? cookie)
(raise (build-cookie-error (format "Cookie expected, received: ~a" cookie))))
(set-cookie-version! cookie version)
cookie))
;;!
;;
;; (function (get-cookie/single name cookies))
;;
;; (param name String "The name of the cookie we are looking for")
;; (param cookies String "The string (from the environment) with the content of the cookie header.")
;;
;; Returns the first name associated with the cookie named `name', if any, or #f.
(define get-cookie/single
(lambda (name cookies)
(let ((cookies (get-cookie name cookies)))
(and (not (null? cookies))
(car cookies)))))
;; Parsing the Cookie header:
;;;;;
;; Auxiliary procedures
;;;;;
;; token = 1*<any CHAR except CTLs or tspecials>
;;
;; tspecials = "(" | ")" | "<" | ">" | "@"
;; | "," | ";" | ":" | "\" | <">
;; | "/" | "[" | "]" | "?" | "="
;; | "{" | "}" | SP | HT
(define char-set:tspecials
(char-set-union (string->char-set "()<>@,;:\\\"/[]?={}")
char-set:whitespace
(char-set #\tab)))
(define char-set:all-but=
(char-set-difference char-set:full (string->char-set "=")))
(define char-set:control
(char-set-union char-set:iso-control
(char-set (integer->char 127))));; DEL
(define char-set:token (char-set-difference char-set:ascii char-set:tspecials char-set:control))
(define char-set:all-but-semicolon
(char-set-difference char-set:full (string->char-set ";")))
;; token? : string -> boolean
;;
;; returns #t if s is an RFC 2068 token (see definition above), #f otherwise.
(define rfc2068:token?
(lambda (s) (string-every char-set:token s)))
;;!
;;
;; (function (get-all-results name cookies))
;;
;; Auxiliar procedure that returns all values associated with
;; `name' in the association list (cookies).
(define get-all-results
(lambda (name cookies)
(let loop ((c cookies))
(cond ((null? c) ())
(else
(let ((pair (car c)))
(if (string=? name (car pair))
;; found an instance of cookie named `name'
(cons (cadr pair) (loop (cdr c)))
(loop (cdr c)))))))))
;; which tipically looks like: (cookie . "test5=\"5\"; test1=\"1\"; test0=\"0\"; test1=\"20\"")
;; note that it can be multi-valued: `test1' has values: "1", and "20".
;; Of course, in the same spirit, we only receive the "string content".
(define get-cookie
(lambda (name cookies)
(let ((cookies (map (lambda (p)
(map string-trim-both
(string-tokenize p char-set:all-but=)))
(string-tokenize cookies char-set:all-but-semicolon))))
(get-all-results name cookies))))
;;!
;;
;; (function (quoted-string? s))
;;
;; (param s String "The string to check")
;;
;; Returns s if the string is an RFC 2068 quoted-string, #f otherwise. As in:
;; quoted-string = ( <"> *(qdtext) <"> )
;; qdtext = <any TEXT except <">>
;;
;; The backslash character ("\") may be used as a single-character quoting
;; mechanism only within quoted-string and comment constructs.
;;
;; quoted-pair = "\" CHAR
;;
;; implementation note: I have chosen to use a regular expression rather than
;; a character set for this definition because of two dependencies: CRLF must appear
;; as a block to be legal, and " may only appear as \"
(define rfc2068:quoted-string?
(lambda (s)
(if (regexp-match #rx"^\"([^\"#\u0000-#\u001F]| |#\return#\newline|#\tab|\\\\\")*\"$" s)
s
#f)))
;;!
;;
;; (function (get-cookie/single name cookies))
;;
;; (param name String "The name of the cookie we are looking for")
;; (param cookies String "The string (from the environment) with the content of the cookie header.")
;;
;; Returns the first name associated with the cookie named `name', if any, or #f.
(define get-cookie/single
(lambda (name cookies)
(let ((cookies (get-cookie name cookies)))
(and (not (null? cookies))
(car cookies)))))
;; value: token | quoted-string
(define (rfc2109:value? s)
(or (rfc2068:token? s) (rfc2068:quoted-string? s)))
;;;;;
;; Auxiliar procedures
;;;;;
;; convert-to-quoted : string -> quoted-string?
;; takes the given string as a particular message, and converts the given string to that
;; representatation
(define (convert-to-quoted str)
(string-append "\"" (regexp-replace* #rx"\"" str "\\\\\"") "\""))
;; token = 1*<any CHAR except CTLs or tspecials>
;;
;; tspecials = "(" | ")" | "<" | ">" | "@"
;; | "," | ";" | ":" | "\" | <">
;; | "/" | "[" | "]" | "?" | "="
;; | "{" | "}" | SP | HT
(define char-set:tspecials
(char-set-union
(string->char-set "()<>@,;:\\\"/[]?={}")
char-set:whitespace
(char-set #\tab)))
(define char-set:control (char-set-union char-set:iso-control
(char-set (integer->char 127))));; DEL
(define char-set:token (char-set-difference char-set:ascii char-set:tspecials char-set:control))
;; token? : string -> boolean
;;
;; returns #t if s is an RFC 2068 token (see definition above), #f otherwise.
(define rfc2068:token?
(lambda (s) (string-every char-set:token s)))
;;!
;;
;; (function (quoted-string? s))
;;
;; (param s String "The string to check")
;;
;; Returns s if the string is an RFC 2068 quoted-string, #f otherwise. As in:
;; quoted-string = ( <"> *(qdtext) <"> )
;; qdtext = <any TEXT except <">>
;;
;; The backslash character ("\") may be used as a single-character quoting
;; mechanism only within quoted-string and comment constructs.
;;
;; quoted-pair = "\" CHAR
;;
;; implementation note: I have chosen to use a regular expression rather than
;; a character set for this definition because of two dependencies: CRLF must appear
;; as a block to be legal, and " may only appear as \"
(define rfc2068:quoted-string?
(lambda (s)
(if (regexp-match #rx"^\"([^\"#\u0000-#\u001F]| |#\return#\newline|#\tab|\\\\\")*\"$" s)
s
#f)))
;; value: token | quoted-string
(define (rfc2109:value? s)
(or (rfc2068:token? s) (rfc2068:quoted-string? s)))
;; convert-to-quoted : string -> quoted-string?
;; takes the given string as a particular message, and converts the given string to that
;; representatation
(define (convert-to-quoted str)
(string-append "\"" (regexp-replace* #rx"\"" str "\\\\\"") "\""))
;; string -> rfc2109:value?
(define (to-rfc2109:value s)
(cond
[(not (string? s))
(raise (build-cookie-error (format "Expected string, given: ~e" s)))]
; for backwards compatibility, just use the given string if it will work
[(rfc2068:token? s) s]
[(rfc2068:quoted-string? s) s]
; ... but if it doesn't work (i.e., it's just a normal message) then try to
; convert it into a representation that will work
[(rfc2068:quoted-string? (convert-to-quoted s))
=> (λ (x) x)]
[else
(raise
(build-cookie-error
(format "Could not convert the given string to an acceptable RFC 2109 value: ~s" s)))]))
;;!
;;
;; (function (cookie-string? s))
;;
;; (param s String "String to check")
;;
;; Returns whether this is a valid string to use as the value or the
;; name (depending on value?) of an HTTP cookie.
(define cookie-string?
(opt-lambda (s (value? #t))
(unless (string? s)
(raise (build-cookie-error (format "String expected, received: ~a" s))))
(if value?
(rfc2109:value? s)
;; name: token
(rfc2068:token? s))))
;; string -> rfc2109:value?
(define (to-rfc2109:value s)
(cond
[(not (string? s))
(raise (build-cookie-error (format "Expected string, given: ~e" s)))]
;; for backwards compatibility, just use the given string if it will work
[(rfc2068:token? s) s]
[(rfc2068:quoted-string? s) s]
;; ... but if it doesn't work (i.e., it's just a normal message) then try
;; to convert it into a representation that will work
[(rfc2068:quoted-string? (convert-to-quoted s))
=> (λ (x) x)]
[else
(raise
(build-cookie-error
(format "Could not convert the given string to an acceptable RFC 2109 value: ~s" s)))]))
;;!
;;
;; (function (cookie-string? s))
;;
;; (param s String "String to check")
;;
;; Returns whether this is a valid string to use as the value or the
;; name (depending on value?) of an HTTP cookie.
(define cookie-string?
(opt-lambda (s (value? #t))
(unless (string? s)
(raise (build-cookie-error (format "String expected, received: ~a" s))))
(if value?
(rfc2109:value? s)
;; name: token
(rfc2068:token? s))))
;; Host names as per RFC 1123 and RFC952, more or less, anyway. :-)
(define char-set:hostname
(let ((a-z-lowercase (ucs-range->char-set #x61 #x7B))
(a-z-uppercase (ucs-range->char-set #x41 #x5B)))
(char-set-adjoin!
(char-set-union char-set:digit a-z-lowercase a-z-uppercase)
#\. )))
(define valid-domain?
(lambda (dom)
(and
;; Domain must start with a dot (.)
(string=? (string-take dom 1) ".")
;; The rest are tokens-like strings separated by dots
(string-every char-set:hostname dom)
(<= (string-length dom) 76))))
(define (valid-path? v)
(and (string? v)
(rfc2109:value? v)))
;; build-cookie-error : string -> cookie-error
;; constructs a cookie-error struct from the given error message
;; (added to fix exceptions-must-take-immutable-strings bug)
(define (build-cookie-error msg)
(make-cookie-error (string->immutable-string msg)
(current-continuation-marks)))
;; Host names as per RFC 1123 and RFC952, more or less, anyway. :-)
(define char-set:hostname
(let ((a-z-lowercase (ucs-range->char-set #x61 #x7B))
(a-z-uppercase (ucs-range->char-set #x41 #x5B)))
(char-set-adjoin!
(char-set-union char-set:digit a-z-lowercase a-z-uppercase)
#\. )))
(define valid-domain?
(lambda (dom)
(and
;; Domain must start with a dot (.)
(string=? (string-take dom 1) ".")
;; The rest are tokens-like strings separated by dots
(string-every char-set:hostname dom)
(<= (string-length dom) 76))))
(define (valid-path? v)
(and (string? v)
(rfc2109:value? v)))
;; build-cookie-error : string -> cookie-error
;; constructs a cookie-error struct from the given error message
;; (added to fix exceptions-must-take-immutable-strings bug)
(define (build-cookie-error msg)
(make-cookie-error (string->immutable-string msg) (current-continuation-marks)))))
)
;;; cookie-unit.ss ends here
;;; cookie-unit.ss ends here

View File

@ -1,12 +1,6 @@
(module dns-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:dns^)
(define-signature net:dns^
(dns-get-address
dns-get-name
dns-get-mail-exchanger
dns-find-nameserver)))
(module dns-sig (lib "a-signature.ss")
dns-get-address
dns-get-name
dns-get-mail-exchanger
dns-find-nameserver)

View File

@ -1,18 +1,14 @@
(module dns-unit (lib "a-unit.ss")
(require (lib "list.ss")
(lib "process.ss")
"dns-sig.ss")
(module dns-unit mzscheme
(require (lib "unitsig.ss")
(lib "list.ss")
(lib "process.ss"))
(require "dns-sig.ss")
(import)
(export dns^)
;; UDP retry timeout:
(define INIT-TIMEOUT 50)
(provide net:dns@)
(define net:dns@
(unit/sig net:dns^
(import)
;; UDP retry timeout:
(define INIT-TIMEOUT 50)
(define types
'((a 1)
@ -365,5 +361,5 @@
line))
=> (lambda (m) (loop name (cadr m) #f))]
[else (loop name ip #f)]))))))]
[else #f])))))
[else #f])))

View File

@ -1,13 +1,8 @@
(module ftp-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:ftp^)
(define-signature net:ftp^
(ftp-cd
ftp-establish-connection ftp-establish-connection*
ftp-close-connection
ftp-directory-list
ftp-download-file
ftp-make-file-seconds)))
(module ftp-sig (lib "a-signature.ss")
ftp-cd
ftp-establish-connection ftp-establish-connection*
ftp-close-connection
ftp-directory-list
ftp-download-file
ftp-make-file-seconds)

View File

@ -1,4 +1,4 @@
(module ftp-unit mzscheme
(module ftp-unit (lib "a-unit.ss")
;; Version 0.2
;; Version 0.1a
;; Micah Flatt
@ -6,13 +6,9 @@
(require (lib "date.ss")
(lib "file.ss")
(lib "port.ss")
"ftp-sig.ss"
(lib "unitsig.ss"))
(provide net:ftp@)
(define net:ftp@
(unit/sig net:ftp^
(import)
"ftp-sig.ss")
(import)
(export ftp^)
;; opqaue record to represent an FTP connection:
(define-struct tcp-connection (in out))
@ -216,4 +212,4 @@
(rename-file-or-directory tmpfile (build-path folder filename) #t)))
;; (printf "FTP Client Installed...~n")
)))
)

View File

@ -1,19 +1,14 @@
(module head-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:head^)
(define-signature net:head^
(empty-header
validate-header
extract-field
remove-field
insert-field
replace-field
extract-all-fields
append-headers
standard-message-header
data-lines->data
extract-addresses
assemble-address-field)))
(module head-sig (lib "a-signature.ss")
empty-header
validate-header
extract-field
remove-field
insert-field
replace-field
extract-all-fields
append-headers
standard-message-header
data-lines->data
extract-addresses
assemble-address-field)

View File

@ -1,16 +1,11 @@
(module head-unit (lib "a-unit.ss")
(require (lib "date.ss")
(lib "string.ss")
"head-sig.ss")
(module head-unit mzscheme
(require (lib "unitsig.ss")
(lib "date.ss")
(lib "string.ss"))
(import)
(export head^)
(require "head-sig.ss")
(provide net:head@)
(define net:head@
(unit/sig net:head^
(import)
;; NB: I've done a copied-code adaptation of a number of these definitions into
;; "bytes-compatible" versions. Finishing the rest will require some kind of interface
;; decision---that is, when you don't supply a header, should the resulting operation
@ -402,4 +397,4 @@
alen)
(loop (cdr addresses)
(format "~a, ~a" s addr)
(+ len alen 2)))))))))))
(+ len alen 2)))))))))

View File

@ -1,44 +1,38 @@
(module imap-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:imap^)
(define-signature net:imap^
(imap-port-number
imap-connection?
imap-connect imap-connect*
imap-disconnect
imap-force-disconnect
imap-reselect
imap-examine
imap-noop
imap-status
imap-poll
imap-new?
imap-messages
imap-recent
imap-uidnext
imap-uidvalidity
imap-unseen
imap-reset-new!
imap-get-expunges
imap-pending-expunges?
imap-get-updates
imap-pending-updates?
imap-get-messages
imap-copy imap-append
imap-store imap-flag->symbol symbol->imap-flag
imap-expunge
imap-mailbox-exists?
imap-create-mailbox
imap-list-child-mailboxes
imap-mailbox-flags
imap-get-hierarchy-delimiter)))
(module imap-sig (lib "a-signature.ss")
imap-port-number
imap-connection?
imap-connect imap-connect*
imap-disconnect
imap-force-disconnect
imap-reselect
imap-examine
imap-noop
imap-status
imap-poll
imap-new?
imap-messages
imap-recent
imap-uidnext
imap-uidvalidity
imap-unseen
imap-reset-new!
imap-get-expunges
imap-pending-expunges?
imap-get-updates
imap-pending-updates?
imap-get-messages
imap-copy imap-append
imap-store imap-flag->symbol symbol->imap-flag
imap-expunge
imap-mailbox-exists?
imap-create-mailbox
imap-list-child-mailboxes
imap-mailbox-flags
imap-get-hierarchy-delimiter)

View File

@ -1,14 +1,10 @@
(module imap-unit mzscheme
(require (lib "unitsig.ss")
(lib "list.ss")
(module imap-unit (lib "a-unit.ss")
(require (lib "list.ss")
"imap-sig.ss"
"private/rbtree.ss")
(provide net:imap@)
(define net:imap@
(unit/sig net:imap^
(import)
(import)
(export imap^)
(define debug-via-stdio? #f)
@ -572,4 +568,4 @@
(cons
(list flags name)
sub-folders))))))))
(reverse sub-folders))))))
(reverse sub-folders))))

View File

@ -1,33 +1,26 @@
(module mime-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:mime^)
(module mime-sig (lib "a-signature.ss")
;; -- exceptions raised --
(struct mime-error () -setters -constructor)
(struct unexpected-termination (msg) -setters -constructor)
(struct missing-multipart-boundary-parameter () -setters -constructor)
(struct malformed-multipart-entity (msg) -setters -constructor)
(struct empty-mechanism () -setters -constructor)
(struct empty-type () -setters -constructor)
(struct empty-subtype () -setters -constructor)
(struct empty-disposition-type () -setters -constructor)
(define-signature net:mime^
(
;; -- exceptions raised --
(struct mime-error () -setters (- make-mime-error))
(struct unexpected-termination (msg) -setters (- make-unexpected-termination))
(struct missing-multipart-boundary-parameter () -setters
(- make-missing-multipart-boundary-parameter))
(struct malformed-multipart-entity (msg) -setters (- make-malformed-multipart-entity))
(struct empty-mechanism () -setters (- make-empty-mechanism))
(struct empty-type () -setters (- make-empty-type))
(struct empty-subtype () -setters (- make-empty-subtype))
(struct empty-disposition-type () -setters (- make-empty-disposition-type))
;; -- basic mime structures --
(struct message (version entity fields))
(struct entity
(type subtype charset encoding
disposition params id
description other fields
parts body))
(struct disposition
(type filename creation
modification read
size params))
;; -- mime methods --
mime-analyze
)))
;; -- basic mime structures --
(struct message (version entity fields))
(struct entity
(type subtype charset encoding
disposition params id
description other fields
parts body))
(struct disposition
(type filename creation
modification read
size params))
;; -- mime methods --
mime-analyze
)

View File

@ -27,23 +27,18 @@
;; Commentary: MIME support for PLT Scheme: an implementation of
;; rfc2045, rfc2046, rfc2047, rfc2048, and rfc2049.
(module mime-unit mzscheme
(module mime-unit (lib "a-unit.ss")
(require "mime-sig.ss"
"qp-sig.ss"
"base64-sig.ss"
"head-sig.ss"
"mime-util.ss"
(lib "unitsig.ss")
(lib "etc.ss")
(lib "string.ss")
(lib "port.ss"))
(provide net:mime@)
(define net:mime@
(unit/sig net:mime^
(import net:base64^
net:qp^
net:head^)
(import base64^ qp^ head^)
(export mime^)
;; Constants:
(define discrete-alist '(("text" . text)
@ -783,4 +778,4 @@
(define disp-quoted-data-time date-time)
)))
)

View File

@ -1,26 +1,20 @@
(module nntp-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:nntp^)
(module nntp-sig (lib "a-signature.ss")
(struct communicator (sender receiver server port))
connect-to-server connect-to-server* disconnect-from-server
authenticate-user open-news-group
head-of-message body-of-message
newnews-since generic-message-command
make-desired-header extract-desired-headers
(define-signature net:nntp^
((struct communicator (sender receiver server port))
connect-to-server connect-to-server* disconnect-from-server
authenticate-user open-news-group
head-of-message body-of-message
newnews-since generic-message-command
make-desired-header extract-desired-headers
(struct nntp ())
(struct unexpected-response (code text))
(struct bad-status-line (line))
(struct premature-close (communicator))
(struct bad-newsgroup-line (line))
(struct non-existent-group (group))
(struct article-not-in-group (article))
(struct no-group-selected ())
(struct article-not-found (article))
(struct authentication-rejected ()))))
(struct nntp ())
(struct unexpected-response (code text))
(struct bad-status-line (line))
(struct premature-close (communicator))
(struct bad-newsgroup-line (line))
(struct non-existent-group (group))
(struct article-not-in-group (article))
(struct no-group-selected ())
(struct article-not-found (article))
(struct authentication-rejected ()))

View File

@ -1,13 +1,9 @@
(module nntp-unit mzscheme
(require (lib "unitsig.ss")
(lib "etc.ss"))
(module nntp-unit (lib "a-unit.ss")
(require (lib "etc.ss")
"nntp-sig.ss")
(require "nntp-sig.ss")
(provide net:nntp@)
(define net:nntp@
(unit/sig net:nntp^
(import)
(import)
(export nntp^)
;; sender : oport
;; receiver : iport
@ -337,5 +333,5 @@
(regexp-match matcher first))
desireds)
(cons first (loop rest))
(loop rest))))))))))
(loop rest))))))))

View File

@ -1,27 +1,21 @@
(module pop3-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:pop3^)
(module pop3-sig (lib "a-signature.ss")
(struct communicator (sender receiver server port state))
connect-to-server connect-to-server* disconnect-from-server
authenticate/plain-text
get-mailbox-status
get-message/complete get-message/headers get-message/body
delete-message
get-unique-id/single get-unique-id/all
(define-signature net:pop3^
((struct communicator (sender receiver server port state))
connect-to-server connect-to-server* disconnect-from-server
authenticate/plain-text
get-mailbox-status
get-message/complete get-message/headers get-message/body
delete-message
get-unique-id/single get-unique-id/all
make-desired-header extract-desired-headers
(struct pop3 ())
(struct cannot-connect ())
(struct username-rejected ())
(struct password-rejected ())
(struct not-ready-for-transaction (communicator))
(struct not-given-headers (communicator message))
(struct illegal-message-number (communicator message))
(struct cannot-delete-message (communicator message))
(struct disconnect-not-quiet (communicator))
(struct malformed-server-response (communicator)))))
make-desired-header extract-desired-headers
(struct pop3 ())
(struct cannot-connect ())
(struct username-rejected ())
(struct password-rejected ())
(struct not-ready-for-transaction (communicator))
(struct not-given-headers (communicator message))
(struct illegal-message-number (communicator message))
(struct cannot-delete-message (communicator message))
(struct disconnect-not-quiet (communicator))
(struct malformed-server-response (communicator)))

View File

@ -1,14 +1,9 @@
(module pop3-unit (lib "a-unit.ss")
(require (lib "etc.ss")
"pop3-sig.ss")
(module pop3-unit mzscheme
(require (lib "unitsig.ss")
(lib "etc.ss"))
(require "pop3-sig.ss")
(provide net:pop3@)
(define net:pop3@
(unit/sig net:pop3^
(import)
(import)
(export pop3^)
;; Implements RFC 1939, Post Office Protocol - Version 3, Myers & Rose
@ -411,5 +406,5 @@
(regexp-match matcher first))
desireds)
(cons first (loop rest))
(loop rest))))))))))
(loop rest))))))))

View File

@ -1,17 +1,12 @@
(module qp-sig mzscheme
(require (lib "unitsig.ss"))
(module qp-sig (lib "a-signature.ss")
;; -- exceptions raised --
(struct qp-error () -setters -constructor)
(struct qp-wrong-input () -setters -constructor)
(struct qp-wrong-line-size (size) -setters -constructor)
(provide net:qp^)
(define-signature net:qp^
(
;; -- exceptions raised --
(struct qp-error () -setters (- make-qp-error))
(struct qp-wrong-input () -setters (- make-qp-wrong-input))
(struct qp-wrong-line-size (size) -setters (- make-qp-wrong-line-size))
;; -- qp methods --
qp-encode
qp-decode
qp-encode-stream
qp-decode-stream
)))
;; -- qp methods --
qp-encode
qp-decode
qp-encode-stream
qp-decode-stream
)

View File

@ -25,15 +25,12 @@
;;
;; Commentary:
(module qp-unit mzscheme
(module qp-unit (lib "a-unit.ss")
(require "qp-sig.ss"
(lib "unitsig.ss")
(lib "etc.ss"))
(provide net:qp@)
(define net:qp@
(unit/sig net:qp^
(import)
(import)
(export qp^)
;; Exceptions:
;; String or input-port expected:
@ -171,6 +168,6 @@
(vector-set! hex-values (+ i 65) (+ 10 i))
(vector-set! hex-values (+ i 97) (+ 10 i))
(vector-set! hex-bytes (+ 10 i) (+ i 65))
(loop (add1 i)))))))
(loop (add1 i)))))
;;; qp-unit.ss ends here

View File

@ -1,11 +1,5 @@
(module sendmail-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:sendmail^)
(define-signature net:sendmail^
(send-mail-message/port
send-mail-message
(struct no-mail-recipients ()))))
(module sendmail-sig (lib "a-signature.ss")
send-mail-message/port
send-mail-message
(struct no-mail-recipients ()))

View File

@ -1,14 +1,9 @@
(module sendmail-unit (lib "a-unit.ss")
(require (lib "process.ss")
"sendmail-sig.ss")
(module sendmail-unit mzscheme
(require (lib "unitsig.ss")
(lib "process.ss"))
(require "sendmail-sig.ss")
(provide net:sendmail@)
(define net:sendmail@
(unit/sig net:sendmail^
(import)
(import)
(export sendmail^)
(define-struct (no-mail-recipients exn) ())
@ -121,4 +116,4 @@
(display s writer) ; We use -i, so "." is not a problem
(newline writer))
text)
(close-output-port writer)))))))
(close-output-port writer)))))

View File

@ -1,11 +1,6 @@
(module smtp-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:smtp^)
(define-signature net:smtp^
(smtp-sending-server
smtp-send-message
smtp-send-message*
smtp-sending-end-of-message)))
(module smtp-sig (lib "a-signature.ss")
smtp-sending-server
smtp-send-message
smtp-send-message*
smtp-sending-end-of-message)

View File

@ -1,15 +1,10 @@
(module smtp-unit (lib "a-unit.ss")
(require (lib "kw.ss")
"base64.ss"
"smtp-sig.ss")
(module smtp-unit mzscheme
(require (lib "unitsig.ss")
(lib "kw.ss")
"base64.ss")
(require "smtp-sig.ss")
(provide net:smtp@)
(define net:smtp@
(unit/sig net:smtp^
(import)
(import)
(export smtp^)
(define smtp-sending-server (make-parameter "localhost"))
@ -133,4 +128,4 @@
(values (current-input-port) (current-output-port))
(tcp-connect server opt-port-no))])
(smtp-send-message* r w sender recipients header message-lines
auth-user auth-passwd)))))))
auth-user auth-passwd)))))

View File

@ -1,14 +1,10 @@
(module uri-codec-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:uri-codec^)
(define-signature net:uri-codec^
(uri-encode
uri-decode
uri-path-segment-encode
uri-path-segment-decode
form-urlencoded-encode
form-urlencoded-decode
alist->form-urlencoded
form-urlencoded->alist
current-alist-separator-mode)))
(module uri-codec-sig (lib "a-signature.ss")
uri-encode
uri-decode
uri-path-segment-encode
uri-path-segment-decode
form-urlencoded-encode
form-urlencoded-decode
alist->form-urlencoded
form-urlencoded->alist
current-alist-separator-mode)

View File

@ -167,21 +167,17 @@ JALQefhDMCATcl2/bZL0bw==
;; Draws inspiration from encode-decode.scm by Kurt Normark and a code
;; sample provided by Eli Barzilay
(module uri-codec-unit mzscheme
(module uri-codec-unit (lib "a-unit.ss")
(require (lib "unitsig.ss")
(lib "match.ss")
(require (lib "match.ss")
(lib "string.ss")
(lib "list.ss")
(lib "etc.ss")
"uri-codec-sig.ss")
(provide uri-codec@)
(define uri-codec@
(unit/sig net:uri-codec^
(import)
(import)
(export uri-codec^)
(define (self-map-char ch) (cons ch ch))
(define (self-map-chars str) (map self-map-char (string->list str)))
@ -375,6 +371,6 @@ JALQefhDMCATcl2/bZL0bw==
(raise-type-error 'current-alist-separator-mode
"'amp, 'semi, or 'amp-or-semi"
s))
s))))))
s))))
;;; uri-codec-unit.ss ends here

View File

@ -1,19 +1,15 @@
(module url-sig mzscheme
(require (lib "unitsig.ss"))
(provide net:url^)
(define-signature net:url^
(get-pure-port
get-impure-port
post-pure-port
post-impure-port
display-pure-port
purify-port
netscape/string->url
string->url
url->string
call/input-url
combine-url/relative
url-exception?
current-proxy-servers)))
(module url-sig (lib "a-signature.ss")
get-pure-port
get-impure-port
post-pure-port
post-impure-port
display-pure-port
purify-port
netscape/string->url
string->url
url->string
call/input-url
combine-url/relative
url-exception?
current-proxy-servers)

View File

@ -11,7 +11,7 @@
(module url-unit mzscheme
(require (lib "file.ss")
(lib "unitsig.ss")
(lib "unit.ss")
(lib "port.ss")
(lib "string.ss")
(lib "list.ss")
@ -26,9 +26,9 @@
(define url:os-type (system-type))
(define (set-url:os-type! new) (set! url:os-type new))
(define url@
(unit/sig net:url^
(import net:tcp^)
(define-unit url@
(import tcp^)
(export url^)
(define-struct (url-exception exn:fail) ())
@ -445,4 +445,4 @@
(apply string-append (reverse! r))
(loop (cdr strings) (list* (car strings) sep r))))]))
)))
))

View File

@ -3,8 +3,7 @@
(Section 'pconvert)
(require (lib "unit.ss")
(lib "file.ss")
(require (lib "file.ss")
(lib "class.ss")
(lib "pconvert.ss"))
@ -12,7 +11,6 @@
(quasi-read-style-printing #f)
(define (xl) 1)
(define (xu) (unit (import) (export)))
(define (xc) (class object% () (sequence (super-init))))
(let ()
@ -174,7 +172,6 @@
(make-pctest null 'empty 'empty 'empty '`() '`() '`() 'empty)
(make-same-test add1 'add1)
(make-same-test (void) '(void))
(make-same-test (unit (import) (export)) '(unit ...))
(make-same-test (make-weak-box 12) '(make-weak-box 12))
(make-same-test (regexp "1") '(regexp "1"))
(make-same-test (module-path-index-join #f #f) '(module-path-index-join false false))
@ -190,12 +187,6 @@
(make-same-test (letrec ([xc-ID-BETTER-NOT-BE-DEFINED (class object% ())])
xc-ID-BETTER-NOT-BE-DEFINED)
'(class ...))
(make-same-test xu 'xu)
(make-same-test (letrec ([xu (unit (import) (export))]) xu)
'(unit ...))
(make-same-test (letrec ([xu-ID-BETTER-NOT-BE-DEFINED (unit (import) (export))])
xu-ID-BETTER-NOT-BE-DEFINED)
'(unit ...))
(make-same-test (lambda (x) x) '(lambda (a1) ...))
(make-same-test (lambda x x) '(lambda args ...))
(make-same-test (lambda (a b . c) a) '(lambda (a1 a2 . args) ...))
@ -360,7 +351,6 @@
(test-shared (lambda (x) x) '(lambda (a1) ...))
(test-shared (delay 1) '(delay ...))
(test-shared (class object% ()) '(class ...))
(test-shared (unit (import) (export)) '(unit ...))
(test-shared (new (class object% (super-new))) '(instantiate (class ...) ...))
(test-shared "abc" "abc")

View File

@ -2,7 +2,7 @@
(load-relative "loadtest.ss")
(Section 'unit)
(require (lib "unit.ss"))
(require (lib "unit200.ss"))
(syntax-test #'(unit))
(syntax-test #'(unit (import)))

View File

@ -1,8 +1,8 @@
(load-relative "loadtest.ss")
(require (lib "unit.ss"))
(require (lib "unitsig.ss"))
(require (lib "unit200.ss"))
(require (lib "unitsig200.ss"))
(require (lib "include.ss"))
(Section 'unit/sig)