pass backtraces through the compiler
[bpt/guile.git] / module / system / base / compile.scm
CommitLineData
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
178return a representation of the lexical environment in place at compile
179time. 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))