Fix handling of (set! var (let (var) ...)) and similar cases.
Was moving (set!) into the (%bind) form, and thus setting the wrong variable.
Now, if set! var is bound, will create a temporary for result of %bind first,
and set! original variable to temporary in the proper scope.
Also, normalize rules for nested (%bind)s:
* The (%bind) inside a (%lambda) is always flat.
- This is a responsiblity of simplify-lambda, and any function which
may change structure after simplification (e.g. promote-to-box).
* Any other (%bind) may be nested, unless otherwise noted.
This commit is contained in:
parent
5c8625a1f1
commit
67ea700ac2
132
compiler.ss
132
compiler.ss
|
|
@ -327,23 +327,30 @@
|
||||||
(form-captures? form var #f #t))
|
(form-captures? form var #f #t))
|
||||||
|
|
||||||
(define (simplify-set! form)
|
(define (simplify-set! form)
|
||||||
(let ([value-form (simplify-form (third form))])
|
(let ([variable (second form)]
|
||||||
|
[value-form (simplify-form (third form))])
|
||||||
(if (and (pair? value-form) (eq? (first value-form) '%bind))
|
(if (and (pair? value-form) (eq? (first value-form) '%bind))
|
||||||
(simplify-form
|
(if (memq variable (second value-form))
|
||||||
`(let ,(second value-form)
|
(let ([tmp (gensym)])
|
||||||
,@(foldr (lambda (subform after)
|
`(%bind (,tmp)
|
||||||
(cond
|
; guaranteed not to cause unbounded recursion: tmp is unique
|
||||||
[(pair? after) (cons subform after)]
|
,(simplify-set! `(set! ,tmp ,value-form))
|
||||||
[(and (pair? subform) (eq? (first subform) '%values))
|
(%set! ,variable ,tmp)))
|
||||||
; Requires at least one value; ignores extras.
|
`(%bind ,(second value-form)
|
||||||
(if (null? (cdr subform))
|
,@(foldr (lambda (subform after)
|
||||||
(error "Attempted to set variable to void in:" form)
|
(cond
|
||||||
`((set! ,(second form) ,(second subform))))]
|
[(pair? after) (cons subform after)]
|
||||||
[(value-form? subform) `((set! ,(second form) ,subform))]
|
[(and (pair? subform) (eq? (first subform) '%values))
|
||||||
[else (error "Attempted to set variable to void in:" form)]))
|
; Requires at least one value; ignores extras.
|
||||||
'()
|
(if (null? (cdr subform))
|
||||||
(cddr value-form))))
|
(error "Attempted to set variable to void in:" form)
|
||||||
`(%set! ,(second form) ,value-form))))
|
`((%set! ,variable ,(second subform))))]
|
||||||
|
[(value-form? subform)
|
||||||
|
(list (simplify-set! `(set! ,variable ,subform)))]
|
||||||
|
[else (error "Attempted to set variable to void in:" form)]))
|
||||||
|
'()
|
||||||
|
(cddr value-form))))
|
||||||
|
`(%set! ,variable ,value-form))))
|
||||||
|
|
||||||
(define (simplify-primitive simple-op value-forms)
|
(define (simplify-primitive simple-op value-forms)
|
||||||
(define (value->binding value-form)
|
(define (value->binding value-form)
|
||||||
|
|
@ -379,28 +386,27 @@
|
||||||
(define vars (map first bindings))
|
(define vars (map first bindings))
|
||||||
(define (bound-var? var) (and (memq var vars) #t))
|
(define (bound-var? var) (and (memq var vars) #t))
|
||||||
|
|
||||||
(flatten-binds
|
; If the value of any binding refers to one of the variable names being bound...
|
||||||
; If the value of any binding refers to one of the variable names being bound...
|
(if (ormap (lambda (value) (ormap bound-var? (free-variables value)))
|
||||||
(if (ormap (lambda (value) (ormap bound-var? (free-variables value)))
|
(map second (filter has-value? bindings)))
|
||||||
(map second (filter has-value? bindings)))
|
; ...then bind the values to temps first, before binding the real names.
|
||||||
; ...then bind the values to temps first, before binding the real names.
|
(let ([temp-bindings (map (lambda (binding)
|
||||||
(let ([temp-bindings (map (lambda (binding)
|
(let ([tmp (gensym)])
|
||||||
(let ([tmp (gensym)])
|
(list tmp
|
||||||
(list tmp
|
(simplify-form `(set! ,tmp ,(second binding)))
|
||||||
(simplify-form `(set! ,tmp ,(second binding)))
|
`(%set! ,(first binding) ,tmp))))
|
||||||
`(%set! ,(first binding) ,tmp))))
|
(filter has-value? bindings))])
|
||||||
(filter has-value? bindings))])
|
`(%bind ,(map first temp-bindings)
|
||||||
`(%bind ,(map first temp-bindings)
|
,@(map second temp-bindings)
|
||||||
,@(map second temp-bindings)
|
(%bind ,vars
|
||||||
(%bind ,vars
|
,@(map third temp-bindings)
|
||||||
,@(map third temp-bindings)
|
,@(map simplify-form bodyexprs))))
|
||||||
,@(map simplify-form bodyexprs))))
|
; Otherwise, just bind the real names directly.
|
||||||
; Otherwise, just bind the real names directly.
|
`(%bind ,vars
|
||||||
`(%bind ,vars
|
,@(map (lambda (binding)
|
||||||
,@(map (lambda (binding)
|
(simplify-set! `(set! ,@binding)))
|
||||||
(simplify-set! `(set! ,@binding)))
|
(filter has-value? bindings))
|
||||||
(filter has-value? bindings))
|
,@(map simplify-form bodyexprs))))
|
||||||
,@(map simplify-form bodyexprs)))))
|
|
||||||
|
|
||||||
; (let* ...) ; eval exprs & bind variables serially
|
; (let* ...) ; eval exprs & bind variables serially
|
||||||
; => (let ([var-0 expr-0])
|
; => (let ([var-0 expr-0])
|
||||||
|
|
@ -489,9 +495,10 @@
|
||||||
[else (let-values ([(req opt rst) (split-arglist (cdr arglist))])
|
[else (let-values ([(req opt rst) (split-arglist (cdr arglist))])
|
||||||
(values (cons (car arglist) req) opt rst))]))
|
(values (cons (car arglist) req) opt rst))]))
|
||||||
|
|
||||||
(define (add-return ctx k form)
|
(define (add-return ctx k nested-bind)
|
||||||
|
(define flat-bind (flatten-binds nested-bind))
|
||||||
(define argv (gensym))
|
(define argv (gensym))
|
||||||
`(%bind (,@(second form) ,argv)
|
`(%bind (,@(second flat-bind) ,argv)
|
||||||
,@(foldr (lambda (subform after)
|
,@(foldr (lambda (subform after)
|
||||||
(cond
|
(cond
|
||||||
[(pair? after)
|
[(pair? after)
|
||||||
|
|
@ -519,44 +526,42 @@
|
||||||
`(,subform
|
`(,subform
|
||||||
(%tail-call ,k %nil #f #f))]))
|
(%tail-call ,k %nil #f #f))]))
|
||||||
'()
|
'()
|
||||||
(cddr form))))
|
(cddr flat-bind))))
|
||||||
|
|
||||||
(define (simplify-lambda form)
|
(define (simplify-lambda form)
|
||||||
(define arglist (car (cdr form)))
|
(define arglist (car (cdr form)))
|
||||||
(define bodyexprs (cdr (cdr form)))
|
(define bodyexprs (cdr (cdr form)))
|
||||||
|
|
||||||
(define-values (requireds optionals rest) (split-arglist arglist))
|
(define-values (requireds optionals rest) (split-arglist arglist))
|
||||||
(define argv-temp (gensym))
|
(define argv (gensym))
|
||||||
(define ctx (gensym))
|
(define ctx (gensym))
|
||||||
(define k (gensym))
|
(define k (gensym))
|
||||||
|
|
||||||
(define (add-req req inner) `(let ([,req (car ,argv-temp)])
|
(define (add-req req inner) `(let ([,req (car ,argv)])
|
||||||
(set! ,argv-temp (cdr ,argv-temp))
|
(set! ,argv (cdr ,argv))
|
||||||
,inner))
|
,inner))
|
||||||
(define (add-opt opt-list inner) `(let (,(car opt-list))
|
(define (add-opt opt-list inner) `(let (,(car opt-list))
|
||||||
(if (pair? ,argv-temp)
|
(if (pair? ,argv)
|
||||||
(begin
|
(begin
|
||||||
(set! ,(first opt-list) (car ,argv-temp))
|
(set! ,(first opt-list) (car ,argv))
|
||||||
(set! ,argv-temp (cdr ,argv-temp)))
|
(set! ,argv (cdr ,argv)))
|
||||||
(set! ,(first opt-list) ,(second opt-list)))
|
(set! ,(first opt-list) ,(second opt-list)))
|
||||||
,inner))
|
,inner))
|
||||||
(define rest+bodyexprs (if rest `(let ([,rest ,argv-temp]) ,@bodyexprs)
|
(define rest+bodyexprs (if rest `(let ([,rest ,argv]) ,@bodyexprs)
|
||||||
`(begin ,@bodyexprs)))
|
`(begin ,@bodyexprs)))
|
||||||
(narrow-binds
|
(narrow-binds
|
||||||
`(%lambda () ()
|
`(%lambda () ()
|
||||||
,((compose (lambda (bind) (transform-to-cps ctx bind))
|
,((compose (lambda (bind) (transform-to-cps ctx bind))
|
||||||
(lambda (bind) (add-return ctx k bind))
|
(lambda (bind) (add-return ctx k bind)))
|
||||||
flatten-binds)
|
(simplify-form
|
||||||
`(%bind (,ctx ,k)
|
`(let ([,argv %argv]
|
||||||
(%set! ,ctx %ctx)
|
[,ctx %ctx]
|
||||||
(%set! ,k %k)
|
[,k %k])
|
||||||
,(simplify-form
|
,(foldr add-req
|
||||||
`(let ([,argv-temp %argv])
|
(foldr add-opt
|
||||||
,(foldr add-req
|
rest+bodyexprs
|
||||||
(foldr add-opt
|
optionals)
|
||||||
rest+bodyexprs
|
requireds)))))))
|
||||||
optionals)
|
|
||||||
requireds))))))))
|
|
||||||
|
|
||||||
(define (narrow-binds simple-lambda-form)
|
(define (narrow-binds simple-lambda-form)
|
||||||
(define bind (fourth simple-lambda-form))
|
(define bind (fourth simple-lambda-form))
|
||||||
|
|
@ -705,7 +710,8 @@
|
||||||
; (%set! k-argv (%cons k %nil))
|
; (%set! k-argv (%cons k %nil))
|
||||||
; (%tail-call l k-argv ctx k))
|
; (%tail-call l k-argv ctx k))
|
||||||
|
|
||||||
(define (transform-to-cps ctx bind)
|
(define (transform-to-cps ctx nested-bind)
|
||||||
|
(define flat-bind (flatten-binds nested-bind))
|
||||||
(define (cps-prepend subform after)
|
(define (cps-prepend subform after)
|
||||||
(cond
|
(cond
|
||||||
; (%set! v (%apply x y))
|
; (%set! v (%apply x y))
|
||||||
|
|
@ -774,8 +780,8 @@
|
||||||
; discard any form without side-effects
|
; discard any form without side-effects
|
||||||
[else after]))
|
[else after]))
|
||||||
(flatten-binds
|
(flatten-binds
|
||||||
`(%bind ,(second bind)
|
`(%bind ,(second flat-bind)
|
||||||
,@(foldr cps-prepend '() (cddr bind)))))
|
,@(foldr cps-prepend '() (cddr flat-bind)))))
|
||||||
|
|
||||||
; (fn-expr arg-expr...)
|
; (fn-expr arg-expr...)
|
||||||
; => (let ([fn-var fn-expr] arg-var... argv)
|
; => (let ([fn-var fn-expr] arg-var... argv)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue