Support private fields
This commit is contained in:
parent
4559981212
commit
bbd5d97a23
|
@ -25,7 +25,8 @@
|
|||
class:
|
||||
;; for use in ~literal clauses
|
||||
class:-internal
|
||||
optional-init)
|
||||
optional-init
|
||||
private-field)
|
||||
|
||||
;; give it a binding, but it shouldn't be used directly
|
||||
(define-syntax (class:-internal stx)
|
||||
|
@ -34,6 +35,9 @@
|
|||
(define-syntax (optional-init stx)
|
||||
(raise-syntax-error "should only be used internally"))
|
||||
|
||||
(define-syntax (private-field stx)
|
||||
(raise-syntax-error "should only be used internally"))
|
||||
|
||||
(begin-for-syntax
|
||||
(module+ test (require rackunit))
|
||||
|
||||
|
@ -239,7 +243,7 @@
|
|||
clause?
|
||||
non-clause?))
|
||||
(define name-dict (extract-names clauses))
|
||||
(define-values (annotated-methods other-top-level)
|
||||
(define-values (annotated-methods other-top-level private-fields)
|
||||
(process-class-contents others name-dict))
|
||||
(define annotated-super
|
||||
(syntax-property #'super 'tr:class:super #t))
|
||||
|
@ -258,6 +262,7 @@
|
|||
(public #,@(dict-ref name-dict #'public '()))
|
||||
(override #,@(dict-ref name-dict #'override '()))
|
||||
(private #,@(dict-ref name-dict #'private '()))
|
||||
(private-field #,@private-fields)
|
||||
(inherit #,@(dict-ref name-dict #'inherit '()))))
|
||||
(class #,annotated-super
|
||||
#,@(map clause-stx clauses)
|
||||
|
@ -265,18 +270,19 @@
|
|||
#,(syntax-property
|
||||
#`(begin #,@(map non-clause-stx other-top-level))
|
||||
'tr:class:top-level #t)
|
||||
#,(make-locals-table name-dict)))
|
||||
#,(make-locals-table name-dict private-fields)))
|
||||
'tr:class #t)
|
||||
'typechecker:ignore #t)])]))
|
||||
|
||||
(begin-for-syntax
|
||||
;; process-class-contents : Listof<Syntax> Dict<Id, Listof<Id>>
|
||||
;; -> Listof<Syntax> Listof<Syntax>
|
||||
;; -> Listof<Syntax> Listof<Syntax> Listof<Syntax>
|
||||
;; Process methods and other top-level expressions and definitions
|
||||
;; that aren't class clauses like `init` or `public`
|
||||
(define (process-class-contents contents name-dict)
|
||||
(for/fold ([methods '()]
|
||||
[rest-top '()])
|
||||
[rest-top '()]
|
||||
[private-fields '()])
|
||||
([content contents])
|
||||
(define stx (non-clause-stx content))
|
||||
(syntax-parse stx
|
||||
|
@ -293,13 +299,21 @@
|
|||
'tr:class:method
|
||||
(syntax-e #'id)))
|
||||
methods)
|
||||
rest-top)]
|
||||
rest-top private-fields)]
|
||||
;; private field definition
|
||||
[(define-values (id ...) . rst)
|
||||
(values methods
|
||||
(append rest-top (list content))
|
||||
(append (syntax->list #'(id ...))
|
||||
private-fields))]
|
||||
;; Identify super-new for the benefit of the type checker
|
||||
[(super-new [init-id init-expr] ...)
|
||||
(define new-non-clause
|
||||
(non-clause (syntax-property stx 'tr:class:super-new #t)))
|
||||
(values methods (append rest-top (list new-non-clause)))]
|
||||
[_ (values methods (append rest-top (list content)))])))
|
||||
(values methods (append rest-top (list new-non-clause))
|
||||
private-fields)]
|
||||
[_ (values methods (append rest-top (list content))
|
||||
private-fields)])))
|
||||
|
||||
;; get-optional-inits : Listof<Clause> -> Listof<Id>
|
||||
;; Get a list of the internal names of mandatory inits
|
||||
|
@ -327,7 +341,7 @@
|
|||
;; The identifiers inside the lambdas below will expand via
|
||||
;; set!-transformers to the appropriate accessors, which lets
|
||||
;; us figure out the accessor identifiers.
|
||||
(define (make-locals-table name-dict)
|
||||
(define (make-locals-table name-dict private-field-names)
|
||||
(define public-names (stx-map stx-car (dict-ref name-dict #'public '())))
|
||||
(define override-names
|
||||
(stx-map stx-car (dict-ref name-dict #'override '())))
|
||||
|
@ -349,6 +363,9 @@
|
|||
[(#,@field-names)
|
||||
(values #,@(map (λ (stx) #`(λ () #,stx (set! #,stx 0)))
|
||||
field-names))]
|
||||
[(#,@private-field-names)
|
||||
(values #,@(map (λ (stx) #`(λ () #,stx (set! #,stx 0)))
|
||||
private-field-names))]
|
||||
[(#,@init-names)
|
||||
(values #,@(map (λ (stx) #`(λ () #,stx))
|
||||
init-names))]
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
(define-syntax-class internal-class-data
|
||||
#:literals (#%plain-app quote-syntax class:-internal begin
|
||||
values c:init c:init-field optional-init c:field
|
||||
c:public c:override c:private c:inherit)
|
||||
c:public c:override c:private c:inherit private-field)
|
||||
(pattern (begin (quote-syntax
|
||||
(class:-internal
|
||||
(c:init init-names:name-pair ...)
|
||||
|
@ -45,6 +45,7 @@
|
|||
(c:public public-names:name-pair ...)
|
||||
(c:override override-names:name-pair ...)
|
||||
(c:private privates:id ...)
|
||||
(private-field private-fields:id ...)
|
||||
(c:inherit inherit-names:name-pair ...)))
|
||||
(#%plain-app values))
|
||||
#:with init-internals #'(init-names.internal ...)
|
||||
|
@ -60,7 +61,8 @@
|
|||
#:with override-externals #'(override-names.external ...)
|
||||
#:with inherit-externals #'(inherit-names.external ...)
|
||||
#:with inherit-internals #'(inherit-names.internal ...)
|
||||
#:with private-names #'(privates ...)))
|
||||
#:with private-names #'(privates ...)
|
||||
#:with private-field-names #'(private-fields ...)))
|
||||
|
||||
(define-syntax-class initializer-body
|
||||
#:literals (letrec-syntaxes+values)
|
||||
|
@ -117,7 +119,7 @@
|
|||
public-internals public-externals
|
||||
override-internals override-externals
|
||||
inherit-internals inherit-externals
|
||||
private-names
|
||||
private-names private-field-names
|
||||
make-methods
|
||||
initializer-body
|
||||
initializer-self-id
|
||||
|
@ -208,6 +210,8 @@
|
|||
(list->set (syntax->datum #'cls.inherit-externals)))
|
||||
(define this%-private-names
|
||||
(list->set (syntax->datum #'cls.private-names)))
|
||||
(define this%-private-fields
|
||||
(list->set (syntax->datum #'cls.private-field-names)))
|
||||
(define this%-method-names
|
||||
(set-union this%-public-names this%-override-names))
|
||||
(define all-internal
|
||||
|
@ -274,13 +278,18 @@
|
|||
;; trawl the body for the local name table
|
||||
(define locals (trawl-for-property #'cls.make-methods 'tr:class:local-table))
|
||||
(define-values (local-method-table local-private-table local-field-table
|
||||
local-init-table local-inherit-table local-super-table)
|
||||
local-private-field-table local-init-table
|
||||
local-inherit-table local-super-table)
|
||||
(construct-local-mapping-tables (car locals)))
|
||||
;; types for private elements
|
||||
(define private-method-types
|
||||
(for/hash ([(name type) (in-dict internals-table)]
|
||||
#:when (set-member? this%-private-names name))
|
||||
(values name type)))
|
||||
(define private-field-types
|
||||
(for/hash ([(name type) (in-dict internals-table)]
|
||||
#:when (set-member? this%-private-fields name))
|
||||
(values name (list type))))
|
||||
;; start type-checking elements in the body
|
||||
(define-values (lexical-names lexical-types
|
||||
lexical-names/top-level lexical-types/top-level)
|
||||
|
@ -289,6 +298,8 @@
|
|||
this%-method-internals
|
||||
local-field-table fields
|
||||
this%-field-internals
|
||||
local-private-field-table private-field-types
|
||||
this%-private-fields
|
||||
local-init-table inits
|
||||
;; omit init-fields here since they don't have
|
||||
;; init accessors, only field accessors
|
||||
|
@ -393,6 +404,8 @@
|
|||
(define (local-tables->lexical-env internal-external-mapping
|
||||
local-method-table methods method-names
|
||||
local-field-table fields field-names
|
||||
local-private-field-table
|
||||
private-field-types private-field-names
|
||||
local-init-table inits init-names
|
||||
local-inherit-table local-super-table
|
||||
super-types
|
||||
|
@ -408,6 +421,12 @@
|
|||
(define localized-field-pairs (localize local-field-table field-names))
|
||||
(define localized-field-get-names (map car localized-field-pairs))
|
||||
(define localized-field-set-names (map cadr localized-field-pairs))
|
||||
(define localized-private-field-pairs
|
||||
(localize local-private-field-table private-field-names))
|
||||
(define localized-private-field-get-names
|
||||
(map car localized-private-field-pairs))
|
||||
(define localized-private-field-set-names
|
||||
(map cadr localized-private-field-pairs))
|
||||
(define localized-inherit-names (localize local-inherit-table inherit-names))
|
||||
(define localized-private-methods
|
||||
(localize local-private-table private-methods))
|
||||
|
@ -429,19 +448,26 @@
|
|||
(define method-types (make-method-types method-names methods))
|
||||
(define inherit-types (make-method-types inherit-names super-types))
|
||||
|
||||
(define field-get-types
|
||||
(for/list ([f (in-set field-names)])
|
||||
(define external (dict-ref internal-external-mapping f))
|
||||
(define maybe-type (dict-ref fields external #f))
|
||||
;; construct field accessor types
|
||||
(define (make-field-types field-names type-map #:private? [private? #f])
|
||||
(for/lists (_1 _2) ([f (in-set field-names)])
|
||||
(define external
|
||||
(if private?
|
||||
f
|
||||
(dict-ref internal-external-mapping f)))
|
||||
(define maybe-type (dict-ref type-map external #f))
|
||||
(values
|
||||
(->* (list (make-Univ)) (or (and maybe-type (car maybe-type))
|
||||
(make-Univ)))))
|
||||
(define field-set-types
|
||||
(for/list ([f (in-set field-names)])
|
||||
(define external (dict-ref internal-external-mapping f))
|
||||
(define maybe-type (dict-ref fields external #f))
|
||||
(make-Univ)))
|
||||
(->* (list (make-Univ) (or (and maybe-type (car maybe-type))
|
||||
-Bottom))
|
||||
-Void)))
|
||||
-Void))))
|
||||
|
||||
(define-values (field-get-types field-set-types)
|
||||
(make-field-types field-names fields))
|
||||
(define-values (private-field-get-types private-field-set-types)
|
||||
(make-field-types private-field-names private-field-types
|
||||
#:private? #t))
|
||||
|
||||
;; types for privates and super calls
|
||||
(define (make-private-like-types names type-map)
|
||||
|
@ -465,10 +491,13 @@
|
|||
localized-private-methods
|
||||
localized-field-get-names
|
||||
localized-field-set-names
|
||||
localized-private-field-get-names
|
||||
localized-private-field-set-names
|
||||
localized-inherit-names
|
||||
localized-override-names))
|
||||
(define all-types (append method-types private-method-types
|
||||
field-get-types field-set-types
|
||||
private-field-get-types private-field-set-types
|
||||
inherit-types super-call-types))
|
||||
(values all-names all-types
|
||||
;; FIXME: consider removing method names and types
|
||||
|
@ -628,6 +657,14 @@
|
|||
(let-values (((_) _))
|
||||
(let-values (((_) _)) (#%plain-app local-field-set:id _ _))))
|
||||
...)]
|
||||
[(private-field:id ...)
|
||||
(#%plain-app
|
||||
values
|
||||
(#%plain-lambda ()
|
||||
(let-values (((_) _)) (#%plain-app local-private-get:id _))
|
||||
(let-values (((_) _))
|
||||
(let-values (((_) _)) (#%plain-app local-private-set:id _ _))))
|
||||
...)]
|
||||
[(init:id ...)
|
||||
(#%plain-app values (#%plain-lambda () local-init:id) ...)]
|
||||
[(inherit:id ...)
|
||||
|
@ -656,6 +693,10 @@
|
|||
(syntax->datum #'(field ...))
|
||||
(syntax->list #'(local-field-get ...))
|
||||
(syntax->list #'(local-field-set ...)))
|
||||
(map list
|
||||
(syntax->datum #'(private-field ...))
|
||||
(syntax->list #'(local-private-get ...))
|
||||
(syntax->list #'(local-private-set ...)))
|
||||
(map cons
|
||||
(syntax->datum #'(init ...))
|
||||
(syntax->list #'(local-init ...)))
|
||||
|
|
|
@ -382,6 +382,44 @@
|
|||
(field [f "foo"])
|
||||
(set! f 5))))
|
||||
|
||||
;; test private field
|
||||
(check-ok
|
||||
(class: object%
|
||||
(super-new)
|
||||
(: x Integer)
|
||||
(define x 5)
|
||||
(set! x 8)
|
||||
(+ x 1))
|
||||
(: d% (Class (field [y String])))
|
||||
(define d%
|
||||
(class: object%
|
||||
(super-new)
|
||||
(: x Integer)
|
||||
(define x 5)
|
||||
(: y String)
|
||||
(field [y "foo"]))))
|
||||
|
||||
;; fails, bad private field set!
|
||||
(check-err
|
||||
(class: object%
|
||||
(super-new)
|
||||
(: x Integer)
|
||||
(define x 5)
|
||||
(set! x "foo")))
|
||||
|
||||
;; fails, bad private field default
|
||||
(check-err
|
||||
(class: object%
|
||||
(super-new)
|
||||
(: x Integer)
|
||||
(define x "foo")))
|
||||
|
||||
;; fails, private field needs type annotation
|
||||
(check-err
|
||||
(class: object%
|
||||
(super-new)
|
||||
(define x "foo")))
|
||||
|
||||
;; test private method
|
||||
(check-ok
|
||||
(class: object% (super-new)
|
||||
|
|
Loading…
Reference in New Issue
Block a user