+(define cur-lambda 0)
+(define (fresh-lambda)
+ (set! cur-lambda (+ 1 cur-lambda))
+ (format "_lambda~a" (- cur-lambda 1)))
+
+ ; for now we can only call closures
+(define (codegen-call closure args si env)
+ (let* ((captured (caddr closure))
+ (label (cadr closure))
+ (argument-start (length captured)))
+
+ ; first move the captured variables into param registers
+ (for-each
+ (lambda (e i)
+ (emit "movq ~a(%rsp), ~a"
+ (cdr (assoc e env)) ; offset of the var
+ (param-register i)))
+ captured (range 0 (length captured)))
+
+
+ ; then codegen the arguments and move them into the next param registers
+ (for-each
+ (lambda (e i)
+ (begin
+ (codegen-expr e si env)
+ ; move result to correct param register
+ (emit "movq %rax, ~a" (param-register i))))
+ args (range argument-start (length args)))
+
+ ; now call
+ (emit "callq ~a" label)))
+
+
+(define (codegen-lambda l)
+ (let* ((label (car l))
+ (args (cadr l))
+ (captured (caddr l))
+ (body (cadddr l))
+ ; captured, then args
+ (vars (append captured args))
+
+ (param-registers (map param-register
+ (range 0 (length vars))))
+ (stack-offsets (map (lambda (i)
+ (* (- wordsize) i))
+ (range 0 (length vars))))
+
+ (copy-insts (map (lambda (r o)
+ (format "movq ~a, ~a(%rsp)"
+ r o))
+ param-registers stack-offsets))
+
+ (env (map cons vars stack-offsets)))
+ (emit "~a:" label)
+ (display "## lambda body: ")
+ (display body)
+ (newline)
+ (display "## environment: ")
+ (display env)
+ (newline)
+ (amd64-abi
+ (lambda ()
+ (for-each emit copy-insts)
+ (codegen-expr body (* (- wordsize) (length vars)) env)
+ )))) ; move args and capture vars to stack
+