better invocation documentation
[bpt/guile.git] / module / system / base / compile.scm
CommitLineData
cb4cca12
KN
1;;; High-level compiler interface
2
eda06220 3;; Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
cb4cca12 4
e1203ea0
LC
5;;; This library is free software; you can redistribute it and/or
6;;; modify it under the terms of the GNU Lesser General Public
7;;; License as published by the Free Software Foundation; either
8;;; version 3 of the License, or (at your option) any later version.
9;;;
10;;; This library 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 GNU
13;;; Lesser General Public License for more details.
14;;;
15;;; You should have received a copy of the GNU Lesser General Public
16;;; License along with this library; if not, write to the Free Software
17;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
cb4cca12
KN
18
19;;; Code:
20
21(define-module (system base compile)
b0b180d5 22 #:use-module (system base syntax)
1a1a10d3 23 #:use-module (system base language)
2e4c3227 24 #:use-module (system base message)
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 28 #:use-module (ice-9 receive)
6cb42361 29 #:export (compiled-file-name
8753fd53
AW
30 compile-file
31 compile-and-load
32 read-and-compile
68623e8e 33 compile
6cb42361 34 decompile))
8f5cfc81 35
48302624 36
8f5cfc81
KN
37;;;
38;;; Compiler
39;;;
cb4cca12 40
b0b180d5
AW
41(define (call-once thunk)
42 (let ((entered #f))
03fa04df
AW
43 (dynamic-wind
44 (lambda ()
45 (if entered
46 (error "thunk may only be entered once: ~a" thunk))
47 (set! entered #t))
b0b180d5
AW
48 thunk
49 (lambda () #t))))
50
b9e67767 51;; (put 'call-with-output-file/atomic 'scheme-indent-function 1)
535fb833 52(define* (call-with-output-file/atomic filename proc #:optional reference)
e6d4e05c
AW
53 (let* ((template (string-append filename ".XXXXXX"))
54 (tmp (mkstemp! template)))
b0b180d5 55 (call-once
03fa04df 56 (lambda ()
b0b180d5
AW
57 (with-throw-handler #t
58 (lambda ()
98922879 59 (proc tmp)
a56db0f6 60 (chmod tmp (logand #o0666 (lognot (umask))))
5a0df7be 61 (close-port tmp)
b0b180d5
AW
62 (rename-file template filename))
63 (lambda args
64 (delete-file template)))))))
e6d4e05c 65
7b107cce
AW
66(define (ensure-language x)
67 (if (language? x)
68 x
69 (lookup-language x)))
70
56dbc8a8
AW
71;; Throws an exception if `dir' is not writable. The mkdir occurs
72;; before the check, so that we avoid races (possibly due to parallel
73;; compilation).
74;;
f3130a2e 75(define (ensure-writable-dir dir)
56dbc8a8
AW
76 (catch 'system-error
77 (lambda ()
78 (mkdir dir))
79 (lambda (k subr fmt args rest)
80 (let ((errno (and (pair? rest) (car rest))))
81 (cond
82 ((eqv? errno EEXIST)
83 (let ((st (stat dir)))
84 (if (or (not (eq? (stat:type st) 'directory))
85 (not (access? dir W_OK)))
86 (error "directory not writable" dir))))
87 ((eqv? errno ENOENT)
88 (ensure-writable-dir (dirname dir))
89 (ensure-writable-dir dir))
90 (else
91 (throw k subr fmt args rest)))))))
4c9c9b9b 92
5ea401bf
AW
93;;; This function is among the trickiest I've ever written. I tried many
94;;; variants. In the end, simple is best, of course.
95;;;
96;;; After turning this around a number of times, it seems that the the
97;;; desired behavior is that .go files should exist in a path, for
98;;; searching. That is orthogonal to this function. For writing .go
3c997c4b
AW
99;;; files, either you know where they should go, in which case you tell
100;;; compile-file explicitly, as in the srcdir != builddir case; or you
101;;; don't know, in which case this function is called, and we just put
102;;; them in your own ccache dir in ~/.guile-ccache.
04af4c4c
AW
103;;;
104;;; See also boot-9.scm:load.
f3130a2e 105(define (compiled-file-name file)
5ea401bf
AW
106 (define (compiled-extension)
107 (cond ((or (null? %load-compiled-extensions)
108 (string-null? (car %load-compiled-extensions)))
109 (warn "invalid %load-compiled-extensions"
110 %load-compiled-extensions)
111 ".go")
112 (else (car %load-compiled-extensions))))
113 (and %compile-fallback-path
3c997c4b 114 (let ((f (string-append
179fe336
AW
115 %compile-fallback-path
116 ;; no need for '/' separator here, canonicalize-path
117 ;; will give us an absolute path
118 (canonicalize-path file)
25b82b34 119 (compiled-extension))))
5ea401bf
AW
120 (and (false-if-exception (ensure-writable-dir (dirname f)))
121 f))))
f3130a2e 122
b8076ec6
AW
123(define* (compile-file file #:key
124 (output-file #f)
b8076ec6
AW
125 (from (current-language))
126 (to 'objcode)
f95f82f8 127 (env (default-environment from))
b9e67767
AW
128 (opts '())
129 (canonicalization 'relative))
130 (with-fluids ((%file-port-name-canonicalization canonicalization))
2183d66e 131 (let* ((comp (or output-file (compiled-file-name file)
6f06e8d3 132 (error "failed to create path for auto-compiled file"
2183d66e 133 file)))
b9e67767
AW
134 (in (open-input-file file))
135 (enc (file-encoding in)))
eda06220
LC
136 ;; Choose the input encoding deterministically.
137 (set-port-encoding! in (or enc "UTF-8"))
138
b9e67767
AW
139 (ensure-writable-dir (dirname comp))
140 (call-with-output-file/atomic comp
141 (lambda (port)
142 ((language-printer (ensure-language to))
143 (read-and-compile in #:env env #:from from #:to to #:opts opts)
144 port))
145 file)
146 comp)))
8f5cfc81 147
f95f82f8 148(define* (compile-and-load file #:key (from 'scheme) (to 'value)
b9e67767
AW
149 (env (current-module)) (opts '())
150 (canonicalization 'relative))
151 (with-fluids ((%file-port-name-canonicalization canonicalization))
152 (read-and-compile (open-input-file file)
153 #:from from #:to to #:opts opts
154 #:env env)))
8f5cfc81 155
8f5cfc81
KN
156\f
157;;;
b0b180d5 158;;; Compiler interface
8f5cfc81
KN
159;;;
160
b0b180d5 161(define (compile-passes from to opts)
5d6fb8bb
AW
162 (map cdr
163 (or (lookup-compilation-order from to)
164 (error "no way to compile" from "to" to))))
8f5cfc81 165
b0b180d5 166(define (compile-fold passes exp env opts)
b8076ec6
AW
167 (let lp ((passes passes) (x exp) (e env) (cenv env) (first? #t))
168 (if (null? passes)
169 (values x e cenv)
170 (receive (x e new-cenv) ((car passes) x e opts)
171 (lp (cdr passes) x e (if first? new-cenv cenv) #f)))))
8f5cfc81 172
b8076ec6
AW
173(define (find-language-joint from to)
174 (let lp ((in (reverse (or (lookup-compilation-order from to)
175 (error "no way to compile" from "to" to))))
176 (lang to))
177 (cond ((null? in)
178 (error "don't know how to join expressions" from to))
179 ((language-joiner lang) lang)
180 (else
181 (lp (cdr in) (caar in))))))
182
183(define* (read-and-compile port #:key
b8076ec6
AW
184 (from (current-language))
185 (to 'objcode)
f95f82f8 186 (env (default-environment from))
b8076ec6
AW
187 (opts '()))
188 (let ((from (ensure-language from))
189 (to (ensure-language to)))
190 (let ((joint (find-language-joint from to)))
40867c97
AW
191 (with-fluids ((*current-language* from))
192 (let lp ((exps '()) (env #f) (cenv env))
193 (let ((x ((language-reader (current-language)) port cenv)))
b8076ec6
AW
194 (cond
195 ((eof-object? x)
196 (compile ((language-joiner joint) (reverse exps) env)
f95f82f8
AW
197 #:from joint #:to to
198 ;; env can be false if no expressions were read.
199 #:env (or env (default-environment joint))
200 #:opts opts))
b8076ec6
AW
201 (else
202 ;; compile-fold instead of compile so we get the env too
203 (receive (jexp jenv jcenv)
204 (compile-fold (compile-passes (current-language) joint opts)
205 x cenv opts)
206 (lp (cons jexp exps) jenv jcenv))))))))))
207
b0b180d5 208(define* (compile x #:key
b0b180d5 209 (from (current-language))
7b107cce 210 (to 'value)
f95f82f8 211 (env (default-environment from))
b0b180d5 212 (opts '()))
2e4c3227
LC
213
214 (let ((warnings (memq #:warnings opts)))
215 (if (pair? warnings)
216 (let ((warnings (cadr warnings)))
217 ;; Sanity-check the requested warnings.
218 (for-each (lambda (w)
219 (or (lookup-warning-type w)
220 (warning 'unsupported-warning #f w)))
221 warnings))))
222
b8076ec6 223 (receive (exp env cenv)
40867c97 224 (compile-fold (compile-passes from to opts) x env opts)
b8076ec6 225 exp))
7b107cce
AW
226
227\f
228;;;
229;;; Decompiler interface
230;;;
231
232(define (decompile-passes from to opts)
233 (map cdr
234 (or (lookup-decompilation-order from to)
235 (error "no way to decompile" from "to" to))))
236
d7236899
AW
237(define (decompile-fold passes exp env opts)
238 (if (null? passes)
239 (values exp env)
240 (receive (exp env) ((car passes) exp env opts)
241 (decompile-fold (cdr passes) exp env opts))))
242
7b107cce
AW
243(define* (decompile x #:key
244 (env #f)
245 (from 'value)
246 (to 'assembly)
247 (opts '()))
d7236899
AW
248 (decompile-fold (decompile-passes from to opts)
249 x
250 env
251 opts))