Commit | Line | Data |
---|---|---|
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 |