Use `values\' and `call-with-values\'.
[bpt/guile.git] / vm / compile.scm
CommitLineData
a98cef7e
KN
1;;; compile.scm --- Compile Scheme codes
2
3;; Copyright (C) 2000 Free Software Foundation, Inc.
4
5;; This file is part of Guile VM.
6
7;; Guile VM is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 2, or (at your option)
10;; any later version.
11;;
12;; Guile VM is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16;;
17;; You should have received a copy of the GNU General Public License
18;; along with Guile VM; see the file COPYING. If not, write to
19;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20;; Boston, MA 02111-1307, USA.
21
22;;; Code:
23
24(define-module (vm compile)
25 :use-module (vm vm)
26 :use-module (vm utils)
27 :use-module (vm types)
28 :use-module (vm bytecomp)
29 :use-module (ice-9 syncase)
30 :export (compile compile-file))
31
32(define (compile form . opts)
33 (catch 'result
34 (lambda ()
35 (let ((x (syncase form)))
36 (if (or (memq #:e opts) (memq #:expand-only opts))
37 (throw 'result x))
38 (set! x (parse x (make-env '() (make-top-level-env))))
39 (if (or (memq #:p opts) (memq #:parse-only opts))
40 (throw 'result x))
41 (set! x (byte-compile 0 #f x))
42 (if (or (memq #:c opts) (memq #:compile-only opts))
43 (throw 'result x))
44 (make-program (make-bytecode x) #f)))
45 (lambda (key arg) arg)))
46
47(define (compile-file file)
48 (let ((out-file (string-append (substring file 0 (1- (string-length file)))
49 "c")))
50 (with-input-from-file file
51 (lambda ()
52 (with-output-to-file out-file
53 (lambda ()
54 (format #t ";;; Compiled from ~A\n\n" file)
dbb74d81 55 (display "(use-modules (vm vm))\n\n")
a98cef7e 56 (display "(let ((vm (make-vm)))\n")
015959cb
KN
57 (display "(define (vm-exec code)")
58 (display "(vm-run vm (make-program (make-bytecode code) #f)))\n")
a98cef7e
KN
59 (do ((input (read) (read)))
60 ((eof-object? input))
61 (display "(vm-exec ")
62 (write (compile input #:compile-only))
63 (display ")\n"))
64 (display ")\n")))))))
65
66\f
67;;;
68;;; Parser
69;;;
70
71(define (parse x env)
72 (cond ((pair? x) (parse-pair x env))
73 ((symbol? x) (make-code:ref env (env-ref env x)))
74 (else (make-code:constant env x))))
75
76(define (parse-pair x env)
77 (let ((name (car x)) (args (cdr x)))
78 (if (assq name *syntax-alist*)
79 ;; syntax
80 ((assq-ref *syntax-alist* name) args env)
81 ;; procedure
82 (let ((proc (if (symbol? name)
83 (env-ref env name)
84 (parse name env))))
85 (if (and (variable? proc)
86 (variable-bound? proc)
87 (assq (variable-value proc) *procedure-alist*))
88 ;; procedure macro
89 ((assq-ref *procedure-alist* (variable-value proc)) args env)
90 ;; procedure call
91 (apply make-code:call env proc (map-parse args env)))))))
92
93(define (map-parse x env)
94 (map (lambda (x) (parse x env)) x))
95
96\f
97;;;
98;;; Syntax
99;;;
100
101(define *syntax-list*
102 '(quote lambda set! define if cond and or begin let let* letrec
103 local-set! until))
104
105(define (parse-quote args env)
106 (make-code:constant env (car args)))
107
108(define (canon-formals formals)
eef3cc8c
KN
109 ;; foo -> (), foo
110 ;; (foo bar baz) -> (foo bar baz), #f
111 ;; (foo bar . baz) -> (foo bar), baz
a98cef7e 112 (cond ((symbol? formals)
eef3cc8c 113 (values '() formals))
a98cef7e
KN
114 ((or (null? formals)
115 (null? (cdr (last-pair formals))))
eef3cc8c 116 (values formals #f))
a98cef7e
KN
117 (else
118 (let* ((copy (list-copy formals))
119 (pair (last-pair copy))
120 (last (cdr pair)))
121 (set-cdr! pair '())
eef3cc8c 122 (values copy last)))))
a98cef7e
KN
123
124(define (parse-lambda args env)
125 (let ((formals (car args)) (body (cdr args)))
eef3cc8c
KN
126 (call-with-values (lambda () (canon-formals formals))
127 (lambda (reqs rest)
128 (let* ((syms (append reqs (if rest (list rest) '())))
129 (new-env (make-env syms env)))
130 (make-code:program env (length reqs) (if rest #t #f)
131 (parse-begin body new-env)))))))
a98cef7e
KN
132
133(define (parse-set! args env)
134 (let ((var (env-ref env (car args)))
135 (val (parse (cadr args) env)))
136 (variable-externalize! var)
137 (make-code:set env var val)))
138
139(define (parse-local-set! args env)
140 (let ((var (env-ref env (car args)))
141 (val (parse (cadr args) env)))
142 (make-code:set env var val)))
143
144(define (parse-define args env)
145 (parse-set! args env))
146
147(define (parse-if args env)
148 (let ((test (parse (car args) env))
149 (consequent (parse (cadr args) env))
150 (alternate (if (null? (cddr args))
151 (make-code:unspecified env)
152 (parse (caddr args) env))))
153 (make-code:if env test consequent alternate)))
154
155;; FIXME: This should be expanded by syncase.
156(define (parse-cond args env)
157 (cond ((null? args) (make-code:unspecified env))
158 ((eq? (caar args) 'else)
159 (parse-begin (cdar args) env))
160 (else
161 (let* ((clause (car args))
162 (test (parse (car clause) env))
163 (body (parse-begin (cdr clause) env))
164 (alternate (parse-cond (cdr args) env)))
165 (make-code:if env test body alternate)))))
166
167(define (parse-and args env)
168 (apply make-code:and env (map-parse args env)))
169
170(define (parse-or args env)
171 (apply make-code:or env (map-parse args env)))
172
173(define (parse-begin args env)
174 (apply make-code:begin env (map-parse args env)))
175
176(define (%parse-let:finish env bindings init body)
177 (for-each (lambda (binding)
178 (env-remove-variable! env (car binding)))
179 bindings)
180 (apply make-code:begin env (append! init body)))
181
182(define (parse-let args env)
183 (if (symbol? (car args))
184 ;; named let
185 (let ((tag (car args)) (bindings (cadr args)) (body (cddr args)))
186 (let* ((var (env-add-variable! env tag))
187 (proc (parse-lambda (cons (map car bindings) body) env))
188 (init (make-code:set env var proc))
189 (call (apply make-code:call env var
190 (map-parse (map cadr bindings) env))))
191 (env-remove-variable! env tag)
192 (make-code:begin env init call)))
193 ;; normal let
194 (let ((bindings (car args)) (body (cdr args)))
195 (let* (;; create values before binding
196 (vals (map-parse (map cadr bindings) env))
197 ;; create bindings
198 (init (map (lambda (sym val)
199 (let ((var (env-add-variable! env sym)))
200 (make-code:set env var val)))
201 (map car bindings) vals)))
202 (%parse-let:finish env bindings init (map-parse body env))))))
203
204(define (parse-let* args env)
205 (let ((bindings (car args)) (body (cdr args)))
206 (let (;; create values and bindings one after another
207 (init (map (lambda (binding)
208 (let* ((val (parse (cadr binding) env))
209 (var (env-add-variable! env (car binding))))
210 (make-code:set env var val)))
211 bindings)))
212 (%parse-let:finish env bindings init (map-parse body env)))))
213
214(define (parse-letrec args env)
215 (let ((bindings (car args)) (body (cdr args)))
216 (let* (;; create all variables before values
217 (vars (map (lambda (sym)
218 (env-add-variable! env sym))
219 (map car bindings)))
220 ;; create and set values
221 (init (map (lambda (var val)
222 (make-code:set env var (parse val env)))
223 vars (map cadr bindings))))
224 (%parse-let:finish env bindings init (map-parse body env)))))
225
226(define (parse-until args env)
227 (apply make-code:until env (parse (car args) env)
228 (map-parse (cdr args) env)))
229
230(define *syntax-alist*
231 (map (lambda (name)
232 (cons name (eval (symbol-append 'parse- name) (current-module))))
233 *syntax-list*))
234
235\f
236;;;
237;;; Procedure
238;;;
239
240(define *procedure-list*
241 '(caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr
242 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
243 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
015959cb
KN
244 ;;map for-each
245 ))
a98cef7e
KN
246
247(define (parse-caar args env) (parse `(car (car ,@args)) env))
248(define (parse-cadr args env) (parse `(car (cdr ,@args)) env))
249(define (parse-cdar args env) (parse `(cdr (car ,@args)) env))
250(define (parse-cddr args env) (parse `(cdr (cdr ,@args)) env))
251
252(define (parse-caaar args env) (parse `(car (car (car ,@args))) env))
253(define (parse-caadr args env) (parse `(car (car (cdr ,@args))) env))
254(define (parse-cadar args env) (parse `(car (cdr (car ,@args))) env))
255(define (parse-caddr args env) (parse `(car (cdr (cdr ,@args))) env))
256(define (parse-cdaar args env) (parse `(cdr (car (car ,@args))) env))
257(define (parse-cdadr args env) (parse `(cdr (car (cdr ,@args))) env))
258(define (parse-cddar args env) (parse `(cdr (cdr (car ,@args))) env))
259(define (parse-cdddr args env) (parse `(cdr (cdr (cdr ,@args))) env))
260
261(define (parse-caaaar args env) (parse `(car (car (car (car ,@args)))) env))
262(define (parse-caaadr args env) (parse `(car (car (car (cdr ,@args)))) env))
263(define (parse-caadar args env) (parse `(car (car (cdr (car ,@args)))) env))
264(define (parse-caaddr args env) (parse `(car (car (cdr (cdr ,@args)))) env))
265(define (parse-cadaar args env) (parse `(car (cdr (car (car ,@args)))) env))
266(define (parse-cadadr args env) (parse `(car (cdr (car (cdr ,@args)))) env))
267(define (parse-caddar args env) (parse `(car (cdr (cdr (car ,@args)))) env))
268(define (parse-cadddr args env) (parse `(car (cdr (cdr (cdr ,@args)))) env))
269(define (parse-cdaaar args env) (parse `(cdr (car (car (car ,@args)))) env))
270(define (parse-cdaadr args env) (parse `(cdr (car (car (cdr ,@args)))) env))
271(define (parse-cdadar args env) (parse `(cdr (car (cdr (car ,@args)))) env))
272(define (parse-cdaddr args env) (parse `(cdr (car (cdr (cdr ,@args)))) env))
273(define (parse-cddaar args env) (parse `(cdr (cdr (car (car ,@args)))) env))
274(define (parse-cddadr args env) (parse `(cdr (cdr (car (cdr ,@args)))) env))
275(define (parse-cdddar args env) (parse `(cdr (cdr (cdr (car ,@args)))) env))
276(define (parse-cddddr args env) (parse `(cdr (cdr (cdr (cdr ,@args)))) env))
277
015959cb
KN
278;(define (parse-map args env)
279; (check-nargs args >= 2)
280; (case (length args)
281; ((2)
282; (let ((proc (car args)) (list (cadr args)))
283; (parse `(let ((list ,list) (result '()))
284; (until (null? list)
285; (local-set! result (cons (,proc (car list)) result))
286; (local-set! list (cdr list)))
287; (reverse! result))
288; env)))
289; (else
290; (error "Not implemented yet"))))
291;
292;(define (parse-for-each args env)
293; (check-nargs args >= 2)
294; (case (length args)
295; ((2)
296; (let ((proc (car args)) (list (cadr args)))
297; (parse `(let ((list ,list))
298; (until (null? list)
299; (,proc (car list))
300; (local-set! list (cdr list))))
301; env)))
302; (else
303; (error "Not implemented yet"))))
a98cef7e
KN
304
305(define *procedure-alist*
306 (map (lambda (name)
307 (cons (eval name (current-module))
308 (eval (symbol-append 'parse- name) (current-module))))
309 *procedure-list*))
310
311;;; compile.scm ends here