298 lines
8.9 KiB
Scheme
298 lines
8.9 KiB
Scheme
|
|
(module classidmap mzscheme
|
|
|
|
(require (lib "stx.ss" "syntax"))
|
|
|
|
(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-object this-id name src)))
|
|
|
|
;; Check Syntax binding info:
|
|
(define (binding from to stx)
|
|
stx
|
|
;; This 'bound-in-source is no longer needed
|
|
#;
|
|
(syntax-property
|
|
stx
|
|
'bound-in-source
|
|
(cons from (syntax-local-introduce to))))
|
|
|
|
|
|
(define (make-this-map orig-id the-finder the-obj)
|
|
(let ([set!-stx (datum->syntax-object the-finder 'set!)])
|
|
(mk-set!-trans
|
|
orig-id
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(raise-syntax-error 'class "cannot mutate object identifier" stx)]
|
|
[(id . args)
|
|
(datum->syntax-object
|
|
stx
|
|
(cons (find the-finder the-obj stx) (syntax args))
|
|
stx)]
|
|
[id (find the-finder the-obj stx)])))))
|
|
|
|
(define (make-field-map the-finder the-obj the-binder the-binder-localized field-accessor field-mutator field-pos/null)
|
|
(let ([set!-stx (datum->syntax-object the-finder 'set!)])
|
|
(mk-set!-trans
|
|
the-binder-localized
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(binding
|
|
the-binder (syntax id)
|
|
(datum->syntax-object
|
|
the-finder
|
|
(list* field-mutator (find the-finder the-obj stx) (append field-pos/null (list (syntax expr))))
|
|
stx))]
|
|
[(id . args)
|
|
(binding
|
|
the-binder (syntax id)
|
|
(datum->syntax-object
|
|
the-finder
|
|
(cons (list* field-accessor (find the-finder the-obj stx) field-pos/null) (syntax args))
|
|
stx))]
|
|
[_else
|
|
(binding
|
|
the-binder stx
|
|
(datum->syntax-object
|
|
the-finder
|
|
(list* field-accessor (find the-finder the-obj stx) field-pos/null)
|
|
stx))])))))
|
|
|
|
(define (make-method-map the-finder the-obj the-binder the-binder-localized method-accessor)
|
|
(let ([set!-stx (datum->syntax-object the-finder 'set!)])
|
|
(mk-set!-trans
|
|
the-binder-localized
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(raise-syntax-error 'class "cannot mutate method" stx)]
|
|
[(id . args)
|
|
(binding
|
|
the-binder (syntax id)
|
|
(datum->syntax-object
|
|
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-object the-finder 'set!)])
|
|
(mk-set!-trans
|
|
the-binder-localized
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(raise-syntax-error 'class "cannot mutate method" stx)]
|
|
[(id . args)
|
|
(binding
|
|
the-binder (syntax id)
|
|
(datum->syntax-object
|
|
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-object the-finder 'set!)])
|
|
(mk-set!-trans
|
|
the-binder-localized
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(raise-syntax-error 'class "cannot mutate super method" stx)]
|
|
[(id . args)
|
|
(binding
|
|
the-binder (syntax id)
|
|
(datum->syntax-object
|
|
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-object the-finder 'set!)]
|
|
[lambda-stx (datum->syntax-object the-finder 'lambda)])
|
|
(mk-set!-trans
|
|
the-binder-localized
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(raise-syntax-error 'class "cannot mutate inner method" stx)]
|
|
[(id (lambda () default) . args)
|
|
(module-identifier=? (syntax lambda) lambda-stx)
|
|
(let ([target (find the-finder the-obj stx)])
|
|
(binding
|
|
the-binder (syntax id)
|
|
(datum->syntax-object
|
|
the-finder
|
|
(make-method-apply (list (find the-finder rename-temp stx) target #'default)
|
|
target (syntax args))
|
|
stx)))]
|
|
[(id (lambda largs default) . args)
|
|
(module-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)
|
|
(module-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-object
|
|
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-object
|
|
the-finder
|
|
(let ([target (find the-finder the-obj stx)])
|
|
(datum->syntax-object
|
|
the-finder
|
|
(make-method-apply (list (find the-finder rename-temp stx) target default-expr)
|
|
target args)
|
|
stx))
|
|
stx))
|
|
|
|
(define init-error-map
|
|
(make-set!-transformer
|
|
(lambda (stx)
|
|
(raise-syntax-error
|
|
'class
|
|
"cannot use non-field init variable in a method"
|
|
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 set!-stx id-stx method-stx method-obj-stx)
|
|
(make-set!-transformer
|
|
(lambda (stx)
|
|
(syntax-case stx ()
|
|
[(set! id expr)
|
|
(module-identifier=? (syntax set!) set!-stx)
|
|
(raise-syntax-error 'with-method "cannot mutate method" stx)]
|
|
[(id . args)
|
|
(datum->syntax-object
|
|
set!-stx
|
|
(make-method-apply
|
|
method-stx
|
|
method-obj-stx
|
|
(syntax args))
|
|
stx)]
|
|
[_else
|
|
(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))
|
|
|
|
(define (localize orig-id)
|
|
(let loop ([id orig-id])
|
|
(let ([v (syntax-local-value id (lambda () #f))])
|
|
(cond
|
|
[(and v (private-name? v))
|
|
(list 'unquote
|
|
(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-immutable v c)
|
|
(list-immutable v))))
|
|
|
|
(define (class-top-level-context? ctx)
|
|
(and (pair? ctx)
|
|
(class-context? (car ctx))))
|
|
|
|
(provide (protect make-this-map make-field-map make-method-map
|
|
make-direct-method-map
|
|
make-rename-super-map make-rename-inner-map
|
|
init-error-map super-error-map
|
|
make-with-method-map
|
|
flatten-args
|
|
make-private-name localize
|
|
generate-super-call generate-inner-call
|
|
generate-class-expand-context class-top-level-context?)))
|