cs: fix letrec
Report source name when accessing a variable too early, and allow multiple returns (based on continuation capture) for the right-hand side of a `letrec`. The repair directly implements `letrec` as needed in terms of `let` and `set!`, instead of relying on Chez Scheme's `letrec`, unless right-hand sides are simple enough. Implementing `letrec` that way risks losing Chez Scheme optimizations, but schemify takes care of many improvements already.
This commit is contained in:
parent
cea82c1ddc
commit
e37199cd7a
|
@ -226,6 +226,7 @@ RUMBLE_SRCS = rumble/define.ss \
|
|||
rumble/virtual-register.ss \
|
||||
rumble/check.ss \
|
||||
rumble/syntax-rule.ss \
|
||||
rumble/letrec.ss \
|
||||
rumble/constant.ss \
|
||||
rumble/hash-code.ss \
|
||||
rumble/struct.ss \
|
||||
|
|
|
@ -6,11 +6,27 @@
|
|||
(cond
|
||||
[(pair? v) (let-values ([(a stripped-a) (correlated->annotation* (car v))]
|
||||
[(d stripped-d) (correlated->annotation* (cdr v))])
|
||||
(if (and (eq? a (car v))
|
||||
(eq? d (cdr v)))
|
||||
(values v v)
|
||||
(values (cons a d)
|
||||
(cons stripped-a stripped-d))))]
|
||||
(cond
|
||||
[(and (eq? a (car v))
|
||||
(eq? d (cdr v)))
|
||||
(values v v)]
|
||||
[(and (eq? stripped-a 'letrec*)
|
||||
(pair? (cdr v)))
|
||||
(let ([names (let loop ([clauses (cadr v)])
|
||||
(cond
|
||||
[(null? clauses) '()]
|
||||
[else
|
||||
(let ([id (caar clauses)])
|
||||
(cons (or (and (correlated? id)
|
||||
(correlated-property id 'undefined-error-name))
|
||||
(if (correlated? id)
|
||||
(correlated-e id)
|
||||
id))
|
||||
(loop (cdr clauses))))]))])
|
||||
(values (list* 'letrec*/names names d)
|
||||
(list* 'letrec*/names names stripped-d)))]
|
||||
[else (values (cons a d)
|
||||
(cons stripped-a stripped-d))]))]
|
||||
[(correlated? v) (let-values ([(e stripped-e) (correlated->annotation* (correlated-e v))])
|
||||
(let ([name (correlated-property v 'inferred-name)])
|
||||
(define (add-name e)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
begin0
|
||||
|
||||
letrec*/names
|
||||
|
||||
dynamic-wind
|
||||
call-with-current-continuation
|
||||
call-with-composable-continuation
|
||||
|
@ -693,6 +695,7 @@
|
|||
(include "rumble/define.ss")
|
||||
(include "rumble/virtual-register.ss")
|
||||
(include "rumble/begin0.ss")
|
||||
(include "rumble/letrec.ss")
|
||||
(include "rumble/syntax-rule.ss")
|
||||
(include "rumble/lock.ss")
|
||||
(include "rumble/thread-local.ss")
|
||||
|
|
47
racket/src/cs/rumble/letrec.ss
Normal file
47
racket/src/cs/rumble/letrec.ss
Normal file
|
@ -0,0 +1,47 @@
|
|||
(meta define no-early-reference?
|
||||
(lambda (stx ids)
|
||||
(cond
|
||||
[(#%identifier? stx)
|
||||
(not (#%ormap (lambda (id) (free-identifier=? id stx)) ids))]
|
||||
[(let ([d (syntax->datum stx)])
|
||||
(or (number? d) (boolean? d) (string? d) (bytevector? d)))
|
||||
#t]
|
||||
[else
|
||||
(syntax-case stx (quote |#%name| lambda case-lambda)
|
||||
[(quote _) #t]
|
||||
[(|#%name| _ exp) (no-early-reference? #'exp ids)]
|
||||
[(lambda . _) #t]
|
||||
[(case-lambda . _) #t]
|
||||
[_ #f])])))
|
||||
|
||||
(meta define no-early-references?
|
||||
(lambda (rhss ids)
|
||||
(cond
|
||||
[(null? rhss) #t]
|
||||
[else (and (no-early-reference? (car rhss) ids)
|
||||
(no-early-references? (cdr rhss) (cdr ids)))])))
|
||||
|
||||
;; Like `letrec*`, but makes use-before-definition checks explicit so
|
||||
;; that a source name is included in the error messages. Also, the
|
||||
;; expansion allows `call/cc`-based capture and multiple return on the
|
||||
;; right-hand side.
|
||||
(define-syntax (letrec*/names stx)
|
||||
(syntax-case stx ()
|
||||
[(_ (name ...) ([id rhs] ...) body ...)
|
||||
(cond
|
||||
[(no-early-references? #'(rhs ...) #'(id ...))
|
||||
#'(letrec* ([id rhs] ...) body ...)]
|
||||
[else
|
||||
(with-syntax ([(tmp-id ...) (generate-temporaries #'(id ...))])
|
||||
#'(let ([tmp-id unsafe-undefined] ...)
|
||||
(let-syntax ([id (identifier-syntax
|
||||
[id (check-not-unsafe-undefined tmp-id 'name)]
|
||||
[(set! id exp)
|
||||
(let ([id exp])
|
||||
(check-not-unsafe-undefined/assign tmp-id 'name)
|
||||
(set! tmp-id id))])]
|
||||
...)
|
||||
(set! tmp-id rhs)
|
||||
...
|
||||
(let ()
|
||||
body ...))))])]))
|
Loading…
Reference in New Issue
Block a user