(scm_string_for_each_index): Correction to docstring.
[bpt/guile.git] / libguile / environments.c
CommitLineData
c35738c1 1/* Copyright (C) 1999,2000,2001, 2003 Free Software Foundation, Inc.
5d3e2388 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.
5d3e2388 7 *
73be1d9e 8 * This library is distributed in the hope that it will be useful,
5d3e2388 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.
5d3e2388 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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
5d3e2388
DH
17
18\f
19
20#include "libguile/_scm.h"
21#include "libguile/alist.h"
22#include "libguile/eval.h"
23#include "libguile/gh.h"
24#include "libguile/hash.h"
35060ae9 25#include "libguile/list.h"
5d3e2388
DH
26#include "libguile/ports.h"
27#include "libguile/smob.h"
28#include "libguile/symbols.h"
29#include "libguile/vectors.h"
30#include "libguile/weaks.h"
31
32#include "libguile/environments.h"
33
34\f
35
92c2555f
MV
36scm_t_bits scm_tc16_environment;
37scm_t_bits scm_tc16_observer;
231a4ea8 38#define DEFAULT_OBARRAY_SIZE 31
5d3e2388 39
de42a0ee
DH
40SCM scm_system_environment;
41
5d3e2388
DH
42\f
43
44/* error conditions */
45
46/*
47 * Throw an error if symbol is not bound in environment func
48 */
49void
50scm_error_environment_unbound (const char *func, SCM env, SCM symbol)
51{
52 /* Dirk:FIXME:: Should throw an environment:unbound type error */
53 char error[] = "Symbol `~A' not bound in environment `~A'.";
54 SCM arguments = scm_cons2 (symbol, env, SCM_EOL);
55 scm_misc_error (func, error, arguments);
56}
57
58
59/*
60 * Throw an error if func tried to create (define) or remove
61 * (undefine) a new binding for symbol in env
62 */
63void
64scm_error_environment_immutable_binding (const char *func, SCM env, SCM symbol)
65{
66 /* Dirk:FIXME:: Should throw an environment:immutable-binding type error */
67 char error[] = "Immutable binding in environment ~A (symbol: `~A').";
68 SCM arguments = scm_cons2 (env, symbol, SCM_EOL);
69 scm_misc_error (func, error, arguments);
70}
71
72
73/*
74 * Throw an error if func tried to change an immutable location.
75 */
76void
77scm_error_environment_immutable_location (const char *func, SCM env, SCM symbol)
78{
79 /* Dirk:FIXME:: Should throw an environment:immutable-location type error */
80 char error[] = "Immutable location in environment `~A' (symbol: `~A').";
81 SCM arguments = scm_cons2 (env, symbol, SCM_EOL);
82 scm_misc_error (func, error, arguments);
83}
84
85\f
86
87/* generic environments */
88
89
90/* Create an environment for the given type. Dereferencing type twice must
91 * deliver the initialized set of environment functions. Thus, type will
92 * also determine the signature of the underlying environment implementation.
93 * Dereferencing type once will typically deliver the data fields used by the
94 * underlying environment implementation.
95 */
96SCM
97scm_make_environment (void *type)
98{
228a24ef 99 return scm_cell (scm_tc16_environment, (scm_t_bits) type);
5d3e2388
DH
100}
101
102
103SCM_DEFINE (scm_environment_p, "environment?", 1, 0, 0,
104 (SCM obj),
0fb104ed
MG
105 "Return @code{#t} if @var{obj} is an environment, or @code{#f}\n"
106 "otherwise.")
5d3e2388
DH
107#define FUNC_NAME s_scm_environment_p
108{
7888309b 109 return scm_from_bool (SCM_ENVIRONMENT_P (obj));
5d3e2388
DH
110}
111#undef FUNC_NAME
112
113
114SCM_DEFINE (scm_environment_bound_p, "environment-bound?", 2, 0, 0,
115 (SCM env, SCM sym),
0fb104ed
MG
116 "Return @code{#t} if @var{sym} is bound in @var{env}, or\n"
117 "@code{#f} otherwise.")
5d3e2388
DH
118#define FUNC_NAME s_scm_environment_bound_p
119{
120 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
cc95e00a 121 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, FUNC_NAME);
5d3e2388 122
7888309b 123 return scm_from_bool (SCM_ENVIRONMENT_BOUND_P (env, sym));
5d3e2388
DH
124}
125#undef FUNC_NAME
126
127
128SCM_DEFINE (scm_environment_ref, "environment-ref", 2, 0, 0,
129 (SCM env, SCM sym),
0fb104ed
MG
130 "Return the value of the location bound to @var{sym} in\n"
131 "@var{env}. If @var{sym} is unbound in @var{env}, signal an\n"
132 "@code{environment:unbound} error.")
5d3e2388
DH
133#define FUNC_NAME s_scm_environment_ref
134{
135 SCM val;
136
137 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
cc95e00a 138 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, FUNC_NAME);
5d3e2388
DH
139
140 val = SCM_ENVIRONMENT_REF (env, sym);
141
142 if (!SCM_UNBNDP (val))
143 return val;
144 else
145 scm_error_environment_unbound (FUNC_NAME, env, sym);
146}
147#undef FUNC_NAME
148
149
150/* This C function is identical to environment-ref, except that if symbol is
151 * unbound in env, it returns the value SCM_UNDEFINED, instead of signalling
152 * an error.
153 */
154SCM
155scm_c_environment_ref (SCM env, SCM sym)
156{
157 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, "scm_c_environment_ref");
cc95e00a 158 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, "scm_c_environment_ref");
5d3e2388
DH
159 return SCM_ENVIRONMENT_REF (env, sym);
160}
161
162
163static SCM
164environment_default_folder (SCM proc, SCM symbol, SCM value, SCM tail)
165{
9b26d381 166 return scm_call_3 (proc, symbol, value, tail);
5d3e2388
DH
167}
168
169
170SCM_DEFINE (scm_environment_fold, "environment-fold", 3, 0, 0,
171 (SCM env, SCM proc, SCM init),
0fb104ed
MG
172 "Iterate over all the bindings in @var{env}, accumulating some\n"
173 "value.\n"
174 "For each binding in @var{env}, apply @var{proc} to the symbol\n"
175 "bound, its value, and the result from the previous application\n"
176 "of @var{proc}.\n"
177 "Use @var{init} as @var{proc}'s third argument the first time\n"
178 "@var{proc} is applied.\n"
179 "If @var{env} contains no bindings, this function simply returns\n"
180 "@var{init}.\n"
181 "If @var{env} binds the symbol sym1 to the value val1, sym2 to\n"
182 "val2, and so on, then this procedure computes:\n"
1e6808ea 183 "@lisp\n"
5d3e2388
DH
184 " (proc sym1 val1\n"
185 " (proc sym2 val2\n"
186 " ...\n"
187 " (proc symn valn\n"
188 " init)))\n"
1e6808ea 189 "@end lisp\n"
0fb104ed
MG
190 "Each binding in @var{env} will be processed exactly once.\n"
191 "@code{environment-fold} makes no guarantees about the order in\n"
192 "which the bindings are processed.\n"
5d3e2388
DH
193 "Here is a function which, given an environment, constructs an\n"
194 "association list representing that environment's bindings,\n"
195 "using environment-fold:\n"
1e6808ea 196 "@lisp\n"
5d3e2388
DH
197 " (define (environment->alist env)\n"
198 " (environment-fold env\n"
199 " (lambda (sym val tail)\n"
200 " (cons (cons sym val) tail))\n"
0fb104ed 201 " '()))\n"
1e6808ea 202 "@end lisp")
5d3e2388
DH
203#define FUNC_NAME s_scm_environment_fold
204{
205 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
bc36d050 206 SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
5d3e2388
DH
207 proc, SCM_ARG2, FUNC_NAME);
208
209 return SCM_ENVIRONMENT_FOLD (env, environment_default_folder, proc, init);
210}
211#undef FUNC_NAME
212
213
214/* This is the C-level analog of environment-fold. For each binding in ENV,
215 * make the call:
216 * (*proc) (data, symbol, value, previous)
217 * where previous is the value returned from the last call to *PROC, or INIT
218 * for the first call. If ENV contains no bindings, return INIT.
219 */
220SCM
221scm_c_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
222{
223 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, "scm_c_environment_fold");
224
225 return SCM_ENVIRONMENT_FOLD (env, proc, data, init);
226}
227
228
229SCM_DEFINE (scm_environment_define, "environment-define", 3, 0, 0,
230 (SCM env, SCM sym, SCM val),
0fb104ed
MG
231 "Bind @var{sym} to a new location containing @var{val} in\n"
232 "@var{env}. If @var{sym} is already bound to another location\n"
233 "in @var{env} and the binding is mutable, that binding is\n"
234 "replaced. The new binding and location are both mutable. The\n"
235 "return value is unspecified.\n"
236 "If @var{sym} is already bound in @var{env}, and the binding is\n"
237 "immutable, signal an @code{environment:immutable-binding} error.")
5d3e2388
DH
238#define FUNC_NAME s_scm_environment_define
239{
240 SCM status;
241
242 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
cc95e00a 243 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, FUNC_NAME);
5d3e2388
DH
244
245 status = SCM_ENVIRONMENT_DEFINE (env, sym, val);
246
bc36d050 247 if (scm_is_eq (status, SCM_ENVIRONMENT_SUCCESS))
5d3e2388 248 return SCM_UNSPECIFIED;
bc36d050 249 else if (scm_is_eq (status, SCM_ENVIRONMENT_BINDING_IMMUTABLE))
5d3e2388
DH
250 scm_error_environment_immutable_binding (FUNC_NAME, env, sym);
251 else
252 abort();
253}
254#undef FUNC_NAME
255
256
257SCM_DEFINE (scm_environment_undefine, "environment-undefine", 2, 0, 0,
258 (SCM env, SCM sym),
0fb104ed
MG
259 "Remove any binding for @var{sym} from @var{env}. If @var{sym}\n"
260 "is unbound in @var{env}, do nothing. The return value is\n"
261 "unspecified.\n"
262 "If @var{sym} is already bound in @var{env}, and the binding is\n"
263 "immutable, signal an @code{environment:immutable-binding} error.")
5d3e2388
DH
264#define FUNC_NAME s_scm_environment_undefine
265{
266 SCM status;
267
268 SCM_ASSERT(SCM_ENVIRONMENT_P(env), env, SCM_ARG1, FUNC_NAME);
cc95e00a 269 SCM_ASSERT(scm_is_symbol(sym), sym, SCM_ARG2, FUNC_NAME);
5d3e2388
DH
270
271 status = SCM_ENVIRONMENT_UNDEFINE (env, sym);
272
bc36d050 273 if (scm_is_eq (status, SCM_ENVIRONMENT_SUCCESS))
5d3e2388 274 return SCM_UNSPECIFIED;
bc36d050 275 else if (scm_is_eq (status, SCM_ENVIRONMENT_BINDING_IMMUTABLE))
5d3e2388
DH
276 scm_error_environment_immutable_binding (FUNC_NAME, env, sym);
277 else
278 abort();
279}
280#undef FUNC_NAME
281
282
283SCM_DEFINE (scm_environment_set_x, "environment-set!", 3, 0, 0,
284 (SCM env, SCM sym, SCM val),
0fb104ed
MG
285 "If @var{env} binds @var{sym} to some location, change that\n"
286 "location's value to @var{val}. The return value is\n"
287 "unspecified.\n"
288 "If @var{sym} is not bound in @var{env}, signal an\n"
289 "@code{environment:unbound} error. If @var{env} binds @var{sym}\n"
290 "to an immutable location, signal an\n"
291 "@code{environment:immutable-location} error.")
5d3e2388
DH
292#define FUNC_NAME s_scm_environment_set_x
293{
294 SCM status;
295
296 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
cc95e00a 297 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, FUNC_NAME);
5d3e2388
DH
298
299 status = SCM_ENVIRONMENT_SET (env, sym, val);
300
bc36d050 301 if (scm_is_eq (status, SCM_ENVIRONMENT_SUCCESS))
5d3e2388
DH
302 return SCM_UNSPECIFIED;
303 else if (SCM_UNBNDP (status))
304 scm_error_environment_unbound (FUNC_NAME, env, sym);
bc36d050 305 else if (scm_is_eq (status, SCM_ENVIRONMENT_LOCATION_IMMUTABLE))
5d3e2388
DH
306 scm_error_environment_immutable_binding (FUNC_NAME, env, sym);
307 else
308 abort();
309}
310#undef FUNC_NAME
311
312
313SCM_DEFINE (scm_environment_cell, "environment-cell", 3, 0, 0,
314 (SCM env, SCM sym, SCM for_write),
0fb104ed
MG
315 "Return the value cell which @var{env} binds to @var{sym}, or\n"
316 "@code{#f} if the binding does not live in a value cell.\n"
317 "The argument @var{for-write} indicates whether the caller\n"
318 "intends to modify the variable's value by mutating the value\n"
319 "cell. If the variable is immutable, then\n"
320 "@code{environment-cell} signals an\n"
321 "@code{environment:immutable-location} error.\n"
322 "If @var{sym} is unbound in @var{env}, signal an\n"
323 "@code{environment:unbound} error.\n"
5d3e2388 324 "If you use this function, you should consider using\n"
0fb104ed
MG
325 "@code{environment-observe}, to be notified when @var{sym} gets\n"
326 "re-bound to a new value cell, or becomes undefined.")
5d3e2388
DH
327#define FUNC_NAME s_scm_environment_cell
328{
329 SCM location;
330
331 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
cc95e00a 332 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, FUNC_NAME);
7888309b 333 SCM_ASSERT (scm_is_bool (for_write), for_write, SCM_ARG3, FUNC_NAME);
5d3e2388 334
7888309b 335 location = SCM_ENVIRONMENT_CELL (env, sym, scm_is_true (for_write));
5d3e2388
DH
336 if (!SCM_IMP (location))
337 return location;
338 else if (SCM_UNBNDP (location))
339 scm_error_environment_unbound (FUNC_NAME, env, sym);
bc36d050 340 else if (scm_is_eq (location, SCM_ENVIRONMENT_LOCATION_IMMUTABLE))
5d3e2388
DH
341 scm_error_environment_immutable_location (FUNC_NAME, env, sym);
342 else /* no cell */
343 return location;
344}
345#undef FUNC_NAME
346
347
348/* This C function is identical to environment-cell, with the following
349 * exceptions: If symbol is unbound in env, it returns the value
350 * SCM_UNDEFINED, instead of signalling an error. If symbol is bound to an
351 * immutable location but the cell is requested for write, the value
352 * SCM_ENVIRONMENT_LOCATION_IMMUTABLE is returned.
353 */
354SCM
355scm_c_environment_cell(SCM env, SCM sym, int for_write)
356{
357 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, "scm_c_environment_cell");
cc95e00a 358 SCM_ASSERT (scm_is_symbol (sym), sym, SCM_ARG2, "scm_c_environment_cell");
5d3e2388
DH
359
360 return SCM_ENVIRONMENT_CELL (env, sym, for_write);
361}
362
363
364static void
365environment_default_observer (SCM env, SCM proc)
366{
9b26d381 367 scm_call_1 (proc, env);
5d3e2388
DH
368}
369
370
371SCM_DEFINE (scm_environment_observe, "environment-observe", 2, 0, 0,
372 (SCM env, SCM proc),
0fb104ed
MG
373 "Whenever @var{env}'s bindings change, apply @var{proc} to\n"
374 "@var{env}.\n"
5d3e2388 375 "This function returns an object, token, which you can pass to\n"
0fb104ed
MG
376 "@code{environment-unobserve} to remove @var{proc} from the set\n"
377 "of procedures observing @var{env}. The type and value of\n"
378 "token is unspecified.")
5d3e2388
DH
379#define FUNC_NAME s_scm_environment_observe
380{
381 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
382
383 return SCM_ENVIRONMENT_OBSERVE (env, environment_default_observer, proc, 0);
384}
385#undef FUNC_NAME
386
387
388SCM_DEFINE (scm_environment_observe_weak, "environment-observe-weak", 2, 0, 0,
389 (SCM env, SCM proc),
390 "This function is the same as environment-observe, except that\n"
0fb104ed
MG
391 "the reference @var{env} retains to @var{proc} is a weak\n"
392 "reference. This means that, if there are no other live,\n"
393 "non-weak references to @var{proc}, it will be\n"
394 "garbage-collected, and dropped from @var{env}'s\n"
5d3e2388
DH
395 "list of observing procedures.")
396#define FUNC_NAME s_scm_environment_observe_weak
397{
398 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
399
400 return SCM_ENVIRONMENT_OBSERVE (env, environment_default_observer, proc, 1);
401}
402#undef FUNC_NAME
403
404
405/* This is the C-level analog of the Scheme functions environment-observe and
406 * environment-observe-weak. Whenever env's bindings change, call the
407 * function proc, passing it env and data. If weak_p is non-zero, env will
408 * retain only a weak reference to data, and if data is garbage collected, the
409 * entire observation will be dropped. This function returns a token, with
410 * the same meaning as those returned by environment-observe and
411 * environment-observe-weak.
412 */
413SCM
414scm_c_environment_observe (SCM env, scm_environment_observer proc, SCM data, int weak_p)
415#define FUNC_NAME "scm_c_environment_observe"
416{
417 SCM_ASSERT (SCM_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
418
419 return SCM_ENVIRONMENT_OBSERVE (env, proc, data, weak_p);
420}
421#undef FUNC_NAME
422
423
424SCM_DEFINE (scm_environment_unobserve, "environment-unobserve", 1, 0, 0,
425 (SCM token),
426 "Cancel the observation request which returned the value\n"
0fb104ed
MG
427 "@var{token}. The return value is unspecified.\n"
428 "If a call @code{(environment-observe env proc)} returns\n"
429 "@var{token}, then the call @code{(environment-unobserve token)}\n"
430 "will cause @var{proc} to no longer be called when @var{env}'s\n"
431 "bindings change.")
5d3e2388
DH
432#define FUNC_NAME s_scm_environment_unobserve
433{
434 SCM env;
435
436 SCM_ASSERT (SCM_OBSERVER_P (token), token, SCM_ARG1, FUNC_NAME);
437
438 env = SCM_OBSERVER_ENVIRONMENT (token);
439 SCM_ENVIRONMENT_UNOBSERVE (env, token);
440
441 return SCM_UNSPECIFIED;
442}
443#undef FUNC_NAME
444
445
446static SCM
e841c3e0 447environment_mark (SCM env)
5d3e2388
DH
448{
449 return (*(SCM_ENVIRONMENT_FUNCS (env)->mark)) (env);
450}
451
452
1be6b49c 453static size_t
e841c3e0 454environment_free (SCM env)
5d3e2388 455{
4c9419ac
MV
456 (*(SCM_ENVIRONMENT_FUNCS (env)->free)) (env);
457 return 0;
5d3e2388
DH
458}
459
460
461static int
e841c3e0 462environment_print (SCM env, SCM port, scm_print_state *pstate)
5d3e2388
DH
463{
464 return (*(SCM_ENVIRONMENT_FUNCS (env)->print)) (env, port, pstate);
465}
466
467\f
468
469/* observers */
470
471static SCM
e841c3e0 472observer_mark (SCM observer)
5d3e2388
DH
473{
474 scm_gc_mark (SCM_OBSERVER_ENVIRONMENT (observer));
475 scm_gc_mark (SCM_OBSERVER_DATA (observer));
476 return SCM_BOOL_F;
477}
478
479
5d3e2388 480static int
e81d98ec 481observer_print (SCM type, SCM port, scm_print_state *pstate SCM_UNUSED)
5d3e2388 482{
b9bd8526 483 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 484 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
485
486 scm_puts ("#<observer ", port);
18f9d343 487 scm_display (base16, port);
5d3e2388
DH
488 scm_puts (">", port);
489
490 return 1;
491}
492
493\f
494
495/* obarrays
496 *
497 * Obarrays form the basic lookup tables used to implement most of guile's
498 * built-in environment types. An obarray is implemented as a hash table with
499 * symbols as keys. The content of the data depends on the environment type.
500 */
501
502
503/*
a2d47b23
DH
504 * Enter symbol into obarray. The symbol must not already exist in obarray.
505 * The freshly generated (symbol . data) cell is returned.
5d3e2388
DH
506 */
507static SCM
508obarray_enter (SCM obarray, SCM symbol, SCM data)
509{
cc95e00a 510 size_t hash = scm_i_symbol_hash (symbol) % SCM_HASHTABLE_N_BUCKETS (obarray);
5d3e2388 511 SCM entry = scm_cons (symbol, data);
4057a3e0 512 SCM slot = scm_cons (entry, SCM_HASHTABLE_BUCKET (obarray, hash));
c35738c1 513 SCM_SET_HASHTABLE_BUCKET (obarray, hash, slot);
6fccb880 514 SCM_HASHTABLE_INCREMENT (obarray);
c35738c1
MD
515 if (SCM_HASHTABLE_N_ITEMS (obarray) > SCM_HASHTABLE_UPPER (obarray))
516 scm_i_rehash (obarray, scm_i_hash_symbol, 0, "obarray_enter");
5d3e2388
DH
517
518 return entry;
519}
520
521
a2d47b23
DH
522/*
523 * Enter symbol into obarray. An existing entry for symbol is replaced. If
524 * an entry existed, the old (symbol . data) cell is returned, #f otherwise.
525 */
526static SCM
527obarray_replace (SCM obarray, SCM symbol, SCM data)
528{
cc95e00a 529 size_t hash = scm_i_symbol_hash (symbol) % SCM_HASHTABLE_N_BUCKETS (obarray);
a2d47b23
DH
530 SCM new_entry = scm_cons (symbol, data);
531 SCM lsym;
532 SCM slot;
533
4057a3e0 534 for (lsym = SCM_HASHTABLE_BUCKET (obarray, hash);
d2e53ed6 535 !scm_is_null (lsym);
c35738c1 536 lsym = SCM_CDR (lsym))
a2d47b23
DH
537 {
538 SCM old_entry = SCM_CAR (lsym);
bc36d050 539 if (scm_is_eq (SCM_CAR (old_entry), symbol))
a2d47b23
DH
540 {
541 SCM_SETCAR (lsym, new_entry);
542 return old_entry;
543 }
544 }
545
4057a3e0 546 slot = scm_cons (new_entry, SCM_HASHTABLE_BUCKET (obarray, hash));
c35738c1 547 SCM_SET_HASHTABLE_BUCKET (obarray, hash, slot);
6fccb880 548 SCM_HASHTABLE_INCREMENT (obarray);
c35738c1
MD
549 if (SCM_HASHTABLE_N_ITEMS (obarray) > SCM_HASHTABLE_UPPER (obarray))
550 scm_i_rehash (obarray, scm_i_hash_symbol, 0, "obarray_replace");
a2d47b23
DH
551
552 return SCM_BOOL_F;
553}
554
555
5d3e2388
DH
556/*
557 * Look up symbol in obarray
558 */
559static SCM
560obarray_retrieve (SCM obarray, SCM sym)
561{
cc95e00a 562 size_t hash = scm_i_symbol_hash (sym) % SCM_HASHTABLE_N_BUCKETS (obarray);
5d3e2388
DH
563 SCM lsym;
564
4057a3e0 565 for (lsym = SCM_HASHTABLE_BUCKET (obarray, hash);
d2e53ed6 566 !scm_is_null (lsym);
c35738c1 567 lsym = SCM_CDR (lsym))
5d3e2388
DH
568 {
569 SCM entry = SCM_CAR (lsym);
bc36d050 570 if (scm_is_eq (SCM_CAR (entry), sym))
5d3e2388
DH
571 return entry;
572 }
573
574 return SCM_UNDEFINED;
575}
576
577
578/*
a2d47b23
DH
579 * Remove entry from obarray. If the symbol was found and removed, the old
580 * (symbol . data) cell is returned, #f otherwise.
5d3e2388
DH
581 */
582static SCM
583obarray_remove (SCM obarray, SCM sym)
584{
cc95e00a 585 size_t hash = scm_i_symbol_hash (sym) % SCM_HASHTABLE_N_BUCKETS (obarray);
4057a3e0 586 SCM table_entry = SCM_HASHTABLE_BUCKET (obarray, hash);
35060ae9 587 SCM handle = scm_sloppy_assq (sym, table_entry);
34d19ef6 588
d2e53ed6 589 if (scm_is_pair (handle))
34d19ef6 590 {
35060ae9 591 SCM new_table_entry = scm_delq1_x (handle, table_entry);
c35738c1
MD
592 SCM_SET_HASHTABLE_BUCKET (obarray, hash, new_table_entry);
593 SCM_HASHTABLE_DECREMENT (obarray);
5d3e2388 594 }
35060ae9
DH
595
596 return handle;
5d3e2388
DH
597}
598
599
600static void
601obarray_remove_all (SCM obarray)
602{
c35738c1 603 size_t size = SCM_HASHTABLE_N_BUCKETS (obarray);
1be6b49c 604 size_t i;
5d3e2388
DH
605
606 for (i = 0; i < size; i++)
607 {
c35738c1 608 SCM_SET_HASHTABLE_BUCKET (obarray, i, SCM_EOL);
5d3e2388 609 }
c35738c1 610 SCM_SET_HASHTABLE_N_ITEMS (obarray, 0);
5d3e2388
DH
611}
612
613\f
614
615/* core environments base
616 *
617 * This struct and the corresponding functions form a base class for guile's
618 * built-in environment types.
619 */
620
621
622struct core_environments_base {
623 struct scm_environment_funcs *funcs;
624
625 SCM observers;
626 SCM weak_observers;
627};
628
629
630#define CORE_ENVIRONMENTS_BASE(env) \
631 ((struct core_environments_base *) SCM_CELL_WORD_1 (env))
632#define CORE_ENVIRONMENT_OBSERVERS(env) \
633 (CORE_ENVIRONMENTS_BASE (env)->observers)
634#define SCM_SET_CORE_ENVIRONMENT_OBSERVERS(env, v) \
635 (CORE_ENVIRONMENT_OBSERVERS (env) = (v))
636#define CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR(env) \
637 (CORE_ENVIRONMENTS_BASE (env)->weak_observers)
638#define CORE_ENVIRONMENT_WEAK_OBSERVERS(env) \
4057a3e0 639 (scm_c_vector_ref (CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env), 0))
5d3e2388 640#define SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS(env, v) \
4057a3e0 641 (scm_c_vector_set_x (CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env), 0, (v)))
5d3e2388
DH
642
643\f
644
645static SCM
646core_environments_observe (SCM env, scm_environment_observer proc, SCM data, int weak_p)
647{
228a24ef
DH
648 SCM observer = scm_double_cell (scm_tc16_observer,
649 SCM_UNPACK (env),
650 SCM_UNPACK (data),
651 (scm_t_bits) proc);
5d3e2388
DH
652
653 if (!weak_p)
654 {
655 SCM observers = CORE_ENVIRONMENT_OBSERVERS (env);
656 SCM new_observers = scm_cons (observer, observers);
657 SCM_SET_CORE_ENVIRONMENT_OBSERVERS (env, new_observers);
658 }
659 else
660 {
661 SCM observers = CORE_ENVIRONMENT_WEAK_OBSERVERS (env);
662 SCM new_observers = scm_acons (SCM_BOOL_F, observer, observers);
663 SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS (env, new_observers);
664 }
665
666 return observer;
667}
668
669
670static void
671core_environments_unobserve (SCM env, SCM observer)
672{
673 unsigned int handling_weaks;
674 for (handling_weaks = 0; handling_weaks <= 1; ++handling_weaks)
675 {
676 SCM l = handling_weaks
677 ? CORE_ENVIRONMENT_WEAK_OBSERVERS (env)
678 : CORE_ENVIRONMENT_OBSERVERS (env);
679
d2e53ed6 680 if (!scm_is_null (l))
5d3e2388
DH
681 {
682 SCM rest = SCM_CDR (l);
683 SCM first = handling_weaks
684 ? SCM_CDAR (l)
685 : SCM_CAR (l);
686
bc36d050 687 if (scm_is_eq (first, observer))
5d3e2388
DH
688 {
689 /* Remove the first observer */
690 handling_weaks
691 ? SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS (env, rest)
692 : SCM_SET_CORE_ENVIRONMENT_OBSERVERS (env, rest);
693 return;
694 }
695
696 do {
697 SCM rest = SCM_CDR (l);
698
d2e53ed6 699 if (!scm_is_null (rest))
5d3e2388
DH
700 {
701 SCM next = handling_weaks
702 ? SCM_CDAR (l)
703 : SCM_CAR (l);
704
bc36d050 705 if (scm_is_eq (next, observer))
5d3e2388
DH
706 {
707 SCM_SETCDR (l, SCM_CDR (rest));
708 return;
709 }
710 }
711
712 l = rest;
d2e53ed6 713 } while (!scm_is_null (l));
5d3e2388
DH
714 }
715 }
716
717 /* Dirk:FIXME:: What to do now, since the observer is not found? */
718}
719
720
721static SCM
722core_environments_mark (SCM env)
723{
724 scm_gc_mark (CORE_ENVIRONMENT_OBSERVERS (env));
725 return CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env);
726}
727
728
729static void
e81d98ec 730core_environments_finalize (SCM env SCM_UNUSED)
5d3e2388
DH
731{
732}
733
734
735static void
736core_environments_preinit (struct core_environments_base *body)
737{
738 body->funcs = NULL;
739 body->observers = SCM_BOOL_F;
740 body->weak_observers = SCM_BOOL_F;
741}
742
743
744static void
745core_environments_init (struct core_environments_base *body,
746 struct scm_environment_funcs *funcs)
747{
748 body->funcs = funcs;
749 body->observers = SCM_EOL;
e11e83f3 750 body->weak_observers = scm_make_weak_value_alist_vector (scm_from_int (1));
5d3e2388
DH
751}
752
753
754/* Tell all observers to clear their caches.
755 *
756 * Environments have to be informed about changes in the following cases:
757 * - The observed env has a new binding. This must be always reported.
758 * - The observed env has dropped a binding. This must be always reported.
759 * - A binding in the observed environment has changed. This must only be
760 * reported, if there is a chance that the binding is being cached outside.
761 * However, this potential optimization is not performed currently.
762 *
763 * Errors that occur while the observers are called are accumulated and
764 * signalled as one single error message to the caller.
765 */
766
767struct update_data
768{
769 SCM observer;
770 SCM environment;
771};
772
773
774static SCM
775update_catch_body (void *ptr)
776{
777 struct update_data *data = (struct update_data *) ptr;
778 SCM observer = data->observer;
779
780 (*SCM_OBSERVER_PROC (observer))
781 (data->environment, SCM_OBSERVER_DATA (observer));
782
783 return SCM_UNDEFINED;
784}
785
786
787static SCM
788update_catch_handler (void *ptr, SCM tag, SCM args)
789{
790 struct update_data *data = (struct update_data *) ptr;
791 SCM observer = data->observer;
cc95e00a
MV
792 SCM message =
793 scm_from_locale_string ("Observer `~A' signals `~A' error: ~S");
5d3e2388 794
1afff620 795 return scm_cons (message, scm_list_3 (observer, tag, args));
5d3e2388
DH
796}
797
798
799static void
800core_environments_broadcast (SCM env)
801#define FUNC_NAME "core_environments_broadcast"
802{
803 unsigned int handling_weaks;
804 SCM errors = SCM_EOL;
805
806 for (handling_weaks = 0; handling_weaks <= 1; ++handling_weaks)
807 {
808 SCM observers = handling_weaks
809 ? CORE_ENVIRONMENT_WEAK_OBSERVERS (env)
810 : CORE_ENVIRONMENT_OBSERVERS (env);
811
d2e53ed6 812 for (; !scm_is_null (observers); observers = SCM_CDR (observers))
5d3e2388
DH
813 {
814 struct update_data data;
815 SCM observer = handling_weaks
816 ? SCM_CDAR (observers)
817 : SCM_CAR (observers);
818 SCM error;
819
820 data.observer = observer;
821 data.environment = env;
822
823 error = scm_internal_catch (SCM_BOOL_T,
824 update_catch_body, &data,
825 update_catch_handler, &data);
826
827 if (!SCM_UNBNDP (error))
828 errors = scm_cons (error, errors);
829 }
830 }
831
d2e53ed6 832 if (!scm_is_null (errors))
5d3e2388
DH
833 {
834 /* Dirk:FIXME:: As soon as scm_misc_error is fixed to handle the name
835 * parameter correctly it should not be necessary any more to also pass
836 * namestr in order to get the desired information from the error
837 * message.
838 */
839 SCM ordered_errors = scm_reverse (errors);
840 scm_misc_error
841 (FUNC_NAME,
842 "Observers of `~A' have signalled the following errors: ~S",
843 scm_cons2 (env, ordered_errors, SCM_EOL));
844 }
845}
846#undef FUNC_NAME
847
848\f
849
850/* leaf environments
851 *
852 * A leaf environment is simply a mutable set of definitions. A leaf
853 * environment supports no operations beyond the common set.
854 *
855 * Implementation: The obarray of the leaf environment holds (symbol . value)
856 * pairs. No further information is necessary, since all bindings and
857 * locations in a leaf environment are mutable.
858 */
859
860
861struct leaf_environment {
862 struct core_environments_base base;
863
864 SCM obarray;
865};
866
867
868#define LEAF_ENVIRONMENT(env) \
869 ((struct leaf_environment *) SCM_CELL_WORD_1 (env))
870
871\f
872
873static SCM
874leaf_environment_ref (SCM env, SCM sym)
875{
876 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
877 SCM binding = obarray_retrieve (obarray, sym);
878 return SCM_UNBNDP (binding) ? binding : SCM_CDR (binding);
879}
880
881
882static SCM
883leaf_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
884{
1be6b49c 885 size_t i;
5d3e2388
DH
886 SCM result = init;
887 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
888
c35738c1 889 for (i = 0; i < SCM_HASHTABLE_N_BUCKETS (obarray); i++)
5d3e2388
DH
890 {
891 SCM l;
4057a3e0 892 for (l = SCM_HASHTABLE_BUCKET (obarray, i);
d2e53ed6 893 !scm_is_null (l);
c35738c1 894 l = SCM_CDR (l))
5d3e2388
DH
895 {
896 SCM binding = SCM_CAR (l);
897 SCM symbol = SCM_CAR (binding);
898 SCM value = SCM_CDR (binding);
899 result = (*proc) (data, symbol, value, result);
900 }
901 }
902 return result;
903}
904
905
906static SCM
907leaf_environment_define (SCM env, SCM sym, SCM val)
908#define FUNC_NAME "leaf_environment_define"
909{
910 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
5d3e2388 911
a2d47b23 912 obarray_replace (obarray, sym, val);
5d3e2388
DH
913 core_environments_broadcast (env);
914
915 return SCM_ENVIRONMENT_SUCCESS;
916}
917#undef FUNC_NAME
918
919
920static SCM
921leaf_environment_undefine (SCM env, SCM sym)
922#define FUNC_NAME "leaf_environment_undefine"
923{
924 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
a2d47b23 925 SCM removed = obarray_remove (obarray, sym);
5d3e2388 926
7888309b 927 if (scm_is_true (removed))
a2d47b23 928 core_environments_broadcast (env);
5d3e2388
DH
929
930 return SCM_ENVIRONMENT_SUCCESS;
931}
932#undef FUNC_NAME
933
934
935static SCM
936leaf_environment_set_x (SCM env, SCM sym, SCM val)
937#define FUNC_NAME "leaf_environment_set_x"
938{
939 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
940 SCM binding = obarray_retrieve (obarray, sym);
941
942 if (!SCM_UNBNDP (binding))
943 {
944 SCM_SETCDR (binding, val);
945 return SCM_ENVIRONMENT_SUCCESS;
946 }
947 else
948 {
949 return SCM_UNDEFINED;
950 }
951}
952#undef FUNC_NAME
953
954
955static SCM
e81d98ec 956leaf_environment_cell (SCM env, SCM sym, int for_write SCM_UNUSED)
5d3e2388
DH
957{
958 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
959 SCM binding = obarray_retrieve (obarray, sym);
960 return binding;
961}
962
963
964static SCM
e841c3e0 965leaf_environment_mark (SCM env)
5d3e2388
DH
966{
967 scm_gc_mark (LEAF_ENVIRONMENT (env)->obarray);
968 return core_environments_mark (env);
969}
970
971
4c9419ac 972static void
e841c3e0 973leaf_environment_free (SCM env)
5d3e2388
DH
974{
975 core_environments_finalize (env);
4c9419ac
MV
976 scm_gc_free (LEAF_ENVIRONMENT (env), sizeof (struct leaf_environment),
977 "leaf environment");
5d3e2388
DH
978}
979
980
981static int
e81d98ec 982leaf_environment_print (SCM type, SCM port, scm_print_state *pstate SCM_UNUSED)
5d3e2388 983{
b9bd8526 984 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 985 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
986
987 scm_puts ("#<leaf environment ", port);
18f9d343 988 scm_display (base16, port);
5d3e2388
DH
989 scm_puts (">", port);
990
991 return 1;
992}
993
994
995static struct scm_environment_funcs leaf_environment_funcs = {
996 leaf_environment_ref,
997 leaf_environment_fold,
998 leaf_environment_define,
999 leaf_environment_undefine,
1000 leaf_environment_set_x,
1001 leaf_environment_cell,
1002 core_environments_observe,
1003 core_environments_unobserve,
e841c3e0
KN
1004 leaf_environment_mark,
1005 leaf_environment_free,
1006 leaf_environment_print
5d3e2388
DH
1007};
1008
1009
1010void *scm_type_leaf_environment = &leaf_environment_funcs;
1011
1012
1013SCM_DEFINE (scm_make_leaf_environment, "make-leaf-environment", 0, 0, 0,
1014 (),
1015 "Create a new leaf environment, containing no bindings.\n"
1016 "All bindings and locations created in the new environment\n"
1017 "will be mutable.")
1018#define FUNC_NAME s_scm_make_leaf_environment
1019{
1be6b49c 1020 size_t size = sizeof (struct leaf_environment);
4c9419ac 1021 struct leaf_environment *body = scm_gc_malloc (size, "leaf environment");
5d3e2388
DH
1022 SCM env;
1023
1024 core_environments_preinit (&body->base);
1025 body->obarray = SCM_BOOL_F;
1026
1027 env = scm_make_environment (body);
1028
1029 core_environments_init (&body->base, &leaf_environment_funcs);
00ffa0e7 1030 body->obarray = scm_c_make_hash_table (DEFAULT_OBARRAY_SIZE);
5d3e2388
DH
1031
1032 return env;
1033}
1034#undef FUNC_NAME
1035
1036
1037SCM_DEFINE (scm_leaf_environment_p, "leaf-environment?", 1, 0, 0,
1038 (SCM object),
0fb104ed
MG
1039 "Return @code{#t} if object is a leaf environment, or @code{#f}\n"
1040 "otherwise.")
5d3e2388
DH
1041#define FUNC_NAME s_scm_leaf_environment_p
1042{
7888309b 1043 return scm_from_bool (SCM_LEAF_ENVIRONMENT_P (object));
5d3e2388
DH
1044}
1045#undef FUNC_NAME
1046
1047\f
1048
1049/* eval environments
1050 *
1051 * A module's source code refers to definitions imported from other modules,
1052 * and definitions made within itself. An eval environment combines two
1053 * environments -- a local environment and an imported environment -- to
1054 * produce a new environment in which both sorts of references can be
1055 * resolved.
1056 *
1057 * Implementation: The obarray of the eval environment is used to cache
1058 * entries from the local and imported environments such that in most of the
1059 * cases only a single lookup is necessary. Since for neither the local nor
1060 * the imported environment it is known, what kind of environment they form,
1061 * the most general case is assumed. Therefore, entries in the obarray take
1062 * one of the following forms:
1063 *
1064 * 1) (<symbol> location mutability . source-env), where mutability indicates
1065 * one of the following states: IMMUTABLE if the location is known to be
1066 * immutable, MUTABLE if the location is known to be mutable, UNKNOWN if
1067 * the location has only been requested for non modifying accesses.
1068 *
1069 * 2) (symbol . source-env) if the symbol has a binding in the source-env, but
1070 * if the source-env can't provide a cell for the binding. Thus, for every
1071 * access, the source-env has to be contacted directly.
1072 */
1073
1074
1075struct eval_environment {
1076 struct core_environments_base base;
1077
1078 SCM obarray;
1079
1080 SCM imported;
1081 SCM imported_observer;
1082 SCM local;
1083 SCM local_observer;
1084};
1085
1086
1087#define EVAL_ENVIRONMENT(env) \
1088 ((struct eval_environment *) SCM_CELL_WORD_1 (env))
1089
93ccaef0
MV
1090#define IMMUTABLE SCM_I_MAKINUM (0)
1091#define MUTABLE SCM_I_MAKINUM (1)
1092#define UNKNOWN SCM_I_MAKINUM (2)
5d3e2388
DH
1093
1094#define CACHED_LOCATION(x) SCM_CAR (x)
1095#define CACHED_MUTABILITY(x) SCM_CADR (x)
1096#define SET_CACHED_MUTABILITY(x, v) SCM_SETCAR (SCM_CDR (x), (v))
1097#define CACHED_SOURCE_ENVIRONMENT(x) SCM_CDDR (x)
1098
1099\f
1100
1101/* eval_environment_lookup will report one of the following distinct results:
1102 * a) (<object> . value) if a cell could be obtained.
1103 * b) <environment> if the environment has to be contacted directly.
1104 * c) IMMUTABLE if an immutable cell was requested for write.
1105 * d) SCM_UNDEFINED if there is no binding for the symbol.
1106 */
1107static SCM
1108eval_environment_lookup (SCM env, SCM sym, int for_write)
1109{
1110 SCM obarray = EVAL_ENVIRONMENT (env)->obarray;
1111 SCM binding = obarray_retrieve (obarray, sym);
1112
1113 if (!SCM_UNBNDP (binding))
1114 {
1115 /* The obarray holds an entry for the symbol. */
1116
1117 SCM entry = SCM_CDR (binding);
1118
d2e53ed6 1119 if (scm_is_pair (entry))
5d3e2388
DH
1120 {
1121 /* The entry in the obarray is a cached location. */
1122
1123 SCM location = CACHED_LOCATION (entry);
1124 SCM mutability;
1125
1126 if (!for_write)
1127 return location;
1128
1129 mutability = CACHED_MUTABILITY (entry);
bc36d050 1130 if (scm_is_eq (mutability, MUTABLE))
5d3e2388
DH
1131 return location;
1132
bc36d050 1133 if (scm_is_eq (mutability, UNKNOWN))
5d3e2388
DH
1134 {
1135 SCM source_env = CACHED_SOURCE_ENVIRONMENT (entry);
1136 SCM location = SCM_ENVIRONMENT_CELL (source_env, sym, 1);
1137
d2e53ed6 1138 if (scm_is_pair (location))
5d3e2388
DH
1139 {
1140 SET_CACHED_MUTABILITY (entry, MUTABLE);
1141 return location;
1142 }
1143 else /* IMMUTABLE */
1144 {
1145 SET_CACHED_MUTABILITY (entry, IMMUTABLE);
1146 return IMMUTABLE;
1147 }
1148 }
1149
1150 return IMMUTABLE;
1151 }
1152 else
1153 {
1154 /* The obarray entry is an environment */
1155
1156 return entry;
1157 }
1158 }
1159 else
1160 {
1161 /* There is no entry for the symbol in the obarray. This can either
1162 * mean that there has not been a request for the symbol yet, or that
1163 * the symbol is really undefined. We are looking for the symbol in
1164 * both the local and the imported environment. If we find a binding, a
1165 * cached entry is created.
1166 */
1167
1168 struct eval_environment *body = EVAL_ENVIRONMENT (env);
1169 unsigned int handling_import;
1170
1171 for (handling_import = 0; handling_import <= 1; ++handling_import)
1172 {
1173 SCM source_env = handling_import ? body->imported : body->local;
1174 SCM location = SCM_ENVIRONMENT_CELL (source_env, sym, for_write);
1175
1176 if (!SCM_UNBNDP (location))
1177 {
d2e53ed6 1178 if (scm_is_pair (location))
5d3e2388
DH
1179 {
1180 SCM mutability = for_write ? MUTABLE : UNKNOWN;
1181 SCM entry = scm_cons2 (location, mutability, source_env);
1182 obarray_enter (obarray, sym, entry);
1183 return location;
1184 }
bc36d050 1185 else if (scm_is_eq (location, SCM_ENVIRONMENT_LOCATION_NO_CELL))
5d3e2388
DH
1186 {
1187 obarray_enter (obarray, sym, source_env);
1188 return source_env;
1189 }
1190 else
1191 {
1192 return IMMUTABLE;
1193 }
1194 }
1195 }
1196
1197 return SCM_UNDEFINED;
1198 }
1199}
1200
1201
1202static SCM
1203eval_environment_ref (SCM env, SCM sym)
1204#define FUNC_NAME "eval_environment_ref"
1205{
1206 SCM location = eval_environment_lookup (env, sym, 0);
1207
d2e53ed6 1208 if (scm_is_pair (location))
5d3e2388
DH
1209 return SCM_CDR (location);
1210 else if (!SCM_UNBNDP (location))
1211 return SCM_ENVIRONMENT_REF (location, sym);
1212 else
1213 return SCM_UNDEFINED;
1214}
1215#undef FUNC_NAME
1216
1217
1218static SCM
1219eval_environment_folder (SCM extended_data, SCM symbol, SCM value, SCM tail)
1220{
1221 SCM local = SCM_CAR (extended_data);
1222
1223 if (!SCM_ENVIRONMENT_BOUND_P (local, symbol))
1224 {
1225 SCM proc_as_nr = SCM_CADR (extended_data);
b9bd8526 1226 unsigned long int proc_as_ul = scm_to_ulong (proc_as_nr);
5d3e2388
DH
1227 scm_environment_folder proc = (scm_environment_folder) proc_as_ul;
1228 SCM data = SCM_CDDR (extended_data);
1229
1230 return (*proc) (data, symbol, value, tail);
1231 }
1232 else
1233 {
1234 return tail;
1235 }
1236}
1237
1238
1239static SCM
1240eval_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
1241{
1242 SCM local = EVAL_ENVIRONMENT (env)->local;
1243 SCM imported = EVAL_ENVIRONMENT (env)->imported;
b9bd8526 1244 SCM proc_as_nr = scm_from_ulong ((unsigned long) proc);
5d3e2388
DH
1245 SCM extended_data = scm_cons2 (local, proc_as_nr, data);
1246 SCM tmp_result = scm_c_environment_fold (imported, eval_environment_folder, extended_data, init);
1247
1248 return scm_c_environment_fold (local, proc, data, tmp_result);
1249}
1250
1251
1252static SCM
1253eval_environment_define (SCM env, SCM sym, SCM val)
1254#define FUNC_NAME "eval_environment_define"
1255{
1256 SCM local = EVAL_ENVIRONMENT (env)->local;
1257 return SCM_ENVIRONMENT_DEFINE (local, sym, val);
1258}
1259#undef FUNC_NAME
1260
1261
1262static SCM
1263eval_environment_undefine (SCM env, SCM sym)
1264#define FUNC_NAME "eval_environment_undefine"
1265{
1266 SCM local = EVAL_ENVIRONMENT (env)->local;
1267 return SCM_ENVIRONMENT_UNDEFINE (local, sym);
1268}
1269#undef FUNC_NAME
1270
1271
1272static SCM
1273eval_environment_set_x (SCM env, SCM sym, SCM val)
1274#define FUNC_NAME "eval_environment_set_x"
1275{
1276 SCM location = eval_environment_lookup (env, sym, 1);
1277
d2e53ed6 1278 if (scm_is_pair (location))
5d3e2388
DH
1279 {
1280 SCM_SETCDR (location, val);
1281 return SCM_ENVIRONMENT_SUCCESS;
1282 }
1283 else if (SCM_ENVIRONMENT_P (location))
1284 {
1285 return SCM_ENVIRONMENT_SET (location, sym, val);
1286 }
bc36d050 1287 else if (scm_is_eq (location, IMMUTABLE))
5d3e2388
DH
1288 {
1289 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
1290 }
1291 else
1292 {
1293 return SCM_UNDEFINED;
1294 }
1295}
1296#undef FUNC_NAME
1297
1298
1299static SCM
1300eval_environment_cell (SCM env, SCM sym, int for_write)
1301#define FUNC_NAME "eval_environment_cell"
1302{
1303 SCM location = eval_environment_lookup (env, sym, for_write);
1304
d2e53ed6 1305 if (scm_is_pair (location))
5d3e2388
DH
1306 return location;
1307 else if (SCM_ENVIRONMENT_P (location))
1308 return SCM_ENVIRONMENT_LOCATION_NO_CELL;
bc36d050 1309 else if (scm_is_eq (location, IMMUTABLE))
5d3e2388
DH
1310 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
1311 else
1312 return SCM_UNDEFINED;
1313}
1314#undef FUNC_NAME
1315
1316
1317static SCM
e841c3e0 1318eval_environment_mark (SCM env)
5d3e2388
DH
1319{
1320 struct eval_environment *body = EVAL_ENVIRONMENT (env);
1321
1322 scm_gc_mark (body->obarray);
1323 scm_gc_mark (body->imported);
1324 scm_gc_mark (body->imported_observer);
1325 scm_gc_mark (body->local);
1326 scm_gc_mark (body->local_observer);
1327
1328 return core_environments_mark (env);
1329}
1330
1331
4c9419ac 1332static void
e841c3e0 1333eval_environment_free (SCM env)
5d3e2388
DH
1334{
1335 core_environments_finalize (env);
4c9419ac
MV
1336 scm_gc_free (EVAL_ENVIRONMENT (env), sizeof (struct eval_environment),
1337 "eval environment");
5d3e2388
DH
1338}
1339
1340
1341static int
e81d98ec 1342eval_environment_print (SCM type, SCM port, scm_print_state *pstate SCM_UNUSED)
5d3e2388 1343{
b9bd8526 1344 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 1345 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
1346
1347 scm_puts ("#<eval environment ", port);
18f9d343 1348 scm_display (base16, port);
5d3e2388
DH
1349 scm_puts (">", port);
1350
1351 return 1;
1352}
1353
1354
1355static struct scm_environment_funcs eval_environment_funcs = {
1356 eval_environment_ref,
1357 eval_environment_fold,
1358 eval_environment_define,
1359 eval_environment_undefine,
1360 eval_environment_set_x,
1361 eval_environment_cell,
1362 core_environments_observe,
1363 core_environments_unobserve,
e841c3e0
KN
1364 eval_environment_mark,
1365 eval_environment_free,
1366 eval_environment_print
5d3e2388
DH
1367};
1368
1369
1370void *scm_type_eval_environment = &eval_environment_funcs;
1371
1372
1373static void
e81d98ec 1374eval_environment_observer (SCM caller SCM_UNUSED, SCM eval_env)
5d3e2388
DH
1375{
1376 SCM obarray = EVAL_ENVIRONMENT (eval_env)->obarray;
1377
1378 obarray_remove_all (obarray);
1379 core_environments_broadcast (eval_env);
1380}
1381
1382
1383SCM_DEFINE (scm_make_eval_environment, "make-eval-environment", 2, 0, 0,
1384 (SCM local, SCM imported),
1385 "Return a new environment object eval whose bindings are the\n"
0fb104ed
MG
1386 "union of the bindings in the environments @var{local} and\n"
1387 "@var{imported}, with bindings from @var{local} taking\n"
1388 "precedence. Definitions made in eval are placed in @var{local}.\n"
1389 "Applying @code{environment-define} or\n"
1390 "@code{environment-undefine} to eval has the same effect as\n"
1391 "applying the procedure to @var{local}.\n"
1392 "Note that eval incorporates @var{local} and @var{imported} by\n"
1393 "reference:\n"
5d3e2388 1394 "If, after creating eval, the program changes the bindings of\n"
0fb104ed
MG
1395 "@var{local} or @var{imported}, those changes will be visible\n"
1396 "in eval.\n"
5d3e2388 1397 "Since most Scheme evaluation takes place in eval environments,\n"
0fb104ed
MG
1398 "they transparently cache the bindings received from @var{local}\n"
1399 "and @var{imported}. Thus, the first time the program looks up\n"
1400 "a symbol in eval, eval may make calls to @var{local} or\n"
1401 "@var{imported} to find their bindings, but subsequent\n"
1402 "references to that symbol will be as fast as references to\n"
1403 "bindings in finite environments.\n"
1404 "In typical use, @var{local} will be a finite environment, and\n"
1405 "@var{imported} will be an import environment")
5d3e2388
DH
1406#define FUNC_NAME s_scm_make_eval_environment
1407{
1408 SCM env;
1409 struct eval_environment *body;
1410
1411 SCM_ASSERT (SCM_ENVIRONMENT_P (local), local, SCM_ARG1, FUNC_NAME);
1412 SCM_ASSERT (SCM_ENVIRONMENT_P (imported), imported, SCM_ARG2, FUNC_NAME);
1413
4c9419ac 1414 body = scm_gc_malloc (sizeof (struct eval_environment), "eval environment");
5d3e2388
DH
1415
1416 core_environments_preinit (&body->base);
1417 body->obarray = SCM_BOOL_F;
1418 body->imported = SCM_BOOL_F;
1419 body->imported_observer = SCM_BOOL_F;
1420 body->local = SCM_BOOL_F;
1421 body->local_observer = SCM_BOOL_F;
1422
1423 env = scm_make_environment (body);
1424
1425 core_environments_init (&body->base, &eval_environment_funcs);
00ffa0e7 1426 body->obarray = scm_c_make_hash_table (DEFAULT_OBARRAY_SIZE);
5d3e2388
DH
1427 body->imported = imported;
1428 body->imported_observer
1429 = SCM_ENVIRONMENT_OBSERVE (imported, eval_environment_observer, env, 1);
1430 body->local = local;
1431 body->local_observer
1432 = SCM_ENVIRONMENT_OBSERVE (local, eval_environment_observer, env, 1);
1433
1434 return env;
1435}
1436#undef FUNC_NAME
1437
1438
1439SCM_DEFINE (scm_eval_environment_p, "eval-environment?", 1, 0, 0,
1440 (SCM object),
0fb104ed
MG
1441 "Return @code{#t} if object is an eval environment, or @code{#f}\n"
1442 "otherwise.")
5d3e2388
DH
1443#define FUNC_NAME s_scm_eval_environment_p
1444{
7888309b 1445 return scm_from_bool (SCM_EVAL_ENVIRONMENT_P (object));
5d3e2388
DH
1446}
1447#undef FUNC_NAME
1448
1449
1450SCM_DEFINE (scm_eval_environment_local, "eval-environment-local", 1, 0, 0,
1451 (SCM env),
0fb104ed 1452 "Return the local environment of eval environment @var{env}.")
5d3e2388
DH
1453#define FUNC_NAME s_scm_eval_environment_local
1454{
1455 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1456
1457 return EVAL_ENVIRONMENT (env)->local;
1458}
1459#undef FUNC_NAME
1460
1461
1462SCM_DEFINE (scm_eval_environment_set_local_x, "eval-environment-set-local!", 2, 0, 0,
1463 (SCM env, SCM local),
0fb104ed 1464 "Change @var{env}'s local environment to @var{local}.")
5d3e2388
DH
1465#define FUNC_NAME s_scm_eval_environment_set_local_x
1466{
1467 struct eval_environment *body;
1468
1469 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1470 SCM_ASSERT (SCM_ENVIRONMENT_P (local), local, SCM_ARG2, FUNC_NAME);
1471
1472 body = EVAL_ENVIRONMENT (env);
1473
1474 obarray_remove_all (body->obarray);
1475 SCM_ENVIRONMENT_UNOBSERVE (body->local, body->local_observer);
1476
1477 body->local = local;
1478 body->local_observer
1479 = SCM_ENVIRONMENT_OBSERVE (local, eval_environment_observer, env, 1);
1480
1481 core_environments_broadcast (env);
1482
1483 return SCM_UNSPECIFIED;
1484}
1485#undef FUNC_NAME
1486
1487
1488SCM_DEFINE (scm_eval_environment_imported, "eval-environment-imported", 1, 0, 0,
1489 (SCM env),
0fb104ed 1490 "Return the imported environment of eval environment @var{env}.")
5d3e2388
DH
1491#define FUNC_NAME s_scm_eval_environment_imported
1492{
1493 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1494
1495 return EVAL_ENVIRONMENT (env)->imported;
1496}
1497#undef FUNC_NAME
1498
1499
1500SCM_DEFINE (scm_eval_environment_set_imported_x, "eval-environment-set-imported!", 2, 0, 0,
1501 (SCM env, SCM imported),
0fb104ed 1502 "Change @var{env}'s imported environment to @var{imported}.")
5d3e2388
DH
1503#define FUNC_NAME s_scm_eval_environment_set_imported_x
1504{
1505 struct eval_environment *body;
1506
1507 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1508 SCM_ASSERT (SCM_ENVIRONMENT_P (imported), imported, SCM_ARG2, FUNC_NAME);
1509
1510 body = EVAL_ENVIRONMENT (env);
1511
1512 obarray_remove_all (body->obarray);
1513 SCM_ENVIRONMENT_UNOBSERVE (body->imported, body->imported_observer);
1514
1515 body->imported = imported;
1516 body->imported_observer
1517 = SCM_ENVIRONMENT_OBSERVE (imported, eval_environment_observer, env, 1);
1518
1519 core_environments_broadcast (env);
1520
1521 return SCM_UNSPECIFIED;
1522}
1523#undef FUNC_NAME
1524
1525\f
1526
1527/* import environments
1528 *
1529 * An import environment combines the bindings of a set of argument
1530 * environments, and checks for naming clashes.
1531 *
1532 * Implementation: The import environment does no caching at all. For every
1533 * access, the list of imported environments is scanned.
1534 */
1535
1536
1537struct import_environment {
1538 struct core_environments_base base;
1539
1540 SCM imports;
1541 SCM import_observers;
1542
1543 SCM conflict_proc;
1544};
1545
1546
1547#define IMPORT_ENVIRONMENT(env) \
1548 ((struct import_environment *) SCM_CELL_WORD_1 (env))
1549
1550\f
1551
1552/* Lookup will report one of the following distinct results:
1553 * a) <environment> if only environment binds the symbol.
1554 * b) (env-1 env-2 ...) for conflicting bindings in env-1, ...
1555 * c) SCM_UNDEFINED if there is no binding for the symbol.
1556 */
1557static SCM
1558import_environment_lookup (SCM env, SCM sym)
1559{
1560 SCM imports = IMPORT_ENVIRONMENT (env)->imports;
1561 SCM result = SCM_UNDEFINED;
1562 SCM l;
1563
d2e53ed6 1564 for (l = imports; !scm_is_null (l); l = SCM_CDR (l))
5d3e2388
DH
1565 {
1566 SCM imported = SCM_CAR (l);
1567
1568 if (SCM_ENVIRONMENT_BOUND_P (imported, sym))
1569 {
1570 if (SCM_UNBNDP (result))
1571 result = imported;
d2e53ed6 1572 else if (scm_is_pair (result))
5d3e2388
DH
1573 result = scm_cons (imported, result);
1574 else
1575 result = scm_cons2 (imported, result, SCM_EOL);
1576 }
1577 }
1578
d2e53ed6 1579 if (scm_is_pair (result))
5d3e2388
DH
1580 return scm_reverse (result);
1581 else
1582 return result;
1583}
1584
1585
1586static SCM
1587import_environment_conflict (SCM env, SCM sym, SCM imports)
1588{
1589 SCM conflict_proc = IMPORT_ENVIRONMENT (env)->conflict_proc;
1590 SCM args = scm_cons2 (env, sym, scm_cons (imports, SCM_EOL));
1591
fdc28395 1592 return scm_apply_0 (conflict_proc, args);
5d3e2388
DH
1593}
1594
1595
1596static SCM
1597import_environment_ref (SCM env, SCM sym)
1598#define FUNC_NAME "import_environment_ref"
1599{
1600 SCM owner = import_environment_lookup (env, sym);
1601
1602 if (SCM_UNBNDP (owner))
1603 {
1604 return SCM_UNDEFINED;
1605 }
d2e53ed6 1606 else if (scm_is_pair (owner))
5d3e2388
DH
1607 {
1608 SCM resolve = import_environment_conflict (env, sym, owner);
1609
1610 if (SCM_ENVIRONMENT_P (resolve))
1611 return SCM_ENVIRONMENT_REF (resolve, sym);
1612 else
1613 return SCM_UNSPECIFIED;
1614 }
1615 else
1616 {
1617 return SCM_ENVIRONMENT_REF (owner, sym);
1618 }
1619}
1620#undef FUNC_NAME
1621
1622
1623static SCM
1624import_environment_folder (SCM extended_data, SCM symbol, SCM value, SCM tail)
1625#define FUNC_NAME "import_environment_fold"
1626{
1627 SCM import_env = SCM_CAR (extended_data);
1628 SCM imported_env = SCM_CADR (extended_data);
1629 SCM owner = import_environment_lookup (import_env, symbol);
1630 SCM proc_as_nr = SCM_CADDR (extended_data);
b9bd8526 1631 unsigned long int proc_as_ul = scm_to_ulong (proc_as_nr);
5d3e2388
DH
1632 scm_environment_folder proc = (scm_environment_folder) proc_as_ul;
1633 SCM data = SCM_CDDDR (extended_data);
1634
d2e53ed6 1635 if (scm_is_pair (owner) && scm_is_eq (SCM_CAR (owner), imported_env))
5d3e2388
DH
1636 owner = import_environment_conflict (import_env, symbol, owner);
1637
1638 if (SCM_ENVIRONMENT_P (owner))
1639 return (*proc) (data, symbol, value, tail);
1640 else /* unresolved conflict */
1641 return (*proc) (data, symbol, SCM_UNSPECIFIED, tail);
1642}
1643#undef FUNC_NAME
1644
1645
1646static SCM
1647import_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
1648{
b9bd8526 1649 SCM proc_as_nr = scm_from_ulong ((unsigned long) proc);
5d3e2388
DH
1650 SCM result = init;
1651 SCM l;
1652
d2e53ed6 1653 for (l = IMPORT_ENVIRONMENT (env)->imports; !scm_is_null (l); l = SCM_CDR (l))
5d3e2388
DH
1654 {
1655 SCM imported_env = SCM_CAR (l);
1656 SCM extended_data = scm_cons (env, scm_cons2 (imported_env, proc_as_nr, data));
1657
1658 result = scm_c_environment_fold (imported_env, import_environment_folder, extended_data, result);
1659 }
1660
1661 return result;
1662}
1663
1664
1665static SCM
e81d98ec
DH
1666import_environment_define (SCM env SCM_UNUSED,
1667 SCM sym SCM_UNUSED,
1668 SCM val SCM_UNUSED)
5d3e2388
DH
1669#define FUNC_NAME "import_environment_define"
1670{
1671 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1672}
1673#undef FUNC_NAME
1674
1675
1676static SCM
e81d98ec
DH
1677import_environment_undefine (SCM env SCM_UNUSED,
1678 SCM sym SCM_UNUSED)
5d3e2388
DH
1679#define FUNC_NAME "import_environment_undefine"
1680{
1681 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1682}
1683#undef FUNC_NAME
1684
1685
1686static SCM
1687import_environment_set_x (SCM env, SCM sym, SCM val)
1688#define FUNC_NAME "import_environment_set_x"
1689{
1690 SCM owner = import_environment_lookup (env, sym);
1691
1692 if (SCM_UNBNDP (owner))
1693 {
1694 return SCM_UNDEFINED;
1695 }
d2e53ed6 1696 else if (scm_is_pair (owner))
5d3e2388
DH
1697 {
1698 SCM resolve = import_environment_conflict (env, sym, owner);
1699
1700 if (SCM_ENVIRONMENT_P (resolve))
1701 return SCM_ENVIRONMENT_SET (resolve, sym, val);
1702 else
1703 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
1704 }
1705 else
1706 {
1707 return SCM_ENVIRONMENT_SET (owner, sym, val);
1708 }
1709}
1710#undef FUNC_NAME
1711
1712
1713static SCM
1714import_environment_cell (SCM env, SCM sym, int for_write)
1715#define FUNC_NAME "import_environment_cell"
1716{
1717 SCM owner = import_environment_lookup (env, sym);
1718
1719 if (SCM_UNBNDP (owner))
1720 {
1721 return SCM_UNDEFINED;
1722 }
d2e53ed6 1723 else if (scm_is_pair (owner))
5d3e2388
DH
1724 {
1725 SCM resolve = import_environment_conflict (env, sym, owner);
1726
1727 if (SCM_ENVIRONMENT_P (resolve))
1728 return SCM_ENVIRONMENT_CELL (resolve, sym, for_write);
1729 else
1730 return SCM_ENVIRONMENT_LOCATION_NO_CELL;
1731 }
1732 else
1733 {
1734 return SCM_ENVIRONMENT_CELL (owner, sym, for_write);
1735 }
1736}
1737#undef FUNC_NAME
1738
1739
1740static SCM
e841c3e0 1741import_environment_mark (SCM env)
5d3e2388
DH
1742{
1743 scm_gc_mark (IMPORT_ENVIRONMENT (env)->imports);
1744 scm_gc_mark (IMPORT_ENVIRONMENT (env)->import_observers);
1745 scm_gc_mark (IMPORT_ENVIRONMENT (env)->conflict_proc);
1746 return core_environments_mark (env);
1747}
1748
1749
4c9419ac 1750static void
e841c3e0 1751import_environment_free (SCM env)
5d3e2388
DH
1752{
1753 core_environments_finalize (env);
4c9419ac
MV
1754 scm_gc_free (IMPORT_ENVIRONMENT (env), sizeof (struct import_environment),
1755 "import environment");
5d3e2388
DH
1756}
1757
1758
1759static int
e81d98ec
DH
1760import_environment_print (SCM type, SCM port,
1761 scm_print_state *pstate SCM_UNUSED)
5d3e2388 1762{
b9bd8526 1763 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 1764 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
1765
1766 scm_puts ("#<import environment ", port);
18f9d343 1767 scm_display (base16, port);
5d3e2388
DH
1768 scm_puts (">", port);
1769
1770 return 1;
1771}
1772
1773
1774static struct scm_environment_funcs import_environment_funcs = {
1775 import_environment_ref,
1776 import_environment_fold,
1777 import_environment_define,
1778 import_environment_undefine,
1779 import_environment_set_x,
1780 import_environment_cell,
1781 core_environments_observe,
1782 core_environments_unobserve,
e841c3e0
KN
1783 import_environment_mark,
1784 import_environment_free,
1785 import_environment_print
5d3e2388
DH
1786};
1787
1788
1789void *scm_type_import_environment = &import_environment_funcs;
1790
1791
1792static void
e81d98ec 1793import_environment_observer (SCM caller SCM_UNUSED, SCM import_env)
5d3e2388
DH
1794{
1795 core_environments_broadcast (import_env);
1796}
1797
1798
1799SCM_DEFINE (scm_make_import_environment, "make-import-environment", 2, 0, 0,
1800 (SCM imports, SCM conflict_proc),
0fb104ed
MG
1801 "Return a new environment @var{imp} whose bindings are the union\n"
1802 "of the bindings from the environments in @var{imports};\n"
1803 "@var{imports} must be a list of environments. That is,\n"
1804 "@var{imp} binds a symbol to a location when some element of\n"
1805 "@var{imports} does.\n"
1806 "If two different elements of @var{imports} have a binding for\n"
1807 "the same symbol, the @var{conflict-proc} is called with the\n"
1808 "following parameters: the import environment, the symbol and\n"
1809 "the list of the imported environments that bind the symbol.\n"
1810 "If the @var{conflict-proc} returns an environment @var{env},\n"
1811 "the conflict is considered as resolved and the binding from\n"
1812 "@var{env} is used. If the @var{conflict-proc} returns some\n"
1813 "non-environment object, the conflict is considered unresolved\n"
1814 "and the symbol is treated as unspecified in the import\n"
1815 "environment.\n"
1816 "The checking for conflicts may be performed lazily, i. e. at\n"
5d3e2388
DH
1817 "the moment when a value or binding for a certain symbol is\n"
1818 "requested instead of the moment when the environment is\n"
1819 "created or the bindings of the imports change.\n"
0fb104ed
MG
1820 "All bindings in @var{imp} are immutable. If you apply\n"
1821 "@code{environment-define} or @code{environment-undefine} to\n"
1822 "@var{imp}, Guile will signal an\n"
1823 " @code{environment:immutable-binding} error. However,\n"
1824 "notice that the set of bindings in @var{imp} may still change,\n"
1825 "if one of its imported environments changes.")
5d3e2388
DH
1826#define FUNC_NAME s_scm_make_import_environment
1827{
1be6b49c 1828 size_t size = sizeof (struct import_environment);
4c9419ac 1829 struct import_environment *body = scm_gc_malloc (size, "import environment");
5d3e2388
DH
1830 SCM env;
1831
1832 core_environments_preinit (&body->base);
1833 body->imports = SCM_BOOL_F;
1834 body->import_observers = SCM_BOOL_F;
1835 body->conflict_proc = SCM_BOOL_F;
1836
1837 env = scm_make_environment (body);
1838
1839 core_environments_init (&body->base, &import_environment_funcs);
1840 body->imports = SCM_EOL;
1841 body->import_observers = SCM_EOL;
1842 body->conflict_proc = conflict_proc;
1843
1844 scm_import_environment_set_imports_x (env, imports);
1845
1846 return env;
1847}
1848#undef FUNC_NAME
1849
1850
1851SCM_DEFINE (scm_import_environment_p, "import-environment?", 1, 0, 0,
1852 (SCM object),
0fb104ed
MG
1853 "Return @code{#t} if object is an import environment, or\n"
1854 "@code{#f} otherwise.")
5d3e2388
DH
1855#define FUNC_NAME s_scm_import_environment_p
1856{
7888309b 1857 return scm_from_bool (SCM_IMPORT_ENVIRONMENT_P (object));
5d3e2388
DH
1858}
1859#undef FUNC_NAME
1860
1861
1862SCM_DEFINE (scm_import_environment_imports, "import-environment-imports", 1, 0, 0,
1863 (SCM env),
0fb104ed
MG
1864 "Return the list of environments imported by the import\n"
1865 "environment @var{env}.")
5d3e2388
DH
1866#define FUNC_NAME s_scm_import_environment_imports
1867{
1868 SCM_ASSERT (SCM_IMPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1869
1870 return IMPORT_ENVIRONMENT (env)->imports;
1871}
1872#undef FUNC_NAME
1873
1874
1875SCM_DEFINE (scm_import_environment_set_imports_x, "import-environment-set-imports!", 2, 0, 0,
1876 (SCM env, SCM imports),
0fb104ed
MG
1877 "Change @var{env}'s list of imported environments to\n"
1878 "@var{imports}, and check for conflicts.")
5d3e2388
DH
1879#define FUNC_NAME s_scm_import_environment_set_imports_x
1880{
1881 struct import_environment *body = IMPORT_ENVIRONMENT (env);
1882 SCM import_observers = SCM_EOL;
1883 SCM l;
1884
1885 SCM_ASSERT (SCM_IMPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
d2e53ed6 1886 for (l = imports; scm_is_pair (l); l = SCM_CDR (l))
5d3e2388
DH
1887 {
1888 SCM obj = SCM_CAR (l);
dd85ce47 1889 SCM_ASSERT (SCM_ENVIRONMENT_P (obj), imports, SCM_ARG2, FUNC_NAME);
5d3e2388 1890 }
d2e53ed6 1891 SCM_ASSERT (scm_is_null (l), imports, SCM_ARG2, FUNC_NAME);
5d3e2388 1892
d2e53ed6 1893 for (l = body->import_observers; !scm_is_null (l); l = SCM_CDR (l))
5d3e2388
DH
1894 {
1895 SCM obs = SCM_CAR (l);
1896 SCM_ENVIRONMENT_UNOBSERVE (env, obs);
1897 }
1898
d2e53ed6 1899 for (l = imports; !scm_is_null (l); l = SCM_CDR (l))
5d3e2388
DH
1900 {
1901 SCM imp = SCM_CAR (l);
1902 SCM obs = SCM_ENVIRONMENT_OBSERVE (imp, import_environment_observer, env, 1);
1903 import_observers = scm_cons (obs, import_observers);
1904 }
1905
1906 body->imports = imports;
1907 body->import_observers = import_observers;
1908
1909 return SCM_UNSPECIFIED;
1910}
1911#undef FUNC_NAME
1912
1913\f
1914
1915/* export environments
1916 *
1917 * An export environment restricts an environment to a specified set of
1918 * bindings.
1919 *
1920 * Implementation: The export environment does no caching at all. For every
1921 * access, the signature is scanned. The signature that is stored internally
1922 * is an alist of pairs (symbol . (mutability)).
1923 */
1924
1925
1926struct export_environment {
1927 struct core_environments_base base;
1928
1929 SCM private;
1930 SCM private_observer;
1931
1932 SCM signature;
1933};
1934
1935
1936#define EXPORT_ENVIRONMENT(env) \
1937 ((struct export_environment *) SCM_CELL_WORD_1 (env))
1938
1939
1940SCM_SYMBOL (symbol_immutable_location, "immutable-location");
1941SCM_SYMBOL (symbol_mutable_location, "mutable-location");
1942
1943\f
1944
1945static SCM
1946export_environment_ref (SCM env, SCM sym)
1947#define FUNC_NAME "export_environment_ref"
1948{
1949 struct export_environment *body = EXPORT_ENVIRONMENT (env);
1950 SCM entry = scm_assq (sym, body->signature);
1951
7888309b 1952 if (scm_is_false (entry))
5d3e2388
DH
1953 return SCM_UNDEFINED;
1954 else
1955 return SCM_ENVIRONMENT_REF (body->private, sym);
1956}
1957#undef FUNC_NAME
1958
1959
1960static SCM
1961export_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
1962{
1963 struct export_environment *body = EXPORT_ENVIRONMENT (env);
1964 SCM result = init;
1965 SCM l;
1966
d2e53ed6 1967 for (l = body->signature; !scm_is_null (l); l = SCM_CDR (l))
5d3e2388
DH
1968 {
1969 SCM symbol = SCM_CAR (l);
1970 SCM value = SCM_ENVIRONMENT_REF (body->private, symbol);
1971 if (!SCM_UNBNDP (value))
1972 result = (*proc) (data, symbol, value, result);
1973 }
1974 return result;
1975}
1976
1977
1978static SCM
e81d98ec
DH
1979export_environment_define (SCM env SCM_UNUSED,
1980 SCM sym SCM_UNUSED,
1981 SCM val SCM_UNUSED)
5d3e2388
DH
1982#define FUNC_NAME "export_environment_define"
1983{
1984 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1985}
1986#undef FUNC_NAME
1987
1988
1989static SCM
e81d98ec 1990export_environment_undefine (SCM env SCM_UNUSED, SCM sym SCM_UNUSED)
5d3e2388
DH
1991#define FUNC_NAME "export_environment_undefine"
1992{
1993 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1994}
1995#undef FUNC_NAME
1996
1997
1998static SCM
1999export_environment_set_x (SCM env, SCM sym, SCM val)
2000#define FUNC_NAME "export_environment_set_x"
2001{
2002 struct export_environment *body = EXPORT_ENVIRONMENT (env);
2003 SCM entry = scm_assq (sym, body->signature);
2004
7888309b 2005 if (scm_is_false (entry))
5d3e2388
DH
2006 {
2007 return SCM_UNDEFINED;
2008 }
2009 else
2010 {
bc36d050 2011 if (scm_is_eq (SCM_CADR (entry), symbol_mutable_location))
5d3e2388
DH
2012 return SCM_ENVIRONMENT_SET (body->private, sym, val);
2013 else
2014 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
2015 }
2016}
2017#undef FUNC_NAME
2018
2019
2020static SCM
2021export_environment_cell (SCM env, SCM sym, int for_write)
2022#define FUNC_NAME "export_environment_cell"
2023{
2024 struct export_environment *body = EXPORT_ENVIRONMENT (env);
2025 SCM entry = scm_assq (sym, body->signature);
2026
7888309b 2027 if (scm_is_false (entry))
5d3e2388
DH
2028 {
2029 return SCM_UNDEFINED;
2030 }
2031 else
2032 {
bc36d050 2033 if (!for_write || scm_is_eq (SCM_CADR (entry), symbol_mutable_location))
5d3e2388
DH
2034 return SCM_ENVIRONMENT_CELL (body->private, sym, for_write);
2035 else
2036 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
2037 }
2038}
2039#undef FUNC_NAME
2040
2041
2042static SCM
e841c3e0 2043export_environment_mark (SCM env)
5d3e2388
DH
2044{
2045 struct export_environment *body = EXPORT_ENVIRONMENT (env);
2046
2047 scm_gc_mark (body->private);
2048 scm_gc_mark (body->private_observer);
2049 scm_gc_mark (body->signature);
2050
2051 return core_environments_mark (env);
2052}
2053
2054
4c9419ac 2055static void
e841c3e0 2056export_environment_free (SCM env)
5d3e2388
DH
2057{
2058 core_environments_finalize (env);
4c9419ac
MV
2059 scm_gc_free (EXPORT_ENVIRONMENT (env), sizeof (struct export_environment),
2060 "export environment");
5d3e2388
DH
2061}
2062
2063
2064static int
e81d98ec
DH
2065export_environment_print (SCM type, SCM port,
2066 scm_print_state *pstate SCM_UNUSED)
5d3e2388 2067{
b9bd8526 2068 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 2069 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
2070
2071 scm_puts ("#<export environment ", port);
18f9d343 2072 scm_display (base16, port);
5d3e2388
DH
2073 scm_puts (">", port);
2074
2075 return 1;
2076}
2077
2078
2079static struct scm_environment_funcs export_environment_funcs = {
2080 export_environment_ref,
2081 export_environment_fold,
2082 export_environment_define,
2083 export_environment_undefine,
2084 export_environment_set_x,
2085 export_environment_cell,
2086 core_environments_observe,
2087 core_environments_unobserve,
e841c3e0
KN
2088 export_environment_mark,
2089 export_environment_free,
2090 export_environment_print
5d3e2388
DH
2091};
2092
2093
2094void *scm_type_export_environment = &export_environment_funcs;
2095
2096
2097static void
e81d98ec 2098export_environment_observer (SCM caller SCM_UNUSED, SCM export_env)
5d3e2388
DH
2099{
2100 core_environments_broadcast (export_env);
2101}
2102
2103
2104SCM_DEFINE (scm_make_export_environment, "make-export-environment", 2, 0, 0,
2105 (SCM private, SCM signature),
0fb104ed
MG
2106 "Return a new environment @var{exp} containing only those\n"
2107 "bindings in private whose symbols are present in\n"
2108 "@var{signature}. The @var{private} argument must be an\n"
2109 "environment.\n\n"
2110 "The environment @var{exp} binds symbol to location when\n"
2111 "@var{env} does, and symbol is exported by @var{signature}.\n\n"
2112 "@var{signature} is a list specifying which of the bindings in\n"
2113 "@var{private} should be visible in @var{exp}. Each element of\n"
2114 "@var{signature} should be a list of the form:\n"
5d3e2388
DH
2115 " (symbol attribute ...)\n"
2116 "where each attribute is one of the following:\n"
0fb104ed
MG
2117 "@table @asis\n"
2118 "@item the symbol @code{mutable-location}\n"
2119 " @var{exp} should treat the\n"
2120 " location bound to symbol as mutable. That is, @var{exp}\n"
2121 " will pass calls to @code{environment-set!} or\n"
2122 " @code{environment-cell} directly through to private.\n"
2123 "@item the symbol @code{immutable-location}\n"
2124 " @var{exp} should treat\n"
2125 " the location bound to symbol as immutable. If the program\n"
2126 " applies @code{environment-set!} to @var{exp} and symbol, or\n"
2127 " calls @code{environment-cell} to obtain a writable value\n"
2128 " cell, @code{environment-set!} will signal an\n"
2129 " @code{environment:immutable-location} error. Note that, even\n"
2130 " if an export environment treats a location as immutable, the\n"
5d3e2388
DH
2131 " underlying environment may treat it as mutable, so its\n"
2132 " value may change.\n"
0fb104ed 2133 "@end table\n"
5d3e2388 2134 "It is an error for an element of signature to specify both\n"
0fb104ed
MG
2135 "@code{mutable-location} and @code{immutable-location}. If\n"
2136 "neither is specified, @code{immutable-location} is assumed.\n\n"
5d3e2388 2137 "As a special case, if an element of signature is a lone\n"
0fb104ed
MG
2138 "symbol @var{sym}, it is equivalent to an element of the form\n"
2139 "@code{(sym)}.\n\n"
2140 "All bindings in @var{exp} are immutable. If you apply\n"
2141 "@code{environment-define} or @code{environment-undefine} to\n"
2142 "@var{exp}, Guile will signal an\n"
2143 "@code{environment:immutable-binding} error. However,\n"
2144 "notice that the set of bindings in @var{exp} may still change,\n"
2145 "if the bindings in private change.")
5d3e2388
DH
2146#define FUNC_NAME s_scm_make_export_environment
2147{
1be6b49c 2148 size_t size;
5d3e2388
DH
2149 struct export_environment *body;
2150 SCM env;
2151
2152 SCM_ASSERT (SCM_ENVIRONMENT_P (private), private, SCM_ARG1, FUNC_NAME);
2153
2154 size = sizeof (struct export_environment);
4c9419ac 2155 body = scm_gc_malloc (size, "export environment");
5d3e2388
DH
2156
2157 core_environments_preinit (&body->base);
2158 body->private = SCM_BOOL_F;
2159 body->private_observer = SCM_BOOL_F;
2160 body->signature = SCM_BOOL_F;
2161
2162 env = scm_make_environment (body);
2163
2164 core_environments_init (&body->base, &export_environment_funcs);
2165 body->private = private;
2166 body->private_observer
2167 = SCM_ENVIRONMENT_OBSERVE (private, export_environment_observer, env, 1);
2168 body->signature = SCM_EOL;
2169
2170 scm_export_environment_set_signature_x (env, signature);
2171
2172 return env;
2173}
2174#undef FUNC_NAME
2175
2176
2177SCM_DEFINE (scm_export_environment_p, "export-environment?", 1, 0, 0,
2178 (SCM object),
0fb104ed
MG
2179 "Return @code{#t} if object is an export environment, or\n"
2180 "@code{#f} otherwise.")
5d3e2388
DH
2181#define FUNC_NAME s_scm_export_environment_p
2182{
7888309b 2183 return scm_from_bool (SCM_EXPORT_ENVIRONMENT_P (object));
5d3e2388
DH
2184}
2185#undef FUNC_NAME
2186
2187
2188SCM_DEFINE (scm_export_environment_private, "export-environment-private", 1, 0, 0,
2189 (SCM env),
0fb104ed 2190 "Return the private environment of export environment @var{env}.")
5d3e2388
DH
2191#define FUNC_NAME s_scm_export_environment_private
2192{
2193 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2194
2195 return EXPORT_ENVIRONMENT (env)->private;
2196}
2197#undef FUNC_NAME
2198
2199
2200SCM_DEFINE (scm_export_environment_set_private_x, "export-environment-set-private!", 2, 0, 0,
2201 (SCM env, SCM private),
0fb104ed 2202 "Change the private environment of export environment @var{env}.")
5d3e2388
DH
2203#define FUNC_NAME s_scm_export_environment_set_private_x
2204{
2205 struct export_environment *body;
2206
2207 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2208 SCM_ASSERT (SCM_ENVIRONMENT_P (private), private, SCM_ARG2, FUNC_NAME);
2209
2210 body = EXPORT_ENVIRONMENT (env);
2211 SCM_ENVIRONMENT_UNOBSERVE (private, body->private_observer);
2212
2213 body->private = private;
2214 body->private_observer
2215 = SCM_ENVIRONMENT_OBSERVE (private, export_environment_observer, env, 1);
2216
2217 return SCM_UNSPECIFIED;
2218}
2219#undef FUNC_NAME
2220
2221
2222SCM_DEFINE (scm_export_environment_signature, "export-environment-signature", 1, 0, 0,
2223 (SCM env),
0fb104ed 2224 "Return the signature of export environment @var{env}.")
5d3e2388
DH
2225#define FUNC_NAME s_scm_export_environment_signature
2226{
2227 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2228
2229 return EXPORT_ENVIRONMENT (env)->signature;
2230}
2231#undef FUNC_NAME
2232
2233
2234static SCM
2235export_environment_parse_signature (SCM signature, const char* caller)
2236{
2237 SCM result = SCM_EOL;
2238 SCM l;
2239
d2e53ed6 2240 for (l = signature; scm_is_pair (l); l = SCM_CDR (l))
5d3e2388
DH
2241 {
2242 SCM entry = SCM_CAR (l);
2243
cc95e00a 2244 if (scm_is_symbol (entry))
5d3e2388
DH
2245 {
2246 SCM new_entry = scm_cons2 (entry, symbol_immutable_location, SCM_EOL);
2247 result = scm_cons (new_entry, result);
2248 }
2249 else
2250 {
2251 SCM sym;
2252 SCM new_entry;
2253 int immutable = 0;
2254 int mutable = 0;
2255 SCM mutability;
2256 SCM l2;
2257
d2e53ed6 2258 SCM_ASSERT (scm_is_pair (entry), entry, SCM_ARGn, caller);
cc95e00a 2259 SCM_ASSERT (scm_is_symbol (SCM_CAR (entry)), entry, SCM_ARGn, caller);
5d3e2388
DH
2260
2261 sym = SCM_CAR (entry);
2262
d2e53ed6 2263 for (l2 = SCM_CDR (entry); scm_is_pair (l2); l2 = SCM_CDR (l2))
5d3e2388
DH
2264 {
2265 SCM attribute = SCM_CAR (l2);
bc36d050 2266 if (scm_is_eq (attribute, symbol_immutable_location))
5d3e2388 2267 immutable = 1;
bc36d050 2268 else if (scm_is_eq (attribute, symbol_mutable_location))
5d3e2388
DH
2269 mutable = 1;
2270 else
2271 SCM_ASSERT (0, entry, SCM_ARGn, caller);
2272 }
d2e53ed6 2273 SCM_ASSERT (scm_is_null (l2), entry, SCM_ARGn, caller);
5d3e2388
DH
2274 SCM_ASSERT (!mutable || !immutable, entry, SCM_ARGn, caller);
2275
2276 if (!mutable && !immutable)
2277 immutable = 1;
2278
2279 mutability = mutable ? symbol_mutable_location : symbol_immutable_location;
2280 new_entry = scm_cons2 (sym, mutability, SCM_EOL);
2281 result = scm_cons (new_entry, result);
2282 }
2283 }
d2e53ed6 2284 SCM_ASSERT (scm_is_null (l), signature, SCM_ARGn, caller);
5d3e2388
DH
2285
2286 /* Dirk:FIXME:: Now we know that signature is syntactically correct. There
2287 * are, however, no checks for symbols entered twice with contradicting
2288 * mutabilities. It would be nice, to implement this test, to be able to
2289 * call the sort functions conveniently from C.
2290 */
2291
2292 return scm_reverse (result);
2293}
2294
2295
2296SCM_DEFINE (scm_export_environment_set_signature_x, "export-environment-set-signature!", 2, 0, 0,
2297 (SCM env, SCM signature),
0fb104ed 2298 "Change the signature of export environment @var{env}.")
5d3e2388
DH
2299#define FUNC_NAME s_scm_export_environment_set_signature_x
2300{
2301 SCM parsed_sig;
2302
2303 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2304 parsed_sig = export_environment_parse_signature (signature, FUNC_NAME);
2305
2306 EXPORT_ENVIRONMENT (env)->signature = parsed_sig;
2307
2308 return SCM_UNSPECIFIED;
2309}
2310#undef FUNC_NAME
2311
2312\f
2313
2314void
2315scm_environments_prehistory ()
2316{
2317 /* create environment smob */
2318 scm_tc16_environment = scm_make_smob_type ("environment", 0);
e841c3e0
KN
2319 scm_set_smob_mark (scm_tc16_environment, environment_mark);
2320 scm_set_smob_free (scm_tc16_environment, environment_free);
2321 scm_set_smob_print (scm_tc16_environment, environment_print);
5d3e2388
DH
2322
2323 /* create observer smob */
2324 scm_tc16_observer = scm_make_smob_type ("observer", 0);
e841c3e0
KN
2325 scm_set_smob_mark (scm_tc16_observer, observer_mark);
2326 scm_set_smob_print (scm_tc16_observer, observer_print);
de42a0ee
DH
2327
2328 /* create system environment */
2329 scm_system_environment = scm_make_leaf_environment ();
2330 scm_permanent_object (scm_system_environment);
5d3e2388
DH
2331}
2332
2333
2334void
2335scm_init_environments ()
2336{
480a873c 2337#include "libguile/environments.x"
5d3e2388
DH
2338}
2339
2340
2341/*
2342 Local Variables:
2343 c-file-style: "gnu"
2344 End:
2345*/