racket/collects/scheme/private/classidmap.ss
Stevie Strickland 14ab0175c3 Okay, expanding field accesses and mutations to basically inline the
unwrapping operation helps a bit, especially with inherited fields.
Unfortunately, as one might expect, TANSTAAFL applies here.  In order
to make sure that we keep the contracted objects around as much as
possible to make sure there are no holes, we end up making local and
inherited field access codes 2-3x more than they did before.  However,
this is still something on the order of 5x faster than external
access.  But blah.

CONTRACTS ARE NOT FREE.  Just ask your local lawyer.

svn: r18285
2010-02-23 03:15:43 +00:00

385 lines
14 KiB
Scheme

#lang scheme/base
(require syntax/stx
(for-syntax scheme/base)
(for-template scheme/base "class-events.ss"))
(define-values (struct:s!t make-s!t s!t? s!t-ref s!t-set!)
(make-struct-type 'set!-transformer #f 2 0 #f null (current-inspector) 0))
(define (mk-set!-trans old-id proc)
(make-set!-transformer (make-s!t proc old-id)))
(define (make-method-apply id this orig-args)
(let loop ([args orig-args][accum null])
(cond
[(stx-null? args)
(list* id this orig-args)]
[(stx-pair? args)
(loop (stx-cdr args) (cons (stx-car args) accum))]
[else
(list* 'apply id this (reverse (cons args accum)))])))
(define (find the-finder name src)
(let ([this-id (syntax-local-value (syntax-local-get-shadower the-finder))])
(datum->syntax this-id name src)))
;; Check Syntax binding info:
(define (binding from to stx)
stx)
(define (make-this-map orig-id the-finder the-obj)
(let ([set!-stx (datum->syntax the-finder 'set!)])
(mk-set!-trans
orig-id
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(raise-syntax-error 'class "cannot mutate object identifier" stx)]
[(id . args)
(datum->syntax
stx
(cons (find the-finder the-obj stx) (syntax args))
stx)]
[id (find the-finder the-obj stx)])))))
(define (make-this%-map replace-stx the-finder)
(let ([set!-stx (datum->syntax the-finder 'set!)])
(make-set!-transformer
(λ (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? #'set! set!-stx)
(raise-syntax-error 'class "cannot mutate this% identifier" stx)]
[id
(identifier? #'id)
(quasisyntax/loc stx #,replace-stx)]
[(f . args)
(quasisyntax/loc stx (#,replace-stx . args))])))))
(define (make-field-map trace-flag the-finder the-obj unwrapper the-binder the-binder-localized
field-accessor field-mutator field-pos/null)
(let ([set!-stx (datum->syntax the-finder 'set!)])
(mk-set!-trans
the-binder-localized
(lambda (stx)
(with-syntax ([obj-expr (find the-finder the-obj stx)])
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(with-syntax ([bindings (syntax/loc stx ([obj obj-expr] [id expr]))]
[trace (syntax/loc stx (set-event obj (quote id) id))]
[set (quasisyntax/loc stx
((unsyntax field-mutator)
((unsyntax unwrapper) obj)
(unsyntax-splicing field-pos/null) id))])
(if trace-flag
(syntax/loc stx (let* bindings trace set))
(syntax/loc stx (let* bindings set))))]
[(id . args)
(with-syntax ([bindings (syntax/loc stx ([obj obj-expr]))]
[trace (syntax/loc stx (get-event obj (quote id)))]
[call (quasisyntax/loc stx
(((unsyntax field-accessor)
((unsyntax unwrapper) obj-expr)
(unsyntax-splicing field-pos/null)) . args))])
(if trace-flag
(syntax/loc stx (let* bindings trace call))
(syntax/loc stx (let* bindings call))))]
[id
(with-syntax ([bindings (syntax/loc stx ([obj obj-expr]))]
[trace (syntax/loc stx (get-event obj (quote id)))]
[get (quasisyntax/loc stx
((unsyntax field-accessor)
((unsyntax unwrapper) obj-expr)
(unsyntax-splicing field-pos/null)))])
(if trace-flag
(syntax/loc stx (let* bindings trace get))
(syntax/loc stx (let* bindings get))))]))))))
(define (make-method-map the-finder the-obj the-binder the-binder-localized method-accessor)
(let ([set!-stx (datum->syntax the-finder 'set!)])
(mk-set!-trans
the-binder-localized
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(raise-syntax-error 'class "cannot mutate method" stx)]
[(id . args)
(binding
the-binder (syntax id)
(datum->syntax
the-finder
(make-method-apply
(list method-accessor (find the-finder the-obj stx))
(find the-finder the-obj stx)
(syntax args))
stx))]
[_else
(raise-syntax-error
'class
"misuse of method (not in application)"
stx)])))))
;; For methods that are dirrectly available via their names
;; (e.g., private methods)
(define (make-direct-method-map the-finder the-obj the-binder the-binder-localized new-name)
(let ([set!-stx (datum->syntax the-finder 'set!)])
(mk-set!-trans
the-binder-localized
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(raise-syntax-error 'class "cannot mutate method" stx)]
[(id . args)
(binding
the-binder (syntax id)
(datum->syntax
the-finder
(make-method-apply (find the-finder new-name stx) (find the-finder the-obj stx) (syntax args))
stx))]
[_else
(raise-syntax-error
'class
"misuse of method (not in application)"
stx)])))))
(define (make-rename-super-map the-finder the-obj the-binder the-binder-localized rename-temp)
(let ([set!-stx (datum->syntax the-finder 'set!)])
(mk-set!-trans
the-binder-localized
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(raise-syntax-error 'class "cannot mutate super method" stx)]
[(id . args)
(binding
the-binder (syntax id)
(datum->syntax
the-finder
(make-method-apply (find the-finder rename-temp stx) (find the-finder the-obj stx) (syntax args))
stx))]
[_else
(raise-syntax-error
'class
"misuse of super method (not in application)"
stx)])))))
(define (make-rename-inner-map the-finder the-obj the-binder the-binder-localized rename-temp)
(let ([set!-stx (datum->syntax the-finder 'set!)]
[lambda-stx (datum->syntax the-finder 'lambda)])
(mk-set!-trans
the-binder-localized
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(raise-syntax-error 'class "cannot mutate inner method" stx)]
[(id (lambda () default) . args)
(free-identifier=? (syntax lambda) lambda-stx)
(let ([target (find the-finder the-obj stx)])
(binding
the-binder (syntax id)
(datum->syntax
the-finder
(make-method-apply (list (find the-finder rename-temp stx) target #'default)
target (syntax args))
stx)))]
[(id (lambda largs default) . args)
(free-identifier=? (syntax lambda) lambda-stx)
(raise-syntax-error
'class
"misuse of inner method (lambda for default does not take zero arguments)"
stx)]
[(id (lambda . rest) . args)
(free-identifier=? (syntax lambda) lambda-stx)
(raise-syntax-error
'class
"misuse of inner method (ill-formed lambda for default)"
stx)]
[(id . args)
(raise-syntax-error
'class
"misuse of inner method (no lambda-wrapped default after name)"
stx)]
[_else
(raise-syntax-error
'class
"misuse of inner method (not in application)"
stx)])))))
(define (generate-super-call stx the-finder the-obj rename-temp args)
(datum->syntax
the-finder
(make-method-apply (find the-finder rename-temp stx)
(find the-finder the-obj stx)
args)
stx))
(define (generate-inner-call stx the-finder the-obj default-expr rename-temp args)
(datum->syntax
the-finder
(let ([target (find the-finder the-obj stx)])
(datum->syntax
the-finder
`(let ([i (,(find the-finder rename-temp stx) ,target)])
(if i
,(make-method-apply 'i target args)
,default-expr))
stx))
stx))
(define (make-init-error-map localized-id)
(mk-set!-trans
localized-id
(lambda (stx)
(raise-syntax-error
'class
"cannot use non-field init variable in a method"
stx))))
(define (make-init-redirect set!-stx #%app-stx local-id localized-id)
(mk-set!-trans
localized-id
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(free-identifier=? (syntax set!) set!-stx)
(with-syntax ([local-id local-id])
(syntax/loc stx (set! local-id expr)))]
[(id . args)
(with-syntax ([local-id local-id]
[#%app #%app-stx])
(syntax/loc stx (#%app local-id . args)))]
[_else (datum->syntax
local-id
(syntax-e local-id)
stx
stx)]))))
(define super-error-map
(lambda (stx)
(raise-syntax-error
'class
"cannot use superclass initialization form in a method"
stx)))
(define (make-with-method-map trace-flag set!-stx id-stx
method-stx method-obj-stx unwrap-stx)
(make-set!-transformer
(lambda (stx)
(syntax-case stx ()
[(set! id expr)
(and (identifier? (syntax id))
(free-identifier=? (syntax set!) set!-stx))
(raise-syntax-error 'with-method "cannot mutate method" stx)]
[(id . args)
(identifier? (syntax id))
(let* ([args-stx (syntax args)]
[proper? (stx-list? args-stx)]
[flat-args-stx (if proper? args-stx (flatten-args args-stx))])
(make-method-call
trace-flag
stx
method-obj-stx
unwrap-stx
method-stx
(syntax (quote id))
flat-args-stx
(not proper?)))]
[id
(identifier? (syntax id))
(raise-syntax-error
'with-method
"misuse of method (not in application)"
stx)]))))
(define (flatten-args orig-args)
(let loop ([args orig-args][accum null])
(cond
[(stx-null? args) orig-args]
[(stx-pair? args)
(loop (stx-cdr args) (cons (stx-car args) accum))]
[else
(reverse (cons args accum))])))
(define-struct private-name (orig-id gen-id)
#:property prop:procedure (lambda (self stx)
(if (not (eq? (syntax-local-context) 'expression))
#`(#%expression #,stx)
(raise-syntax-error
#f
"unbound local member name"
stx))))
(define (do-localize orig-id validate-local-member-stx)
(let loop ([id orig-id])
(let ([v (syntax-local-value id (lambda () #f))])
(cond
[(and v (private-name? v))
(list 'unquote
(list validate-local-member-stx
(list 'quote orig-id)
(binding (private-name-orig-id v)
id
(private-name-gen-id v))))]
[(and (set!-transformer? v)
(s!t? (set!-transformer-procedure v)))
(s!t-ref (set!-transformer-procedure v) 1)]
[else orig-id]))))
(define-struct class-context ())
(define (generate-class-expand-context)
(let ([c (syntax-local-context)]
[v (make-class-context)])
(if (pair? c)
(cons v c)
(list v))))
(define (class-top-level-context? ctx)
(and (pair? ctx)
(class-context? (car ctx))))
(define (make-method-call traced? source-stx object-stx unwrap-stx
method-proc-stx method-name-stx args-stx rest-arg?)
(define-syntax (qstx stx)
(syntax-case stx ()
[(form body) (syntax/loc stx (quasisyntax/loc source-stx body))]))
(with-syntax ([object object-stx]
[method method-proc-stx]
[app (if rest-arg? (qstx apply) (qstx #%app))]
[args args-stx])
(if traced?
(with-syntax ([(mth obj) (generate-temporaries
(list object-stx method-proc-stx))]
[unwrap unwrap-stx]
[name method-name-stx]
[(arg ...) (qstx args)]
[(var ...) (generate-temporaries (qstx args))])
(qstx (let ([mth method]
[obj object]
[var arg] ...)
(initialize-call-event
(unwrap obj) name (app list var ...))
(call-with-values (lambda () (app mth obj var ...))
finalize-call-event))))
(qstx (app method object . args)))))
(provide (protect-out make-this-map make-this%-map make-field-map make-method-map
make-direct-method-map
make-rename-super-map make-rename-inner-map
make-init-error-map make-init-redirect super-error-map
make-with-method-map
flatten-args make-method-call
do-localize make-private-name
generate-super-call generate-inner-call
generate-class-expand-context class-top-level-context?))