original commit: 5033132dc4c37c9dd562672ee2549db4f94b6f02
This commit is contained in:
Matthew Flatt 2001-09-10 19:53:26 +00:00
parent 50cc9a71ce
commit 1ec8f5ceed
3 changed files with 324 additions and 233 deletions

View File

@ -217,6 +217,8 @@
;; ----- Sort body into different categories -----
(let ([extract (lambda (kws l out-cons)
;; returns two lists: expressions that start with an identifier in `kws',
;; and expressions that don't
(let loop ([l l])
(if (null? l)
(values null null)
@ -311,12 +313,32 @@
;; ----- Extract method definitions; check that they look like procs -----
;; Optionally transform them, can expand even if not transforming.
(let* ([local-public-normal-names (map car (append publics overrides))]
(let* ([field-names (map
(lambda (i)
(if (identifier? i)
i
(stx-car i)))
(append plain-fields plain-init-fields))]
[inherit-field-names inherit-fields]
[plain-init-names (map
(lambda (i)
(if (identifier? i)
i
(stx-car i)))
plain-inits)]
[inherit-names (map car inherits)]
[rename-names (map car renames)]
[local-public-normal-names (map car (append publics overrides))]
[local-public-names (append (map car (append public-finals override-finals))
local-public-normal-names)]
[local-method-names (append (map car privates) local-public-names)]
[expand-stop-names (append
local-method-names
field-names
inherit-field-names
plain-init-names
inherit-names
rename-names
(list
this-id
super-instantiate-id
@ -326,8 +348,8 @@
[add-method-property (lambda (l)
(syntax-property l 'method-arity-error #t))]
[proc-shape (lambda (name expr xform?)
;; expands an expression so we can check whether
;; it has the right form
;; expands an expression enough that we can check whether
;; it has the right form; must use local syntax definitions
(define (expand expr locals)
(local-expand
expr
@ -453,11 +475,14 @@
(loop (expand stx locals) #f name locals)
(bad "bad form for method definition" stx))])))])
;; Do the extraction:
(let-values ([(methods private-methods exprs)
(let loop ([exprs exprs][ms null][pms null][es null])
(let-values ([(methods ; (listof (cons id stx))
private-methods ; (listof (cons id stx))
exprs ; (listof stx)
stx-defines) ; (listof (cons (listof id) stx))
(let loop ([exprs exprs][ms null][pms null][es null][sd null])
(if (null? exprs)
(values (reverse! ms) (reverse! pms) (reverse! es))
(syntax-case (car exprs) (define-values)
(values (reverse! ms) (reverse! pms) (reverse! es) (reverse! sd))
(syntax-case (car exprs) (define-values define-syntaxes)
[(define-values (id ...) expr)
(let ([ids (syntax->list (syntax (id ...)))])
;; Check form:
@ -486,16 +511,26 @@
(if public?
pms
(cons (cons (car ids) expr) pms))
es)))
es
sd)))
;; Non-method defn:
(loop (cdr exprs) ms pms (cons (car exprs) es))))]
(loop (cdr exprs) ms pms (cons (car exprs) es) sd)))]
[(define-values . _)
(bad "ill-formed definition" (car exprs))]
[(define-syntaxes (id ...) expr)
(let ([ids (syntax->list (syntax (id ...)))])
(for-each (lambda (id) (unless (identifier? id)
(bad "syntax name is not an identifier" id)))
ids)
(loop (cdr exprs) ms pms es (cons (cons ids (car exprs)) sd)))]
[(define-syntaxes . _)
(bad "ill-formed syntax definition" (car exprs))]
[_else
(loop (cdr exprs) ms pms (cons (car exprs) es))])))])
(loop (cdr exprs) ms pms (cons (car exprs) es) sd)])))])
;; ---- Extract all defined names, including field accessors and mutators ---
(let ([defined-method-names (append (map car methods)
(let ([defined-syntax-names (apply append (map car stx-defines))]
[defined-method-names (append (map car methods)
(map car private-methods))]
[private-field-names (let loop ([l exprs])
(if (null? l)
@ -505,19 +540,6 @@
(append (syntax->list (syntax (id ...)))
(loop (cdr l)))]
[_else (loop (cdr l))])))]
[field-names (map
(lambda (i)
(if (identifier? i)
i
(stx-car i)))
(append plain-fields plain-init-fields))]
[inherit-field-names inherit-fields]
[plain-init-names (map
(lambda (i)
(if (identifier? i)
i
(stx-car i)))
plain-inits)]
[init-mode (cond
[(null? init-rest-decls) 'normal]
[(stx-null? (stx-cdr (car init-rest-decls))) 'stop]
@ -525,13 +547,14 @@
;; -- Look for duplicates --
(let ([dup (check-duplicate-identifier
(append defined-method-names
(append defined-syntax-names
defined-method-names
private-field-names
field-names
inherit-field-names
plain-init-names
(map car inherits)
(map car renames)
inherit-names
rename-names
(list this-id super-instantiate-id super-make-object-id)))])
(when dup
(bad "duplicate declared identifier" dup)))
@ -542,19 +565,31 @@
(bad "duplicate declared identifier" dup)))
;; -- Check that private/public/override are defined --
(let ([ht (make-hash-table)])
(let ([ht (make-hash-table)]
[stx-ht (make-hash-table)])
(for-each
(lambda (defined-name)
(let ([l (hash-table-get ht (syntax-e defined-name) (lambda () null))])
(hash-table-put! ht (syntax-e defined-name) (cons defined-name l))))
defined-method-names)
(for-each
(lambda (defined-name)
(let ([l (hash-table-get stx-ht (syntax-e defined-name) (lambda () null))])
(hash-table-put! stx-ht (syntax-e defined-name) (cons defined-name l))))
defined-syntax-names)
(for-each
(lambda (pubovr-name)
(let ([l (hash-table-get ht (syntax-e pubovr-name) (lambda () null))])
(unless (ormap (lambda (i) (bound-identifier=? i pubovr-name)) l)
(bad
"method declared but not defined"
pubovr-name))))
;; Either undefined or defined as syntax:
(let ([stx-l (hash-table-get stx-ht (syntax-e pubovr-name) (lambda () null))])
(if (ormap (lambda (i) (bound-identifier=? i pubovr-name)) stx-l)
(bad
"method declared but defined as syntax"
pubovr-name)
(bad
"method declared but not defined"
pubovr-name))))))
local-method-names))
;; ---- Convert expressions ----
@ -760,8 +795,9 @@
[the-finder the-finder]
[super-instantiate-id super-instantiate-id]
[super-make-object-id super-make-object-id]
[name class-name])
[name class-name]
[(stx-def ...) (map cdr stx-defines)])
(syntax
(let ([superclass super-expression]
[interfaces (list interface-expr ...)])
@ -789,30 +825,31 @@
rename-temp ...
method-accessor ...) ; public, override, inherit
(letrec-syntaxes+values mappings ()
(letrec ([private-temp private-method]
...
[public-final-temp public-final-method]
...
[override-final-temp override-final-method]
...)
(values
(list public-final-temp ... . public-methods)
(list override-final-temp ... . override-methods)
;; Initialization
(lambda (the-obj super-id init-args)
(fluid-let-syntax ([the-finder (quote-syntax the-obj)])
(letrec-syntax ([super-instantiate-id
(lambda (stx)
(syntax-case stx ()
[(_ (arg (... ...)) (kw kwarg) (... ...))
(syntax (-instantiate super-id _ #f (list arg (... ...)) (kw kwarg) (... ...)))]))])
(let ([super-make-object-id
(lambda args
(super-id #f args null))])
(let ([plain-init-name undefined]
...)
(void) ; in case the body is empty
. exprs)))))))))
stx-def ...
(letrec ([private-temp private-method]
...
[public-final-temp public-final-method]
...
[override-final-temp override-final-method]
...)
(values
(list public-final-temp ... . public-methods)
(list override-final-temp ... . override-methods)
;; Initialization
(lambda (the-obj super-id init-args)
(fluid-let-syntax ([the-finder (quote-syntax the-obj)])
(letrec-syntax ([super-instantiate-id
(lambda (stx)
(syntax-case stx ()
[(_ (arg (... ...)) (kw kwarg) (... ...))
(syntax (-instantiate super-id _ #f (list arg (... ...)) (kw kwarg) (... ...)))]))])
(let ([super-make-object-id
(lambda args
(super-id #f args null))])
(let ([plain-init-name undefined]
...)
(void) ; in case the body is empty
. exprs)))))))))
;; Not primitive:
#f)))))))))))))))])))

View File

@ -7,7 +7,7 @@
[tab ""])
(let ([mk-chain
(lambda (load)
(lambda (filename)
(lambda (filename expected-module)
(fprintf ep
"~aloading ~a at ~a~n"
tab filename (current-process-milliseconds))
@ -18,10 +18,10 @@
(lambda ()
(if (regexp-match "_loader" filename)
(let ([f (load filename)])
(lambda (sym)
(lambda (sym expected-module)
(fprintf ep
"~atrying ~a's ~a~n" tab filename sym)
(let ([loader (f sym)])
(let ([loader (f sym expected-module)])
(and loader
(lambda ()
(fprintf ep
@ -38,7 +38,7 @@
"~adone ~a's ~a at ~a~n"
tab filename sym
(current-process-milliseconds)))))))))
(load filename)))
(load filename expected-module)))
(lambda () (set! tab s))))
(fprintf ep
"~adone ~a at ~a~n"

View File

@ -4,20 +4,26 @@
(module unit mzscheme
(require-for-syntax (lib "kerncase.ss" "syntax")
(lib "stx.ss" "syntax")
"list.ss"
"private/unitidmap.ss")
(define undefined (letrec ([x x]) x))
;; ----------------------------------------------------------------------
;; 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))
(define-struct (exn:unit struct:exn) ())
(define-struct unit (num-imports exports go)) ; unit value
(define-struct (exn:unit struct:exn) ()) ; 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
@ -26,6 +32,9 @@
make-unit)
num-imports exports go))
;; ----------------------------------------------------------------------
;; The `unit' syntactic form
(define-syntax unit
(lambda (stx)
(syntax-case stx (import export)
@ -112,39 +121,52 @@
[else (list defn-or-expr)]))
expanded))))])
(let ([all-expanded (expand-all (syntax->list (syntax (defn&expr ...))))])
;; Get all the defined names
(let ([all-defined-names
(apply
append
(map
(lambda (defn-or-expr)
(syntax-case defn-or-expr (define-values define-syntax)
[(define-values (id ...) expr)
(let ([l (syntax->list (syntax (id ...)))])
(for-each (lambda (i)
(unless (identifier? i)
(raise-syntax-error
'unit
"not an identifier in definition"
stx
i)))
l)
l)]
[(define-values . l)
(raise-syntax-error
'unit
"bad definition form"
stx
defn-or-expr)]
[(define-syntax . l)
(raise-syntax-error
'unit
"misplaced syntax definition"
stx
defn-or-expr)]
[else null]))
all-expanded))])
;; Check that all defined names are distinct:
;; Get all the defined names, sorting out variable definitions
;; from syntax definitions.
(let* ([definition?
(lambda (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
'unit
"not an identifier in definition"
stx
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
'unit
"bad definition form"
stx
defn-or-expr)]
[(define-syntaxes . l)
(raise-syntax-error
'unit
"bad syntax definition form"
stx
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
@ -153,22 +175,34 @@
"variable imported and/or defined twice"
stx
name)))
;; Check that all exported names are defined:
(let ([ht (make-hash-table)])
;; Check that all exported names are defined (as var):
(let ([ht (make-hash-table)]
[stx-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))))
all-defined-names)
(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)
(raise-syntax-error
'unit
"exported variable is not defined"
stx
n))))
;; 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
'unit
"cannot export syntax from a unit"
stx
n)
(raise-syntax-error
'unit
"exported variable is not defined"
stx
n))))))
exported-names))
;; Compute defined but not exported:
@ -179,7 +213,7 @@
(hash-table-put! ht (syntax-e name) (cons name l))))
exported-names)
(let ([internal-names
(let loop ([l all-defined-names])
(let loop ([l all-defined-val-names])
(cond
[(null? l) null]
[(let ([v (hash-table-get ht (syntax-e (car l)) (lambda () null))])
@ -196,55 +230,64 @@
;; because set! on exported variables is not allowed.
(with-syntax ([(defn&expr ...)
(let ([elocs (syntax->list (syntax (eloc ...)))])
(map (lambda (defn-or-expr)
(syntax-case defn-or-expr (define-values)
[(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 ...))))))))]
[else defn-or-expr]))
all-expanded))])
(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) defn-or-expr]
[else #f]))
all-expanded))])
;; Build up set! redirection chain:
(with-syntax ([redirections
(let ([varlocs
@ -276,8 +319,12 @@
(lambda (iloc ...)
(let ([intname undefined] ...)
(letrec-syntaxes+values redirections ()
stx-defn ...
(void) ; in case the body would be empty
defn&expr ...))))))))))))))))))])))
;; ----------------------------------------------------------------------
;; check-expected-interface: used by the expansion of `compound-unit'
(define (check-expected-interface tag unit num-imports exports)
(unless (unit? unit)
@ -308,6 +355,9 @@
[else (loop (cdr l) (add1 i))])))
exports)))
;; ----------------------------------------------------------------------
;; The `compound-unit' syntactic form
(define-syntax compound-unit
(lambda (stx)
(syntax-case stx (import export link)
@ -656,6 +706,9 @@
(append . import-mapping))
...))))))))))))))))))])))
;; ----------------------------------------------------------------------
;; check-unit: used by the expansion of `invoke-unit'
(define (check-unit u n)
(unless (unit? u)
(raise
@ -669,6 +722,9 @@
n (unit-num-imports u))
(current-continuation-marks)))))
;; ----------------------------------------------------------------------
;; The `invoke-unit' syntactic form
(define-syntax invoke-unit
(lambda (stx)
(syntax-case stx (import export)
@ -687,81 +743,79 @@
((list-ref ((unit-go u)) 1)
bx ...))))))])))
(define-syntax do-define-values/invoke-unit
(lambda (stx)
(syntax-case stx ()
[(_ global? exports unite prefix imports orig)
(let* ([badsyntax (lambda (s why)
(raise-syntax-error
(if (syntax-e (syntax global?))
'namespace-variable-bind/invoke-unit
'define-values/invoke-unit)
(format "bad syntax (~a)" why)
(syntax orig)
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)))
(unless (or (not (syntax-e (syntax prefix)))
(identifier? (syntax prefix)))
(badsyntax (syntax prefix) "prefix is not an identifier"))
(for-each symcheck (syntax->list (syntax imports)))
(with-syntax ([(tagged-export ...)
(if (syntax-e (syntax prefix))
(let ([prefix (string-append
(symbol->string
(syntax-e (syntax 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 (syntax (invoke-unit
(compound-unit
(import . imports)
(link [unit-to-invoke (unite . imports)]
[export-extractor
(extract-unit (unit-to-invoke . exports))])
(export))
. imports))])
(if (syntax-e (syntax global?))
(syntax (let-values ([(tagged-export ...) invoke-unit])
(namespace-variable-binding 'tagged-export tagged-export)
...
(void)))
(syntax (define-values (tagged-export ...) invoke-unit))))))])))
(define-syntax define-values/invoke-unit
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ exports unit name . imports)
(syntax (do-define-values/invoke-unit #f exports unit name imports orig))]
[(_ exports unit)
(syntax (do-define-values/invoke-unit #f exports unit #f () orig))]))))
(define-syntax namespace-variable-bind/invoke-unit
(lambda (stx)
(with-syntax ([orig stx])
(syntax-case stx ()
[(_ exports unit name . imports)
(syntax (do-define-values/invoke-unit #t exports unit name imports orig))]
[(_ exports unit)
(syntax (do-define-values/invoke-unit #t exports unit #f () orig))]))))
(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
(if global?
'namespace-variable-bind/invoke-unit
'define-values/invoke-unit)
(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-variable-binding 'tagged-export tagged-export)
...
(void)))
(syntax (define-values (tagged-export ...) invoke-unit)))))))])))])
(values (mk #f) (mk #t))))
(provide unit compound-unit invoke-unit unit?
exn:unit? struct:exn:unit make-exn:unit