expander: adjust rename-transformer handling for implicit forms

For consistently with the old expander, treat `#%app` and `#%datum`
like unbound if they're bound to a rename transformer whose identifier
does not untimately refer to macro or primitive syntactice form.

Closes #2042
This commit is contained in:
Matthew Flatt 2018-04-14 10:14:55 -06:00
parent 8b797a10a8
commit 385f9588f8
3 changed files with 6369 additions and 6113 deletions

View File

@ -1904,6 +1904,24 @@
(m (+ 1 2))
'ok))
;; ----------------------------------------
;; Error (instead of looping) when an implicit is not bound as syntax
(syntax-test #'(module m racket/base
(require (for-syntax racket/base))
(let-syntax ([#%app (make-rename-transformer #'unbound)])
(+ 1 2))))
(syntax-test #'(module m racket/base
(require (for-syntax racket/base))
(let-syntax ([#%app (make-rename-transformer #'cons)])
(+ 1 2))))
(syntax-test #'(module m racket/base
(require (for-syntax racket/base))
(let-syntax ([#%datum (make-rename-transformer #'unbound)])
(+ 1 2))))
;; ----------------------------------------
(report-errs)

View File

@ -69,14 +69,17 @@
;; Aplying a rename transformer substitutes
;; an id without changing `s`
#:alternate-id [alternate-id #f]
#:skip-log? [skip-log? #f])
#:skip-log? [skip-log? #f]
;; For expanding an implicit implemented by a rename transformer:
#:fail-non-transformer [fail-non-transformer #f])
(log-expand* ctx #:unless skip-log? [(if (expand-context-only-immediate? ctx) 'enter-check 'visit) s])
(cond
[(syntax-identifier? s)
(expand-identifier s ctx alternate-id)]
[(and (pair? (syntax-content s))
(syntax-identifier? (car (syntax-content s))))
(expand-id-application-form s ctx alternate-id)]
(expand-id-application-form s ctx alternate-id
#:fail-non-transformer fail-non-transformer)]
[(or (pair? (syntax-content s))
(null? (syntax-content s)))
;; An "application" form that doesn't start with an identifier, so
@ -113,7 +116,8 @@
(dispatch t insp-of-t s id ctx binding primitive? protected?)])))
;; An "application" form that starts with an identifier
(define (expand-id-application-form s ctx alternate-id)
(define (expand-id-application-form s ctx alternate-id
#:fail-non-transformer fail-non-transformer)
(define id (or alternate-id (car (syntax-e/no-taint s))))
(guard-stop
id ctx s
@ -122,11 +126,13 @@
#:immediate? #t))
(log-expand* ctx #:unless (expand-context-only-immediate? ctx) ['resolve id])
(cond
[(eq? binding 'ambiguous)
[(eq? binding 'ambiguous)
(when fail-non-transformer (fail-non-transformer))
(raise-ambiguous-error id ctx)]
[(not binding)
[(not binding)
(when fail-non-transformer (fail-non-transformer))
;; The `#%app` binding might do something with unbound ids
(expand-implicit '#%app (substitute-alternate-id s alternate-id) ctx id)]
(expand-implicit '#%app (substitute-alternate-id s alternate-id) ctx id)]
[else
;; Find out whether it's bound as a variable, syntax, or core form
(define-values (t primitive? insp-of-t protected?)
@ -134,12 +140,14 @@
#:in (and alternate-id (car (syntax-e/no-taint s)))
#:out-of-context-as-variable? (expand-context-in-local-expand? ctx)))
(cond
[(variable? t)
;; Not as syntax or core form, so use implicit `#%app`
(expand-implicit '#%app (substitute-alternate-id s alternate-id) ctx id)]
[else
;; Syntax or core form as "application"
(dispatch t insp-of-t s id ctx binding primitive? protected?)])])))
[(variable? t)
(when fail-non-transformer (fail-non-transformer))
;; Not as syntax or core form, so use implicit `#%app`
(expand-implicit '#%app (substitute-alternate-id s alternate-id) ctx id)]
[else
;; Syntax or core form as "application"
(dispatch t insp-of-t s id ctx binding primitive? protected?
#:fail-non-transformer fail-non-transformer)])])))
;; Handle an implicit: `#%app`, `#%top`, or `#%datum`; this is similar
;; to handling an id-application form, but there are several little
@ -167,7 +175,13 @@
(if b (lookup b ctx id) (values #f #f #f #f)))
(cond
[(transformer? t)
(dispatch-transformer t insp-of-t (make-explicit ctx sym s disarmed-s) id ctx b)]
(define fail-non-transformer
;; Make sure a rename transformer eventualy leads to syntax
(and (rename-transformer? t)
(lambda ()
(raise-syntax-implicit-error s sym trigger-id ctx))))
(dispatch-transformer t insp-of-t (make-explicit ctx sym s disarmed-s) id ctx b
#:fail-non-transformer fail-non-transformer)]
[(core-form? t)
(cond
[(and (eq? sym '#%top)
@ -232,12 +246,14 @@
;; other compile-time value (which is an error), or a token
;; indicating that the binding is a run-time variable; note that
;; `s` is not disarmed
(define (dispatch t insp-of-t s id ctx binding primitive? protected?)
(define (dispatch t insp-of-t s id ctx binding primitive? protected?
#:fail-non-transformer [fail-non-transformer #f])
(cond
[(core-form? t)
(dispatch-core-form t s ctx)]
[(transformer? t)
(dispatch-transformer t insp-of-t s id ctx binding)]
(dispatch-transformer t insp-of-t s id ctx binding
#:fail-non-transformer fail-non-transformer)]
[(variable? t)
(dispatch-variable t s id ctx binding primitive? protected?)]
[else
@ -269,7 +285,8 @@
;; Call a macro expander, taking into account whether it works
;; in the current context, whether to expand just once, etc.
(define (dispatch-transformer t insp-of-t s id ctx binding)
(define (dispatch-transformer t insp-of-t s id ctx binding
#:fail-non-transformer fail-non-transformer)
(cond
[(not-in-this-expand-context? t ctx)
(log-expand ctx 'enter-macro s)
@ -304,7 +321,8 @@
id
id))
#:skip-log? (or (expand-context-only-immediate? ctx)
(rename-transformer? t)))])]))
(rename-transformer? t))
#:fail-non-transformer fail-non-transformer)])]))
;; Handle the expansion of a variable to itself
(define (dispatch-variable t s id ctx binding primitive? protected?)

File diff suppressed because it is too large Load Diff