Fix a bug in the (ice-9 match) test
[bpt/guile.git] / module / system / base / compile.scm
CommitLineData
cb4cca12
KN
1;;; High-level compiler interface
2
b96dac4d 3;; Copyright (C) 2001, 2009 Free Software Foundation, Inc.
cb4cca12
KN
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)
b0b180d5 23 #:use-module (system base syntax)
1a1a10d3 24 #:use-module (system base language)
b0b180d5 25 #:use-module (system vm vm) ;; FIXME: there's a reason for this, can't remember why tho
1a1a10d3 26 #:use-module (ice-9 regex)
3de80ed5 27 #:use-module (ice-9 optargs)
b0b180d5
AW
28 #:use-module (ice-9 receive)
29 #:export (syntax-error
3de80ed5 30 *current-language*
b0b180d5 31 compiled-file-name compile-file compile-and-load
7b107cce
AW
32 compile compile-time-environment
33 decompile)
3de80ed5 34 #:export-syntax (call-with-compile-error-catch))
8f5cfc81
KN
35
36;;;
37;;; Compiler environment
38;;;
39
77046be3 40(define (syntax-error loc msg exp)
1e6ebf54 41 (throw 'syntax-error-compile-time loc msg exp))
8f5cfc81 42
48302624 43(define-macro (call-with-compile-error-catch thunk)
1e6ebf54 44 `(catch 'syntax-error-compile-time
48302624 45 ,thunk
d8eeb67c 46 (lambda (key loc msg exp)
2335fb97 47 (if (pair? loc)
237f96e7
AW
48 (let ((file (or (assq-ref loc 'filename) "unknown file"))
49 (line (assq-ref loc 'line))
50 (col (assq-ref loc 'column)))
51 (format (current-error-port)
52 "~A:~A:~A: ~A: ~A~%" file line col msg exp))
53 (format (current-error-port)
98922879 54 "unknown location: ~A: ~S~%" msg exp)))))
48302624 55
8f5cfc81
KN
56\f
57;;;
58;;; Compiler
59;;;
cb4cca12 60
3de80ed5 61(define *current-language* (make-fluid))
7b107cce 62(fluid-set! *current-language* 'scheme)
b0b180d5 63(define (current-language)
7b107cce 64 (fluid-ref *current-language*))
cb4cca12 65
b0b180d5
AW
66(define (call-once thunk)
67 (let ((entered #f))
03fa04df
AW
68 (dynamic-wind
69 (lambda ()
70 (if entered
71 (error "thunk may only be entered once: ~a" thunk))
72 (set! entered #t))
b0b180d5
AW
73 thunk
74 (lambda () #t))))
75
e6d4e05c
AW
76(define (call-with-output-file/atomic filename proc)
77 (let* ((template (string-append filename ".XXXXXX"))
78 (tmp (mkstemp! template)))
b0b180d5 79 (call-once
03fa04df 80 (lambda ()
b0b180d5
AW
81 (with-throw-handler #t
82 (lambda ()
98922879 83 (proc tmp)
a56db0f6 84 (chmod tmp (logand #o0666 (lognot (umask))))
5a0df7be 85 (close-port tmp)
b0b180d5
AW
86 (rename-file template filename))
87 (lambda args
88 (delete-file template)))))))
e6d4e05c 89
7b107cce
AW
90(define (ensure-language x)
91 (if (language? x)
92 x
93 (lookup-language x)))
94
b8076ec6
AW
95(define* (compile-file file #:key
96 (output-file #f)
97 (env #f)
98 (from (current-language))
99 (to 'objcode)
100 (opts '()))
73f4d8d1 101 (let ((comp (or output-file (compiled-file-name file)))
b8076ec6
AW
102 (in (open-input-file file)))
103 (call-with-output-file/atomic comp
104 (lambda (port)
105 ((language-printer (ensure-language to))
106 (read-and-compile in #:env env #:from from #:to to #:opts opts)
107 port)))
108 comp))
8f5cfc81 109
7b107cce 110(define* (compile-and-load file #:key (to 'value) (opts '()))
b8076ec6
AW
111 (read-and-compile (open-input-port file)
112 #:from lang #:to to #:opts opts))
8f5cfc81 113
77046be3 114(define (compiled-file-name file)
3de80ed5
AW
115 (let ((base (basename file))
116 (cext (cond ((or (null? %load-compiled-extensions)
117 (string-null? (car %load-compiled-extensions)))
118 (warn "invalid %load-compiled-extensions"
119 %load-compiled-extensions)
120 ".go")
121 (else (car %load-compiled-extensions)))))
122 (let lp ((exts %load-extensions))
b96dac4d 123 (cond ((null? exts) (string-append file cext))
3de80ed5
AW
124 ((string-null? (car exts)) (lp (cdr exts)))
125 ((string-suffix? (car exts) base)
126 (string-append
b96dac4d 127 (dirname file) "/"
3de80ed5
AW
128 (substring base 0
129 (- (string-length base) (string-length (car exts))))
130 cext))
131 (else (lp (cdr exts)))))))
132
8f5cfc81
KN
133\f
134;;;
b0b180d5 135;;; Compiler interface
8f5cfc81
KN
136;;;
137
77046be3 138(define (read-file-in file lang)
b0b180d5
AW
139 (call-with-input-file file
140 (or (language-read-file lang)
141 (error "language has no #:read-file" lang))))
142
143(define (compile-passes from to opts)
5d6fb8bb
AW
144 (map cdr
145 (or (lookup-compilation-order from to)
146 (error "no way to compile" from "to" to))))
8f5cfc81 147
b0b180d5 148(define (compile-fold passes exp env opts)
b8076ec6
AW
149 (let lp ((passes passes) (x exp) (e env) (cenv env) (first? #t))
150 (if (null? passes)
151 (values x e cenv)
152 (receive (x e new-cenv) ((car passes) x e opts)
153 (lp (cdr passes) x e (if first? new-cenv cenv) #f)))))
8f5cfc81 154
b0b180d5
AW
155(define (compile-time-environment)
156 "A special function known to the compiler that, when compiled, will
157return a representation of the lexical environment in place at compile
158time. Useful for supporting some forms of dynamic compilation. Returns
159#f if called from the interpreter."
160 #f)
3de80ed5 161
b8076ec6
AW
162(define (find-language-joint from to)
163 (let lp ((in (reverse (or (lookup-compilation-order from to)
164 (error "no way to compile" from "to" to))))
165 (lang to))
166 (cond ((null? in)
167 (error "don't know how to join expressions" from to))
168 ((language-joiner lang) lang)
169 (else
170 (lp (cdr in) (caar in))))))
171
172(define* (read-and-compile port #:key
173 (env #f)
174 (from (current-language))
175 (to 'objcode)
176 (opts '()))
177 (let ((from (ensure-language from))
178 (to (ensure-language to)))
179 (let ((joint (find-language-joint from to)))
180 (with-fluids ((*current-language* from))
181 (let lp ((exps '()) (env #f) (cenv env))
182 (let ((x ((language-reader (current-language)) port)))
183 (cond
184 ((eof-object? x)
185 (compile ((language-joiner joint) (reverse exps) env)
186 #:from joint #:to to #:env env #:opts opts))
187 (else
188 ;; compile-fold instead of compile so we get the env too
189 (receive (jexp jenv jcenv)
190 (compile-fold (compile-passes (current-language) joint opts)
191 x cenv opts)
192 (lp (cons jexp exps) jenv jcenv))))))))))
193
b0b180d5
AW
194(define* (compile x #:key
195 (env #f)
196 (from (current-language))
7b107cce 197 (to 'value)
b0b180d5 198 (opts '()))
b8076ec6
AW
199 (receive (exp env cenv)
200 (compile-fold (compile-passes from to opts) x env opts)
201 exp))
7b107cce
AW
202
203\f
204;;;
205;;; Decompiler interface
206;;;
207
208(define (decompile-passes from to opts)
209 (map cdr
210 (or (lookup-decompilation-order from to)
211 (error "no way to decompile" from "to" to))))
212
d7236899
AW
213(define (decompile-fold passes exp env opts)
214 (if (null? passes)
215 (values exp env)
216 (receive (exp env) ((car passes) exp env opts)
217 (decompile-fold (cdr passes) exp env opts))))
218
7b107cce
AW
219(define* (decompile x #:key
220 (env #f)
221 (from 'value)
222 (to 'assembly)
223 (opts '()))
d7236899
AW
224 (decompile-fold (decompile-passes from to opts)
225 x
226 env
227 opts))