Skip to content

Commit

Permalink
First cut at lambda lift
Browse files Browse the repository at this point in the history
Holy fuck! This patch took me months to write. Yes, literally months to get
here. Also I kind of hate Chez scheme by now. I want Haskell back.
  • Loading branch information
jaseemabid committed Jul 19, 2018
1 parent ad0788e commit 5157d8e
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 5 deletions.
49 changes: 49 additions & 0 deletions src/compiler.scm
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,55 @@
[(list? expr) (map (lambda (e) (cc e env)) expr)]
[else expr]))

;; lift code blocks
;;
;; An incremental approach is required here more than anywhere else. Sigh!
;;
;; 1. Lambdas bound inside named letrec, with no free variables
;;

(define (lift env expr)

(define labels '())

;; Replace a function call of the form (NAME ...) with (labelcall NAME ...)
(define (labelcall name)
(lambda (expr)
(cond [((tagged-list name) expr)
(cons 'labelcall (cons name (cdr expr)) )]
[(list? expr) (map (labelcall name) expr)]
[else expr])))

(define (lift-lambda name expr)
(assert (lambda? expr))

(let* ([formals (second expr)]
[body (third expr)]
[free (free-vars expr env)]

;; Use the components to build transformed version
[this (list 'code formals free (cc body env))])

;; Add the code to top label with name
(set! labels (cons (list name this) labels))))

;; Handle simplest letrec to begin with
(assert (letrec? expr))

;; OMG! Scheme is so fucking hard to read, write or understand.
(letrec ([bindings (second expr)])
(let* ([lvars (map first bindings)]
[lambdas (map second bindings)]
[letrec-body (third expr)])

;; Lift each lambda to top level labels and replace calls in the body
(for-each (lambda (name lam)
(lift-lambda name lam)
(set! letrec-body ((labelcall name) letrec-body)))
lvars lambdas)

(list 'labels labels letrec-body))))

;; Codegen helpers

(define (emit-label label)
Expand Down
13 changes: 8 additions & 5 deletions tests/10-cc.scm
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
[o (lambda (x) (if (zero? x) #f (e (dec x))))])
(e 25)))

(define result '(letrec ([e (code (x) (o) (if (zero? x) #t (o (dec x))))]
[o (code (x) (e) (if (zero? x) #f (e (dec x))))])
(e 25)))
(define lifted '(labels ([o (code (x) (e) (if (zero? x) #f (e (dec x))))]
[e (code (x) (o) (if (zero? x) #t (o (dec x))))])
(labelcall e 25)))

(add-tests "free variables"

Expand All @@ -27,10 +27,13 @@
;; Something non trivial
[(free-vars sample default-env) >> '(e o)])


(add-tests "closure conversion"

;; The simplest example
[(cc '(lambda (x) (+ x y)) default-env) >>
'(code (x) (y) (+ x y))]
'(code (x) (y) (+ x y))])

(add-tests "lift"

[(cc sample default-env) >> result])
[(lift default-env sample ) >> lifted])

0 comments on commit 5157d8e

Please sign in to comment.