-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmother-compile.lisp
64 lines (54 loc) · 2.22 KB
/
mother-compile.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
(in-package #:mother)
(defclass compiled-proc ()
())
(defvar *free*)
(defun linearize-form (form expecting)
(typecase form
(symbol (if expecting (list (gen-lookup form)) nil))
((cons symbol)
(case (first form)
((lambda) (if expecting (linearize-lambda (second form) (cddr form)) nil))
((quote) (if expecting (list (gen-const (second form))) nil))
((begin) (linearize-begin (rest form) expecting))
((if) (linearize-if (second form) (third form) (fourth form) expecting))
(otherwise (linearize-app (first form) (rest form) expecting))))
(cons (linearize-app (first form) (rest form) expecting))
(t (if expecting (list (gen-const (second form)))))))
(defun linearize-begin (forms expecting)
;; lol inefficient
;; (begin) doesn't work atm (or well, it does, it just returns an ugly value)
(nconc (mapcan (rcurry #'linearize-form expecting) (butlast forms))
(linearize-form (first (last forms)) expecting)))
(defun of-list (list) (lambda (item) (find item list)))
(defun linearize-lambda (formals body)
(let* ((thunk (make-thunk body))
;; could be set-difference, but there should be other reasons to not close over variables
;; e.g. if the function doesn't actually escape
(close (remove-if (of-list formals) (thunk-free thunk)))
(lambda (make-instance 'compiled-lambda :thunk thunk :formals formals)))
(if close
(linearize-closure lambda close)
(list (lift lambda)))))
(defun linearize-closure (lambda closing)
;; generate code to allocate a closure
(nconc (mapcar #'gen-lookup closing)
(list `(alloc-frame ,(length closing)))
(list (lift lambda))
(list '(alloc-closure))))
(defun make-thunk (body)
(let ((*free* nil))
;; Uses left-to-right arg evaluation, since the linearization is accumulating the *free*.
(make-instance 'compiled-thunk
:body (linearize-begin body t)
:free *free*)))
(defun linearize-app (fun args expecting)
(defun linearize-if (cond then alt expecting)
(let ((else (gensym "ELSE"))
(done (gensym "DONE")))
(nconc (linearize-form cond t)
(list `(jump-if-false ,else))
(linearize-form then expecting)
(list `(jump ,done))
(list `(label ,else))
(linearize-form alt expecting)
(list `(label ,done)))))