recompiling with compile environments, fluid languages, cleanups
[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
e6d4e05c
AW
65(define (call-with-output-file/atomic filename proc)
66 (let* ((template (string-append filename ".XXXXXX"))
67 (tmp (mkstemp! template)))
68 (catch #t
69 (lambda ()
70 (with-output-to-port tmp
71 (lambda () (proc (current-output-port))))
72 (rename-file template filename))
73 (lambda args
74 (delete-file template)
75 (apply throw args)))))
76
77046be3 77(define (compile-file file . opts)
d79d908e 78 (let ((comp (compiled-file-name file))
3de80ed5 79 (lang (fluid-ref *current-language*)))
48302624 80 (catch 'nothing-at-all
8f5cfc81 81 (lambda ()
48302624
LC
82 (call-with-compile-error-catch
83 (lambda ()
e6d4e05c 84 (call-with-output-file/atomic comp
cb4cca12 85 (lambda (port)
3de80ed5 86 (let* ((source (read-file-in file lang))
8f5cfc81 87 (objcode (apply compile-in source (current-module)
3de80ed5 88 lang opts)))
1a1a10d3 89 (if (memq #:c opts)
ac99cb0c 90 (pprint-glil objcode port)
054599f1 91 (uniform-vector-write (objcode->u8vector objcode) port)))))
48302624 92 (format #t "wrote `~A'\n" comp))))
8f5cfc81 93 (lambda (key . args)
b6368dbb 94 (format #t "ERROR: during compilation of ~A:\n" file)
8f5cfc81 95 (display "ERROR: ")
f21dfea6 96 (apply format #t (cadr args) (caddr args))
8f5cfc81 97 (newline)
f21dfea6 98 (format #t "ERROR: ~A ~A ~A\n" key (car args) (cadddr args))
8f5cfc81
KN
99 (delete-file comp)))))
100
054599f1
LC
101; (let ((c-f compile-file))
102; ;; XXX: Debugging output
103; (set! compile-file
104; (lambda (file . opts)
105; (format #t "compile-file: ~a ~a~%" file opts)
106; (let ((result (apply c-f (cons file opts))))
107; (format #t "compile-file: returned ~a~%" result)
108; result))))
109
77046be3 110(define (load-source-file file . opts)
3de80ed5
AW
111 (let ((lang (fluid-ref *current-language*)))
112 (let ((source (read-file-in file lang)))
113 (apply compile-in source (current-module) lang opts))))
8f5cfc81 114
77046be3 115(define (load-file file . opts)
8f5cfc81
KN
116 (let ((comp (compiled-file-name file)))
117 (if (file-exists? comp)
f21dfea6 118 (load-objcode comp)
8f5cfc81
KN
119 (apply load-source-file file opts))))
120
77046be3 121(define (compiled-file-name file)
3de80ed5
AW
122 (let ((base (basename file))
123 (cext (cond ((or (null? %load-compiled-extensions)
124 (string-null? (car %load-compiled-extensions)))
125 (warn "invalid %load-compiled-extensions"
126 %load-compiled-extensions)
127 ".go")
128 (else (car %load-compiled-extensions)))))
129 (let lp ((exts %load-extensions))
130 (cond ((null? exts) (string-append base cext))
131 ((string-null? (car exts)) (lp (cdr exts)))
132 ((string-suffix? (car exts) base)
133 (string-append
134 (substring base 0
135 (- (string-length base) (string-length (car exts))))
136 cext))
137 (else (lp (cdr exts)))))))
138
139;;; environment := #f
140;;; | MODULE
141;;; | COMPILE-ENV
142;;; compile-env := (MODULE LEXICALS . EXTERNALS)
143(define (cenv-module env)
144 (cond ((not env) #f)
145 ((module? env) env)
146 ((and (pair? env) (module? (car env))) (car env))
147 (else (error "bad environment" env))))
148
149(define (cenv-ghil-env env)
150 (cond ((not env) (make-ghil-toplevel-env))
151 ((module? env) (make-ghil-toplevel-env))
152 ((pair? env)
153 (ghil-env-dereify (cadr env)))
154 (else (error "bad environment" env))))
155
156(define (cenv-externals env)
157 (cond ((not env) '())
158 ((module? env) '())
159 ((pair? env) (cddr env))
160 (else (error "bad environment" env))))
161
162(define (compile-time-environment)
163 "A special function known to the compiler that, when compiled, will
164return a representation of the lexical environment in place at compile
165time. Useful for supporting some forms of dynamic compilation. Returns
166#f if called from the interpreter."
167 #f)
168
169(define* (compile x #:optional env)
170 (let ((thunk (objcode->program
171 (compile-in x env (fluid-ref *current-language*))
172 (cenv-externals env))))
173 (if (not env)
174 (thunk)
175 (save-module-excursion
176 (lambda ()
177 (set-current-module (cenv-module env))
178 (thunk))))))
7a0d0cee 179
8f5cfc81
KN
180\f
181;;;
182;;; Scheme compiler interface
183;;;
184
77046be3 185(define (read-file-in file lang)
44f38a1f 186 (call-with-input-file file (language-read-file lang)))
8f5cfc81 187
77046be3 188(define (compile-in x e lang . opts)
1b8abe55
AW
189 (save-module-excursion
190 (lambda ()
191 (catch 'result
192 (lambda ()
3de80ed5
AW
193 (and=> (cenv-module e) set-current-module)
194 (set! e (cenv-ghil-env e))
1b8abe55
AW
195 ;; expand
196 (set! x ((language-expander lang) x e))
1a1a10d3 197 (if (memq #:e opts) (throw 'result x))
1b8abe55
AW
198 ;; translate
199 (set! x ((language-translator lang) x e))
1a1a10d3 200 (if (memq #:t opts) (throw 'result x))
1b8abe55 201 ;; compile
3de80ed5 202 (set! x (apply compile-il x e opts))
1a1a10d3 203 (if (memq #:c opts) (throw 'result x))
1b8abe55
AW
204 ;; assemble
205 (apply assemble x e opts))
206 (lambda (key val) val)))))
8f5cfc81
KN
207
208;;;
b6368dbb 209;;;
8f5cfc81
KN
210;;;
211
212(define (compile-and-load file . opts)
213 (let ((comp (object-file-name file)))
214 (if (or (not (file-exists? comp))
215 (> (stat:mtime (stat file)) (stat:mtime (stat comp))))
216 (compile-file file))
217 (load-compiled-file comp)))
218
219(define (load/compile file . opts)
220 (let* ((file (file-full-name file))
221 (compiled (object-file-name file)))
222 (if (or (not (file-exists? compiled))
223 (> (stat:mtime (stat file)) (stat:mtime (stat compiled))))
224 (apply compile-file file #f opts))
225 (if (memq #:b opts)
226 (apply vm-trace (the-vm) (load-objcode compiled) opts)
227 ((the-vm) (load-objcode compiled)))))
228
229(define (file-full-name filename)
230 (let* ((port (current-load-port))
231 (oldname (and port (port-filename port))))
232 (if (and oldname
233 (> (string-length filename) 0)
234 (not (char=? (string-ref filename 0) #\/))
235 (not (string=? (dirname oldname) ".")))
236 (string-append (dirname oldname) "/" filename)
237 filename)))
3de80ed5
AW
238
239(fluid-set! *current-language* (lookup-language 'scheme))