R6RS: disallow assignment to exported identifier

svn: r14695
This commit is contained in:
Matthew Flatt 2009-05-03 17:40:31 +00:00
parent 2b4d032701
commit c17c267f48
5 changed files with 62 additions and 13 deletions

View File

@ -9,7 +9,8 @@ FIXME:
(require (for-syntax scheme/base (require (for-syntax scheme/base
syntax/kerncase syntax/kerncase
"private/parse-ref.ss" "private/parse-ref.ss"
scheme/provide-transform)) scheme/provide-transform)
"private/no-set.ss")
(provide (rename-out [module-begin #%module-begin])) (provide (rename-out [module-begin #%module-begin]))
@ -232,6 +233,12 @@ FIXME:
orig orig
ex)]))) ex)])))
exs) exs)
(add-no-set!-identifiers (map (lambda (ex)
(syntax-case ex ()
[(rename (id ex-id))
#'id]
[id ex]))
exs))
(with-syntax ([((ex ...) ...) (with-syntax ([((ex ...) ...)
(map (lambda (ex) (map (lambda (ex)
(syntax-case ex () (syntax-case ex ()

View File

@ -1,26 +1,27 @@
#lang scheme/base #lang scheme/base
(require (for-syntax scheme/base) (require (for-syntax scheme/base)
(for-template (only-in scheme/base set! #%app))) (for-template "no-set.ss"
(only-in scheme/base #%app set!)))
(provide identifier-syntax) (provide identifier-syntax)
(define-syntax (identifier-syntax stx) (define-syntax (identifier-syntax stx)
(syntax-case* stx (set!) (lambda (a b) (syntax-case* stx (r6rs:set!) (lambda (a b)
(free-template-identifier=? a b)) (free-template-identifier=? a b))
[(identifier-syntax template) [(identifier-syntax template)
#'(... #'(...
(make-set!-transformer (make-set!-transformer
(lambda (stx) (lambda (stx)
(syntax-case stx (set!) (syntax-case stx (set!)
[(set! . _) (raise-syntax-error [(set! . _) (raise-syntax-error
#f #f
"cannot assign to identifier macro" "cannot assign to identifier macro"
stx)] stx)]
[(_ arg ...) #'(template arg ...)] [(_ arg ...) #'(template arg ...)]
[_ #'template]))))] [_ #'template]))))]
[(identifier-syntax [(identifier-syntax
[id1 template1] [id1 template1]
[(set! id2 pat) template2]) [(r6rs:set! id2 pat) template2])
(and (identifier? #'id1) (and (identifier? #'id1)
(identifier? #'id2)) (identifier? #'id2))
#'(... #'(...

View File

@ -0,0 +1,33 @@
#lang scheme/base
(require (for-syntax scheme/base
syntax/boundmap))
(provide (for-syntax add-no-set!-identifiers)
r6rs:set!)
;; Provided identifier cannot be `set!'ed. The list
;; is relevant only within the module being compiled.
(define-for-syntax no-set!-identifiers (make-free-identifier-mapping))
(define-for-syntax (add-no-set!-identifiers ids)
(for ([id (in-list ids)])
(free-identifier-mapping-put! no-set!-identifiers id #t)))
(define-for-syntax (no-set!-identifier? id)
(free-identifier-mapping-get no-set!-identifiers id (lambda () #f)))
;; ----------------------------------------
(define-syntax (r6rs:set! stx)
(syntax-case stx ()
[(_ id rhs)
(identifier? #'id)
(if (no-set!-identifier? #'id)
(raise-syntax-error
#f
"cannot mutate exported identifier"
stx
#'id)
(syntax/loc stx (set! id rhs)))]
[(_ . rest)
(syntax/loc stx (set! . rest))]))

View File

@ -7,6 +7,7 @@
scheme/splicing scheme/splicing
r6rs/private/qq-gen r6rs/private/qq-gen
r6rs/private/exns r6rs/private/exns
r6rs/private/no-set
(for-syntax r6rs/private/reconstruct) (for-syntax r6rs/private/reconstruct)
(prefix-in r5rs: r5rs) (prefix-in r5rs: r5rs)
(only-in r6rs/private/readtable rx:number) (only-in r6rs/private/readtable rx:number)
@ -28,7 +29,7 @@
(rename-out [r5rs:if if]) (rename-out [r5rs:if if])
;; 11.4.4 ;; 11.4.4
set! (rename-out [r6rs:set! set!])
;; 11.4.5 ;; 11.4.5
cond else => case cond else => case
@ -269,8 +270,8 @@
(lambda (stx) (lambda (stx)
(if (identifier? stx) (if (identifier? stx)
(syntax/loc stx r6rs-/) (syntax/loc stx r6rs-/)
(syntax-case stx (set!) (syntax-case stx (r6rs:set!)
[(set! . _) [(r6rs:set! . _)
(raise-syntax-error #f (raise-syntax-error #f
"cannot mutate imported identifier" "cannot mutate imported identifier"
stx)] stx)]

View File

@ -6,7 +6,9 @@
scheme/mpair scheme/mpair
r6rs/private/exns r6rs/private/exns
(for-syntax syntax/template (for-syntax syntax/template
r6rs/private/check-pattern)) r6rs/private/check-pattern)
(for-template (only-in scheme/base set!)
r6rs/private/no-set))
(provide make-variable-transformer (provide make-variable-transformer
(rename-out [r6rs:syntax-case syntax-case] (rename-out [r6rs:syntax-case syntax-case]
@ -105,7 +107,12 @@
l)]))))) l)])))))
(define (make-variable-transformer proc) (define (make-variable-transformer proc)
(make-set!-transformer proc)) (make-set!-transformer
(lambda (stx)
(syntax-case* stx (set!) free-template-identifier=?
[(set! . rest)
(proc (syntax/loc stx (r6rs:set! . rest)))]
[else (proc stx)]))))
(define unwrapped-tag (gensym)) (define unwrapped-tag (gensym))