Commit | Line | Data |
---|---|---|
cb4cca12 KN |
1 | ;;; High-level compiler interface |
2 | ||
3 | ;; Copyright (C) 2001 Free Software Foundation, Inc. | |
4 | ||
5 | ;; This program is free software; you can redistribute it and/or modify | |
6 | ;; it under the terms of the GNU General Public License as published by | |
7 | ;; the Free Software Foundation; either version 2, or (at your option) | |
8 | ;; any later version. | |
9 | ;; | |
10 | ;; This program is distributed in the hope that it will be useful, | |
11 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | ;; GNU General Public License for more details. | |
14 | ;; | |
15 | ;; You should have received a copy of the GNU General Public License | |
16 | ;; along with this program; see the file COPYING. If not, write to | |
17 | ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | ;; Boston, MA 02111-1307, USA. | |
19 | ||
20 | ;;; Code: | |
21 | ||
22 | (define-module (system base compile) | |
1a1a10d3 AW |
23 | #:use-syntax (system base syntax) |
24 | #:use-module (system base language) | |
3de80ed5 AW |
25 | #:use-module ((system il compile) #:select ((compile . compile-il))) |
26 | #:use-module (system il ghil) | |
1a1a10d3 AW |
27 | #:use-module (system il glil) |
28 | #:use-module (system vm objcode) | |
1a1a10d3 | 29 | #:use-module (system vm assemble) |
3de80ed5 | 30 | #:use-module (system vm vm) ;; for compile-time evaluation |
1a1a10d3 | 31 | #:use-module (ice-9 regex) |
3de80ed5 | 32 | #:use-module (ice-9 optargs) |
1a1a10d3 | 33 | #:export (syntax-error compile-file load-source-file load-file |
3de80ed5 AW |
34 | *current-language* |
35 | compiled-file-name | |
36 | compile-time-environment | |
37 | compile read-file-in compile-in | |
38 | load/compile) | |
39 | #:export-syntax (call-with-compile-error-catch)) | |
8f5cfc81 KN |
40 | |
41 | ;;; | |
42 | ;;; Compiler environment | |
43 | ;;; | |
44 | ||
77046be3 | 45 | (define (syntax-error loc msg exp) |
1e6ebf54 | 46 | (throw 'syntax-error-compile-time loc msg exp)) |
8f5cfc81 | 47 | |
48302624 | 48 | (define-macro (call-with-compile-error-catch thunk) |
1e6ebf54 | 49 | `(catch 'syntax-error-compile-time |
48302624 | 50 | ,thunk |
d8eeb67c | 51 | (lambda (key loc msg exp) |
2335fb97 | 52 | (if (pair? loc) |
1e6ebf54 AW |
53 | (format (current-error-port) |
54 | "~A:~A: ~A: ~A~%" (car loc) (cdr loc) msg exp) | |
55 | (format (current-error-port) | |
56 | "unknown location: ~A: ~A~%" msg exp))))) | |
48302624 | 57 | |
8f5cfc81 KN |
58 | \f |
59 | ;;; | |
60 | ;;; Compiler | |
61 | ;;; | |
cb4cca12 | 62 | |
3de80ed5 | 63 | (define *current-language* (make-fluid)) |
cb4cca12 | 64 | |
03fa04df AW |
65 | ;; This is basically to avoid mucking with the backtrace. |
66 | (define (call-with-nonlocal-exit-protect thunk on-nonlocal-exit) | |
67 | (let ((success #f) (entered #f)) | |
68 | (dynamic-wind | |
69 | (lambda () | |
70 | (if entered | |
71 | (error "thunk may only be entered once: ~a" thunk)) | |
72 | (set! entered #t)) | |
73 | (lambda () | |
74 | (thunk) | |
75 | (set! success #t)) | |
76 | (lambda () | |
77 | (if (not success) | |
78 | (on-nonlocal-exit)))))) | |
79 | ||
e6d4e05c AW |
80 | (define (call-with-output-file/atomic filename proc) |
81 | (let* ((template (string-append filename ".XXXXXX")) | |
82 | (tmp (mkstemp! template))) | |
03fa04df AW |
83 | (call-with-nonlocal-exit-protect |
84 | (lambda () | |
85 | (with-output-to-port tmp | |
86 | (lambda () (proc (current-output-port)))) | |
87 | (rename-file template filename)) | |
88 | (lambda () | |
89 | (delete-file template))))) | |
e6d4e05c | 90 | |
77046be3 | 91 | (define (compile-file file . opts) |
d79d908e | 92 | (let ((comp (compiled-file-name file)) |
3de80ed5 | 93 | (lang (fluid-ref *current-language*))) |
48302624 | 94 | (catch 'nothing-at-all |
8f5cfc81 | 95 | (lambda () |
48302624 LC |
96 | (call-with-compile-error-catch |
97 | (lambda () | |
e6d4e05c | 98 | (call-with-output-file/atomic comp |
cb4cca12 | 99 | (lambda (port) |
3de80ed5 | 100 | (let* ((source (read-file-in file lang)) |
8f5cfc81 | 101 | (objcode (apply compile-in source (current-module) |
3de80ed5 | 102 | lang opts))) |
1a1a10d3 | 103 | (if (memq #:c opts) |
ac99cb0c | 104 | (pprint-glil objcode port) |
054599f1 | 105 | (uniform-vector-write (objcode->u8vector objcode) port))))) |
48302624 | 106 | (format #t "wrote `~A'\n" comp)))) |
8f5cfc81 | 107 | (lambda (key . args) |
b6368dbb | 108 | (format #t "ERROR: during compilation of ~A:\n" file) |
8f5cfc81 | 109 | (display "ERROR: ") |
f21dfea6 | 110 | (apply format #t (cadr args) (caddr args)) |
8f5cfc81 | 111 | (newline) |
f21dfea6 | 112 | (format #t "ERROR: ~A ~A ~A\n" key (car args) (cadddr args)) |
8f5cfc81 KN |
113 | (delete-file comp))))) |
114 | ||
054599f1 LC |
115 | ; (let ((c-f compile-file)) |
116 | ; ;; XXX: Debugging output | |
117 | ; (set! compile-file | |
118 | ; (lambda (file . opts) | |
119 | ; (format #t "compile-file: ~a ~a~%" file opts) | |
120 | ; (let ((result (apply c-f (cons file opts)))) | |
121 | ; (format #t "compile-file: returned ~a~%" result) | |
122 | ; result)))) | |
123 | ||
77046be3 | 124 | (define (load-source-file file . opts) |
3de80ed5 AW |
125 | (let ((lang (fluid-ref *current-language*))) |
126 | (let ((source (read-file-in file lang))) | |
127 | (apply compile-in source (current-module) lang opts)))) | |
8f5cfc81 | 128 | |
77046be3 | 129 | (define (load-file file . opts) |
8f5cfc81 KN |
130 | (let ((comp (compiled-file-name file))) |
131 | (if (file-exists? comp) | |
f21dfea6 | 132 | (load-objcode comp) |
8f5cfc81 KN |
133 | (apply load-source-file file opts)))) |
134 | ||
77046be3 | 135 | (define (compiled-file-name file) |
3de80ed5 AW |
136 | (let ((base (basename file)) |
137 | (cext (cond ((or (null? %load-compiled-extensions) | |
138 | (string-null? (car %load-compiled-extensions))) | |
139 | (warn "invalid %load-compiled-extensions" | |
140 | %load-compiled-extensions) | |
141 | ".go") | |
142 | (else (car %load-compiled-extensions))))) | |
143 | (let lp ((exts %load-extensions)) | |
144 | (cond ((null? exts) (string-append base cext)) | |
145 | ((string-null? (car exts)) (lp (cdr exts))) | |
146 | ((string-suffix? (car exts) base) | |
147 | (string-append | |
148 | (substring base 0 | |
149 | (- (string-length base) (string-length (car exts)))) | |
150 | cext)) | |
151 | (else (lp (cdr exts))))))) | |
152 | ||
153 | ;;; environment := #f | |
154 | ;;; | MODULE | |
155 | ;;; | COMPILE-ENV | |
156 | ;;; compile-env := (MODULE LEXICALS . EXTERNALS) | |
157 | (define (cenv-module env) | |
158 | (cond ((not env) #f) | |
159 | ((module? env) env) | |
160 | ((and (pair? env) (module? (car env))) (car env)) | |
161 | (else (error "bad environment" env)))) | |
162 | ||
163 | (define (cenv-ghil-env env) | |
164 | (cond ((not env) (make-ghil-toplevel-env)) | |
165 | ((module? env) (make-ghil-toplevel-env)) | |
166 | ((pair? env) | |
167 | (ghil-env-dereify (cadr env))) | |
168 | (else (error "bad environment" env)))) | |
169 | ||
170 | (define (cenv-externals env) | |
171 | (cond ((not env) '()) | |
172 | ((module? env) '()) | |
173 | ((pair? env) (cddr env)) | |
174 | (else (error "bad environment" env)))) | |
175 | ||
176 | (define (compile-time-environment) | |
177 | "A special function known to the compiler that, when compiled, will | |
178 | return a representation of the lexical environment in place at compile | |
179 | time. Useful for supporting some forms of dynamic compilation. Returns | |
180 | #f if called from the interpreter." | |
181 | #f) | |
182 | ||
183 | (define* (compile x #:optional env) | |
184 | (let ((thunk (objcode->program | |
185 | (compile-in x env (fluid-ref *current-language*)) | |
186 | (cenv-externals env)))) | |
187 | (if (not env) | |
188 | (thunk) | |
189 | (save-module-excursion | |
190 | (lambda () | |
191 | (set-current-module (cenv-module env)) | |
192 | (thunk)))))) | |
7a0d0cee | 193 | |
8f5cfc81 KN |
194 | \f |
195 | ;;; | |
196 | ;;; Scheme compiler interface | |
197 | ;;; | |
198 | ||
77046be3 | 199 | (define (read-file-in file lang) |
44f38a1f | 200 | (call-with-input-file file (language-read-file lang))) |
8f5cfc81 | 201 | |
77046be3 | 202 | (define (compile-in x e lang . opts) |
1b8abe55 AW |
203 | (save-module-excursion |
204 | (lambda () | |
205 | (catch 'result | |
206 | (lambda () | |
3de80ed5 AW |
207 | (and=> (cenv-module e) set-current-module) |
208 | (set! e (cenv-ghil-env e)) | |
1b8abe55 AW |
209 | ;; expand |
210 | (set! x ((language-expander lang) x e)) | |
1a1a10d3 | 211 | (if (memq #:e opts) (throw 'result x)) |
1b8abe55 AW |
212 | ;; translate |
213 | (set! x ((language-translator lang) x e)) | |
1a1a10d3 | 214 | (if (memq #:t opts) (throw 'result x)) |
1b8abe55 | 215 | ;; compile |
3de80ed5 | 216 | (set! x (apply compile-il x e opts)) |
1a1a10d3 | 217 | (if (memq #:c opts) (throw 'result x)) |
1b8abe55 AW |
218 | ;; assemble |
219 | (apply assemble x e opts)) | |
220 | (lambda (key val) val))))) | |
8f5cfc81 KN |
221 | |
222 | ;;; | |
b6368dbb | 223 | ;;; |
8f5cfc81 KN |
224 | ;;; |
225 | ||
226 | (define (compile-and-load file . opts) | |
227 | (let ((comp (object-file-name file))) | |
228 | (if (or (not (file-exists? comp)) | |
229 | (> (stat:mtime (stat file)) (stat:mtime (stat comp)))) | |
230 | (compile-file file)) | |
231 | (load-compiled-file comp))) | |
232 | ||
233 | (define (load/compile file . opts) | |
234 | (let* ((file (file-full-name file)) | |
235 | (compiled (object-file-name file))) | |
236 | (if (or (not (file-exists? compiled)) | |
237 | (> (stat:mtime (stat file)) (stat:mtime (stat compiled)))) | |
238 | (apply compile-file file #f opts)) | |
239 | (if (memq #:b opts) | |
240 | (apply vm-trace (the-vm) (load-objcode compiled) opts) | |
241 | ((the-vm) (load-objcode compiled))))) | |
242 | ||
243 | (define (file-full-name filename) | |
244 | (let* ((port (current-load-port)) | |
245 | (oldname (and port (port-filename port)))) | |
246 | (if (and oldname | |
247 | (> (string-length filename) 0) | |
248 | (not (char=? (string-ref filename 0) #\/)) | |
249 | (not (string=? (dirname oldname) "."))) | |
250 | (string-append (dirname oldname) "/" filename) | |
251 | filename))) | |
3de80ed5 AW |
252 | |
253 | (fluid-set! *current-language* (lookup-language 'scheme)) |