* boot-9.scm (app, %app): Renamed former to the latter.
[bpt/guile.git] / ice-9 / syncase.scm
CommitLineData
7906d57d 1;;;; Copyright (C) 1997, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
a63812a2 2;;;;
73be1d9e
MV
3;;;; This library is free software; you can redistribute it and/or
4;;;; modify it under the terms of the GNU Lesser General Public
5;;;; License as published by the Free Software Foundation; either
6;;;; version 2.1 of the License, or (at your option) any later version.
a63812a2 7;;;;
73be1d9e 8;;;; This library is distributed in the hope that it will be useful,
a63812a2 9;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11;;;; Lesser General Public License for more details.
a63812a2 12;;;;
73be1d9e
MV
13;;;; You should have received a copy of the GNU Lesser General Public
14;;;; License along with this library; if not, write to the Free Software
15;;;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
a63812a2
JB
16;;;;
17\f
18
19(define-module (ice-9 syncase)
1a179b03 20 :use-module (ice-9 debug)
5f1bde67 21 :use-module (ice-9 threads)
719fb3f3
MV
22 :export-syntax (sc-macro define-syntax define-syntax-public
23 eval-when fluid-let-syntax
1a179b03
MD
24 identifier-syntax let-syntax
25 letrec-syntax syntax syntax-case syntax-rules
26 with-syntax
27 include)
28 :export (sc-expand sc-expand3 install-global-transformer
29 syntax-dispatch syntax-error bound-identifier=?
30 datum->syntax-object free-identifier=?
31 generate-temporaries identifier? syntax-object->datum
d57da08b
MD
32 void syncase)
33 :replace (eval))
a63812a2
JB
34
35\f
36
db3f1c7e
MV
37(define expansion-eval-closure (make-fluid))
38
39(define (env->eval-closure env)
40 (or (and env
41 (car (last-pair env)))
42 (module-eval-closure the-root-module)))
43
1a179b03 44(define sc-macro
a63812a2
JB
45 (procedure->memoizing-macro
46 (lambda (exp env)
db3f1c7e
MV
47 (with-fluids ((expansion-eval-closure (env->eval-closure env)))
48 (sc-expand exp)))))
49
a63812a2
JB
50;;; Exported variables
51
1a179b03
MD
52(define sc-expand #f)
53(define sc-expand3 #f)
80f225df 54(define sc-chi #f)
1a179b03
MD
55(define install-global-transformer #f)
56(define syntax-dispatch #f)
57(define syntax-error #f)
58
59(define bound-identifier=? #f)
60(define datum->syntax-object #f)
1a179b03
MD
61(define free-identifier=? #f)
62(define generate-temporaries #f)
63(define identifier? #f)
1a179b03 64(define syntax-object->datum #f)
c55bcb32 65
a63812a2 66(define primitive-syntax '(quote lambda letrec if set! begin define or
719fb3f3
MV
67 and let let* cond do quasiquote unquote
68 unquote-splicing case))
a63812a2
JB
69
70(for-each (lambda (symbol)
71 (set-symbol-property! symbol 'primitive-syntax #t))
72 primitive-syntax)
73
74;;; Hooks needed by the syntax-case macro package
75
1a179b03 76(define (void) *unspecified*)
a63812a2
JB
77
78(define andmap
79 (lambda (f first . rest)
80 (or (null? first)
81 (if (null? rest)
82 (let andmap ((first first))
83 (let ((x (car first)) (first (cdr first)))
84 (if (null? first)
85 (f x)
86 (and (f x) (andmap first)))))
87 (let andmap ((first first) (rest rest))
88 (let ((x (car first))
89 (xr (map car rest))
90 (first (cdr first))
91 (rest (map cdr rest)))
92 (if (null? first)
93 (apply f (cons x xr))
94 (and (apply f (cons x xr)) (andmap first rest)))))))))
95
96(define (error who format-string why what)
97 (start-stack 'syncase-stack
98 (scm-error 'misc-error
99 who
8641dd9e 100 "~A ~S"
a63812a2
JB
101 (list why what)
102 '())))
103
104(define the-syncase-module (current-module))
db3f1c7e 105(define the-syncase-eval-closure (module-eval-closure the-syncase-module))
a63812a2 106
7906d57d
MD
107(fluid-set! expansion-eval-closure the-syncase-eval-closure)
108
a63812a2 109(define (putprop symbol key binding)
80f225df
MD
110 (let* ((eval-closure (fluid-ref expansion-eval-closure))
111 ;; Why not simply do (eval-closure symbol #t)?
112 ;; Answer: That would overwrite imported bindings
113 (v (or (eval-closure symbol #f) ;lookup
114 (eval-closure symbol #t) ;create it locally
115 )))
116 ;; Don't destroy Guile macros corresponding to
117 ;; primitive syntax when syncase boots.
118 (if (not (and (symbol-property symbol 'primitive-syntax)
119 (eq? eval-closure the-syncase-eval-closure)))
a63812a2 120 (variable-set! v sc-macro))
80f225df 121 ;; Properties are tied to variable objects
a63812a2
JB
122 (set-object-property! v key binding)))
123
124(define (getprop symbol key)
db3f1c7e 125 (let* ((v ((fluid-ref expansion-eval-closure) symbol #f)))
80f225df
MD
126 (and v
127 (or (object-property v key)
128 (and (variable-bound? v)
129 (macro? (variable-ref v))
130 (macro-transformer (variable-ref v)) ;non-primitive
131 guile-macro)))))
132
133(define guile-macro
134 (cons 'external-macro
135 (lambda (e r w s)
e963ac2c
MD
136 (let ((e (syntax-object->datum e)))
137 (if (symbol? e)
138 ;; pass the expression through
139 e
140 (let* ((eval-closure (fluid-ref expansion-eval-closure))
141 (m (variable-ref (eval-closure (car e) #f))))
142 (if (eq? (macro-type m) 'syntax)
143 ;; pass the expression through
144 e
145 ;; perform Guile macro transform
146 (let ((e ((macro-transformer m)
147 e
148 (append r (list eval-closure)))))
149 (if (null? r)
150 (sc-expand e)
151 (sc-chi e r w))))))))))
a63812a2
JB
152
153(define generated-symbols (make-weak-key-hash-table 1019))
154
51a317b3
RB
155;; We define our own gensym here because the Guile built-in one will
156;; eventually produce uninterned and unreadable symbols (as needed for
157;; safe macro expansions) and will the be inappropriate for dumping to
158;; pssyntax.pp.
159;;
160;; syncase is supposed to only require that gensym produce unique
161;; readable symbols, and they only need be unique with respect to
162;; multiple calls to gensym, not globally unique.
163;;
164(define gensym
165 (let ((counter 0))
56fd1933
RB
166
167 (define next-id
168 (if (provided? 'threads)
169 (let ((symlock (make-mutex)))
170 (lambda ()
171 (let ((result #f))
172 (with-mutex symlock
173 (set! result counter)
174 (set! counter (+ counter 1)))
175 result)))
176 ;; faster, non-threaded case.
177 (lambda ()
178 (let ((result counter))
179 (set! counter (+ counter 1))
180 result))))
181
182 ;; actual gensym body code.
51a317b3 183 (lambda (. rest)
56fd1933
RB
184 (let* ((next-val (next-id))
185 (valstr (number->string next-val)))
186 (cond
187 ((null? rest)
188 (string->symbol (string-append "syntmp-" valstr)))
189 ((null? (cdr rest))
190 (string->symbol (string-append "syntmp-" (car rest) "-" valstr)))
191 (else
192 (error
193 (string-append
194 "syncase's gensym expected 0 or 1 arguments, got "
195 (length rest)))))))))
51a317b3 196
a63812a2
JB
197;;; Load the preprocessed code
198
199(let ((old-debug #f)
200 (old-read #f))
201 (dynamic-wind (lambda ()
202 (set! old-debug (debug-options))
203 (set! old-read (read-options)))
204 (lambda ()
205 (debug-disable 'debug 'procnames)
206 (read-disable 'positions)
207 (load-from-path "ice-9/psyntax.pp"))
208 (lambda ()
209 (debug-options old-debug)
210 (read-options old-read))))
211
212
4be092bc
MD
213;;; The following lines are necessary only if we start making changes
214;; (use-syntax sc-expand)
a63812a2
JB
215;; (load-from-path "ice-9/psyntax.ss")
216
ac5d303b 217(define internal-eval (nested-ref the-scm-module '(%app modules guile eval)))
a63812a2 218
1a179b03 219(define (eval x environment)
a63812a2 220 (internal-eval (if (and (pair? x)
f304437e 221 (equal? (car x) "noexpand"))
a63812a2 222 (cadr x)
6232c3dd
MD
223 (sc-expand x))
224 environment))
a63812a2
JB
225
226;;; Hack to make syncase macros work in the slib module
ac5d303b 227(let ((m (nested-ref the-root-module '(%app modules ice-9 slib))))
a63812a2
JB
228 (if m
229 (set-object-property! (module-local-variable m 'define)
230 '*sc-expander*
231 '(define))))
232
cf743aea
MD
233(define (syncase exp)
234 (with-fluids ((expansion-eval-closure
235 (module-eval-closure (current-module))))
236 (sc-expand exp)))
719fb3f3
MV
237
238(set-module-transformer! the-syncase-module syncase)
239
240(define-syntax define-syntax-public
241 (syntax-rules ()
242 ((_ name rules ...)
243 (begin
244 ;(eval-case ((load-toplevel) (export-syntax name)))
245 (define-syntax name rules ...)))))
7906d57d
MD
246
247(fluid-set! expansion-eval-closure (env->eval-closure #f))