Files
gyehoek-hs/doc/closure-conversion.org
T
msyds 745277ed1a
build / build (push) Successful in 1m12s
wip: abstract stack/continuation machine
2026-08-17 22:31:45 -06:00

2.6 KiB

closure-conversion

the closure-conversion phase makes closed-over variables explicit by addition of the primitive make-closure, taking a code pointer (in the CPS language, bare lambda) and the environment.

scratchpad

(letrec ((make-adder
        (lambda (n)
          (lambda (x)
            (+ n x)))))
((make-adder 3) 2))
(define add-code
  (lambda (n env)
    (+ n (env-ref env 'x))))

(define make-adder-code
  (lambda (n)
    (make-closure add-code ('x n))))

(define make-adder (make-closure make-adder-code))

(apply-closure (apply-closure make-addder 3) 2)
(module
 (type $heap-object (sub (struct (field $hash (mut i32)))))
 (type $closure (sub $heap-object
                     (struct (field $hash (mut i32))
                             (field $code (ref $cont-type)))))
 (type $closure1 (sub $closure
                      (struct (field $hash (mut i32))
                              (field $code (ref $cont-type))
                              (field $env0 (ref eq)))))
 (global $arg0 (mut (ref null eq)) (ref.null eq))
 (global $arg1 (mut (ref null eq)) (ref.null eq))
 (global $arg2 (mut (ref null eq)) (ref.null eq))
 (global $arg3 (mut (ref null eq)) (ref.null eq))
 (global $arg4 (mut (ref null eq)) (ref.null eq))
 (global $arg5 (mut (ref null eq)) (ref.null eq))
 ;; ⋮
 ;; (global $argn (mut (ref null eq)) (ref.null eq))

 (global $current-closure (mut (ref null $closure)) (ref.null $closure))

 (func $add-code (param $nargs i32)
       (local $n (ref eq))
       (local $x (ref eq))
       (local.set $n (global.get $arg0))
       (local.set $x (struct.get $closure1
                                 (global.get $current-closure)
                                 $env0))
       (return (i32.add $n $x)))

 (func $make-adder-code (param $nargs i32)
       (local $n (ref eq))
       (local.set $n (global.get $arg0))
       (return (struct.new $closure1
                           0
                           $add-code)))

 (func $main
       (local.set $make-adder
                  (struct.new $closure
                              0
                              $make-adder-code))
       (global.set $current-closure $make-adder)
       (global.set $arg0 (i32.const 3))
       (local.set $f (call (struct.get $closure
                                       $make-adder
                                       $code)
                           1))
       (global.set $current-closure $f)
       (global.set $arg0 (i32.const 2))
       (return (call (struct.get $closure
                                 $f
                                 $code)
                     1))))