diff --git a/lexical-env.rkt b/lexical-env.rkt index 21cb775..1e515c2 100644 --- a/lexical-env.rkt +++ b/lexical-env.rkt @@ -74,9 +74,12 @@ -(: extend-lexical-environment/names (CompileTimeEnvironment (Listof Symbol) -> CompileTimeEnvironment)) -(define (extend-lexical-environment/names cenv names) - (append (map (lambda: ([n : Symbol]) (make-NamedBinding n #f #f)) names) cenv)) +(: extend-lexical-environment/names (CompileTimeEnvironment (Listof Symbol) (Listof Boolean) -> + CompileTimeEnvironment)) +(define (extend-lexical-environment/names cenv names boxed?) + (append (map (lambda: ([n : Symbol] + [b : Boolean]) (make-NamedBinding n #f b)) names boxed?) + cenv)) (: extend-lexical-environment/parameter-names (CompileTimeEnvironment (Listof Symbol) (Listof Boolean) -> CompileTimeEnvironment)) (define (extend-lexical-environment/parameter-names cenv names boxed?) diff --git a/parse.rkt b/parse.rkt index f11a873..f59fe7f 100644 --- a/parse.rkt +++ b/parse.rkt @@ -385,26 +385,41 @@ [(= 0 (length vars)) (parse `(begin ,@body) cenv)] [(= 1 (length vars)) - (make-Let1 (parameterize ([current-defined-name (first vars)]) - (parse (car rhss) (extend-lexical-environment/placeholders cenv 1))) - (parse `(begin ,@body) - (extend-lexical-environment/names cenv (list (first vars)))))] + (let* ([mutated? (and (member (first vars) (find-mutated-names `(begin ,@body))) #t)] + [let-body (parse `(begin ,@body) + (extend-lexical-environment/names + cenv + (list (first vars)) + (list mutated?)))]) + (make-Let1 (parameterize ([current-defined-name (first vars)]) + (parse (car rhss) (extend-lexical-environment/placeholders cenv 1))) + (if mutated? + (make-BoxEnv 0 let-body) + let-body)))] [else - (let ([rhs-cenv (extend-lexical-environment/placeholders cenv (length vars))]) + (let* ([rhs-cenv (extend-lexical-environment/placeholders cenv (length vars))] + [mutated (find-mutated-names `(begin ,@body))] + [any-mutated? (ormap (lambda (n) (and (member n mutated) #t)) vars)]) (make-LetVoid (length vars) (seq (append (map (lambda (var rhs index) (make-InstallValue index (parameterize ([current-defined-name var]) (parse rhs rhs-cenv)) - #f)) + any-mutated?)) vars rhss (build-list (length rhss) (lambda (i) i))) (list (parse `(begin ,@body) - (extend-lexical-environment/names cenv vars))))) - #f))]))) + (extend-lexical-environment/names + cenv vars + (build-list (length vars) + (lambda (i) + any-mutated?))))))) + any-mutated?))]))) + +;; Letrec's currently doing a set! kind of thing. (define (parse-letrec exp cenv) (let ([vars (let-variables exp)] [rhss (let-rhss exp)] diff --git a/test-parse.rkt b/test-parse.rkt index 13029a3..8b10405 100644 --- a/test-parse.rkt +++ b/test-parse.rkt @@ -309,3 +309,37 @@ (make-App (make-LocalRef 1 #t) (list (make-LocalRef 2 #t))))) #t))) + +(test (parse '(let ([x 0]) + (lambda () + (set! x (add1 x))))) + (make-Top (make-Prefix '(add1)) + (make-Let1 (make-Constant 0) + (make-BoxEnv 0 + (make-Lam #f 0 + (make-InstallValue + 1 + (make-App (make-ToplevelRef 1 0) + (list (make-LocalRef 2 #t))) + #t) + '(1 0)))))) ;; x is 0, prefix is 1 + + + +(test (parse '(let ([x 0] + [y 1]) + (lambda () + (set! x (add1 x))))) + (make-Top (make-Prefix '(add1)) + (make-LetVoid 2 + (make-Seq (list + (make-InstallValue 0 (make-Constant 0) #t) + (make-InstallValue 1 (make-Constant 1) #t) + (make-Lam #f 0 + (make-InstallValue + 1 + (make-App (make-ToplevelRef 1 0) + (list (make-LocalRef 2 #t))) + #t) + '(2 0)))) + #t)))