+ ; load the captured vars onto the stack
+ (for-each
+ (lambda (i)
+ (begin
+ (emit "# loading captive ~a" (list-ref captives i))
+ (emit "movq ~a(~a), %rbx" (* wordsize i) (param-register 0))
+ (emit "movq %rbx, ~a(%rbp)" (* (- wordsize) (+ 1 i)))))
+ (range 0 (length captives)))
+
+ ; load the args onto the stack
+ (for-each
+ (lambda (i)
+ (begin
+ (emit "movq ~a, %rbx" (param-register (+ 1 i)))
+ (emit "movq %rbx, ~a(%rbp)"
+ (* (- wordsize)
+ (+ 1 (length captives) i)))))
+ (range 0 (length args)))
+
+ (codegen-expr body (* (- wordsize) (+ 1 (length params))) env)
+
+ (emit "pop %rbp") ; restore caller's base pointer
+ (emit "ret")))
+
+(define cur-label 0)
+(define (fresh-label)
+ (set! cur-label (+ 1 cur-label))
+ (format "label~a" (- cur-label 1)))
+
+(define (codegen-if cond then else si env)
+ (codegen-expr cond si env)
+ (emit "cmpq $0, %rax")
+ (let ((exit-label (fresh-label))
+ (else-label (fresh-label)))
+ (emit "je ~a" else-label)
+ (codegen-expr then si env)
+ (emit "jmp ~a" exit-label)
+ (emit "~a:" else-label)
+ (codegen-expr else si env)
+ (emit "~a:" exit-label)))
+
+(define (data-tor env e)
+ (if (not (list? e)) #f
+ (assoc (car e) (flat-map data-tors (env-data-layouts env)))))
+
+ ; returns the internal offset in bytes of a product within an ADT
+ ; given the constructor layout
+ ; constructor-layout: (foo (Int Bool))
+(define (data-product-offset data-layouts type sum index)
+ (let* ([products (cdr (assoc sum (cdr (assoc type data-layouts))))]
+ [to-traverse (list-head products index)])
+ (fold-left
+ (lambda (acc t) (+ acc (type-size data-layouts t)))
+ wordsize ; skip the tag in the first word
+ to-traverse)))
+
+(define (data-sum-tag data-layouts type sum)
+
+ (define (go acc sums)
+ (when (null? sums) (error #f "data-sum-tag no sum for type" sum type))
+ (if (eqv? sum (car sums))
+ acc
+ (go (+ 1 acc) (cdr sums))))
+ (let* ([type-sums (cdr (assoc type data-layouts))])
+ (go 0 (map car type-sums))))
+
+(define (codegen-data-tor e si env)
+
+ (define (codegen-destructor tor)
+ (let* ([res (codegen-expr (cadr e) si env)]
+ [info (cadr tor)]
+ [index (caddr info)]
+ [type (car info)]
+ [sum (cadr info)])
+ (when (not (on-stack? (cadr e)))
+ (error #f "trying to destruct something that isn't a stack expression"))
+ (emit "# deconstructing")
+ (emit "movq ~a(%rbp), %rax"
+ (- si (data-product-offset (env-data-layouts env) type sum index)))))
+
+ (define (codegen-constructor tor)
+ (let* ([info (cadr tor)]
+ [type (car info)]
+ [sum (cadr info)]
+ [constructor (car e)]
+
+ [args (cdr e)]
+
+ [tag (data-sum-tag (env-data-layouts env)
+ type
+ sum)]
+
+ [insert-product
+ (lambda (expr i)
+ (let ([res (codegen-expr expr si env)]
+ [stack-offset (- si (data-product-offset (env-data-layouts env)
+ type sum
+ i))])
+ (if (on-stack? res)
+ (error #f "todo: handle stack-exprs in stack exprs")
+ (emit "movq %rax, ~a(%rbp)" stack-offset))))])
+
+ ; emit the tag
+ (emit "movq $~a, ~a(%rbp)" tag si)
+
+ (for-each insert-product args (range 0 (length args)))
+ (type-size (env-data-layouts env) type)))
+
+ (let* ([tor (data-tor env e)]
+ [constructor (eqv? 'constructor (caddr (cadr tor)))])
+ (if constructor
+ (codegen-constructor tor)
+ (codegen-destructor tor))))
+
+(define (codegen-expr e si env)
+ (emit "# ~a" e)
+ (case (ast-type e)
+ ('closure (codegen-closure (cadr e) (caddr e) si env))
+ ('app
+ (case (car e)