(scm_eval, scm_apply, call_cxr_1): Use scm_i_chase_pairs
[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
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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{
166 return gh_call3 (proc, symbol, value, tail);
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{
367 gh_call1 (proc, env);
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);
c35738c1
MD
512 SCM slot = scm_cons (entry, SCM_HASHTABLE_BUCKETS (obarray)[hash]);
513 SCM_SET_HASHTABLE_BUCKET (obarray, hash, slot);
514 if (SCM_HASHTABLE_N_ITEMS (obarray) > SCM_HASHTABLE_UPPER (obarray))
515 scm_i_rehash (obarray, scm_i_hash_symbol, 0, "obarray_enter");
5d3e2388
DH
516
517 return entry;
518}
519
520
a2d47b23
DH
521/*
522 * Enter symbol into obarray. An existing entry for symbol is replaced. If
523 * an entry existed, the old (symbol . data) cell is returned, #f otherwise.
524 */
525static SCM
526obarray_replace (SCM obarray, SCM symbol, SCM data)
527{
cc95e00a 528 size_t hash = scm_i_symbol_hash (symbol) % SCM_HASHTABLE_N_BUCKETS (obarray);
a2d47b23
DH
529 SCM new_entry = scm_cons (symbol, data);
530 SCM lsym;
531 SCM slot;
532
c35738c1
MD
533 for (lsym = SCM_HASHTABLE_BUCKETS (obarray)[hash];
534 !SCM_NULLP (lsym);
535 lsym = SCM_CDR (lsym))
a2d47b23
DH
536 {
537 SCM old_entry = SCM_CAR (lsym);
bc36d050 538 if (scm_is_eq (SCM_CAR (old_entry), symbol))
a2d47b23
DH
539 {
540 SCM_SETCAR (lsym, new_entry);
541 return old_entry;
542 }
543 }
544
c35738c1
MD
545 slot = scm_cons (new_entry, SCM_HASHTABLE_BUCKETS (obarray)[hash]);
546 SCM_SET_HASHTABLE_BUCKET (obarray, hash, slot);
547 if (SCM_HASHTABLE_N_ITEMS (obarray) > SCM_HASHTABLE_UPPER (obarray))
548 scm_i_rehash (obarray, scm_i_hash_symbol, 0, "obarray_replace");
a2d47b23
DH
549
550 return SCM_BOOL_F;
551}
552
553
5d3e2388
DH
554/*
555 * Look up symbol in obarray
556 */
557static SCM
558obarray_retrieve (SCM obarray, SCM sym)
559{
cc95e00a 560 size_t hash = scm_i_symbol_hash (sym) % SCM_HASHTABLE_N_BUCKETS (obarray);
5d3e2388
DH
561 SCM lsym;
562
c35738c1
MD
563 for (lsym = SCM_HASHTABLE_BUCKETS (obarray)[hash];
564 !SCM_NULLP (lsym);
565 lsym = SCM_CDR (lsym))
5d3e2388
DH
566 {
567 SCM entry = SCM_CAR (lsym);
bc36d050 568 if (scm_is_eq (SCM_CAR (entry), sym))
5d3e2388
DH
569 return entry;
570 }
571
572 return SCM_UNDEFINED;
573}
574
575
576/*
a2d47b23
DH
577 * Remove entry from obarray. If the symbol was found and removed, the old
578 * (symbol . data) cell is returned, #f otherwise.
5d3e2388
DH
579 */
580static SCM
581obarray_remove (SCM obarray, SCM sym)
582{
cc95e00a 583 size_t hash = scm_i_symbol_hash (sym) % SCM_HASHTABLE_N_BUCKETS (obarray);
c35738c1 584 SCM table_entry = SCM_HASHTABLE_BUCKETS (obarray)[hash];
35060ae9 585 SCM handle = scm_sloppy_assq (sym, table_entry);
34d19ef6 586
35060ae9 587 if (SCM_CONSP (handle))
34d19ef6 588 {
35060ae9 589 SCM new_table_entry = scm_delq1_x (handle, table_entry);
c35738c1
MD
590 SCM_SET_HASHTABLE_BUCKET (obarray, hash, new_table_entry);
591 SCM_HASHTABLE_DECREMENT (obarray);
5d3e2388 592 }
35060ae9
DH
593
594 return handle;
5d3e2388
DH
595}
596
597
598static void
599obarray_remove_all (SCM obarray)
600{
c35738c1 601 size_t size = SCM_HASHTABLE_N_BUCKETS (obarray);
1be6b49c 602 size_t i;
5d3e2388
DH
603
604 for (i = 0; i < size; i++)
605 {
c35738c1 606 SCM_SET_HASHTABLE_BUCKET (obarray, i, SCM_EOL);
5d3e2388 607 }
c35738c1 608 SCM_SET_HASHTABLE_N_ITEMS (obarray, 0);
5d3e2388
DH
609}
610
611\f
612
613/* core environments base
614 *
615 * This struct and the corresponding functions form a base class for guile's
616 * built-in environment types.
617 */
618
619
620struct core_environments_base {
621 struct scm_environment_funcs *funcs;
622
623 SCM observers;
624 SCM weak_observers;
625};
626
627
628#define CORE_ENVIRONMENTS_BASE(env) \
629 ((struct core_environments_base *) SCM_CELL_WORD_1 (env))
630#define CORE_ENVIRONMENT_OBSERVERS(env) \
631 (CORE_ENVIRONMENTS_BASE (env)->observers)
632#define SCM_SET_CORE_ENVIRONMENT_OBSERVERS(env, v) \
633 (CORE_ENVIRONMENT_OBSERVERS (env) = (v))
634#define CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR(env) \
635 (CORE_ENVIRONMENTS_BASE (env)->weak_observers)
636#define CORE_ENVIRONMENT_WEAK_OBSERVERS(env) \
637 (SCM_VELTS (CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env)) [0])
638#define SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS(env, v) \
34d19ef6 639 (SCM_VECTOR_SET (CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env), 0, (v)))
5d3e2388
DH
640
641\f
642
643static SCM
644core_environments_observe (SCM env, scm_environment_observer proc, SCM data, int weak_p)
645{
228a24ef
DH
646 SCM observer = scm_double_cell (scm_tc16_observer,
647 SCM_UNPACK (env),
648 SCM_UNPACK (data),
649 (scm_t_bits) proc);
5d3e2388
DH
650
651 if (!weak_p)
652 {
653 SCM observers = CORE_ENVIRONMENT_OBSERVERS (env);
654 SCM new_observers = scm_cons (observer, observers);
655 SCM_SET_CORE_ENVIRONMENT_OBSERVERS (env, new_observers);
656 }
657 else
658 {
659 SCM observers = CORE_ENVIRONMENT_WEAK_OBSERVERS (env);
660 SCM new_observers = scm_acons (SCM_BOOL_F, observer, observers);
661 SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS (env, new_observers);
662 }
663
664 return observer;
665}
666
667
668static void
669core_environments_unobserve (SCM env, SCM observer)
670{
671 unsigned int handling_weaks;
672 for (handling_weaks = 0; handling_weaks <= 1; ++handling_weaks)
673 {
674 SCM l = handling_weaks
675 ? CORE_ENVIRONMENT_WEAK_OBSERVERS (env)
676 : CORE_ENVIRONMENT_OBSERVERS (env);
677
678 if (!SCM_NULLP (l))
679 {
680 SCM rest = SCM_CDR (l);
681 SCM first = handling_weaks
682 ? SCM_CDAR (l)
683 : SCM_CAR (l);
684
bc36d050 685 if (scm_is_eq (first, observer))
5d3e2388
DH
686 {
687 /* Remove the first observer */
688 handling_weaks
689 ? SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS (env, rest)
690 : SCM_SET_CORE_ENVIRONMENT_OBSERVERS (env, rest);
691 return;
692 }
693
694 do {
695 SCM rest = SCM_CDR (l);
696
697 if (!SCM_NULLP (rest))
698 {
699 SCM next = handling_weaks
700 ? SCM_CDAR (l)
701 : SCM_CAR (l);
702
bc36d050 703 if (scm_is_eq (next, observer))
5d3e2388
DH
704 {
705 SCM_SETCDR (l, SCM_CDR (rest));
706 return;
707 }
708 }
709
710 l = rest;
711 } while (!SCM_NULLP (l));
712 }
713 }
714
715 /* Dirk:FIXME:: What to do now, since the observer is not found? */
716}
717
718
719static SCM
720core_environments_mark (SCM env)
721{
722 scm_gc_mark (CORE_ENVIRONMENT_OBSERVERS (env));
723 return CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env);
724}
725
726
727static void
e81d98ec 728core_environments_finalize (SCM env SCM_UNUSED)
5d3e2388
DH
729{
730}
731
732
733static void
734core_environments_preinit (struct core_environments_base *body)
735{
736 body->funcs = NULL;
737 body->observers = SCM_BOOL_F;
738 body->weak_observers = SCM_BOOL_F;
739}
740
741
742static void
743core_environments_init (struct core_environments_base *body,
744 struct scm_environment_funcs *funcs)
745{
746 body->funcs = funcs;
747 body->observers = SCM_EOL;
e11e83f3 748 body->weak_observers = scm_make_weak_value_alist_vector (scm_from_int (1));
5d3e2388
DH
749}
750
751
752/* Tell all observers to clear their caches.
753 *
754 * Environments have to be informed about changes in the following cases:
755 * - The observed env has a new binding. This must be always reported.
756 * - The observed env has dropped a binding. This must be always reported.
757 * - A binding in the observed environment has changed. This must only be
758 * reported, if there is a chance that the binding is being cached outside.
759 * However, this potential optimization is not performed currently.
760 *
761 * Errors that occur while the observers are called are accumulated and
762 * signalled as one single error message to the caller.
763 */
764
765struct update_data
766{
767 SCM observer;
768 SCM environment;
769};
770
771
772static SCM
773update_catch_body (void *ptr)
774{
775 struct update_data *data = (struct update_data *) ptr;
776 SCM observer = data->observer;
777
778 (*SCM_OBSERVER_PROC (observer))
779 (data->environment, SCM_OBSERVER_DATA (observer));
780
781 return SCM_UNDEFINED;
782}
783
784
785static SCM
786update_catch_handler (void *ptr, SCM tag, SCM args)
787{
788 struct update_data *data = (struct update_data *) ptr;
789 SCM observer = data->observer;
cc95e00a
MV
790 SCM message =
791 scm_from_locale_string ("Observer `~A' signals `~A' error: ~S");
5d3e2388 792
1afff620 793 return scm_cons (message, scm_list_3 (observer, tag, args));
5d3e2388
DH
794}
795
796
797static void
798core_environments_broadcast (SCM env)
799#define FUNC_NAME "core_environments_broadcast"
800{
801 unsigned int handling_weaks;
802 SCM errors = SCM_EOL;
803
804 for (handling_weaks = 0; handling_weaks <= 1; ++handling_weaks)
805 {
806 SCM observers = handling_weaks
807 ? CORE_ENVIRONMENT_WEAK_OBSERVERS (env)
808 : CORE_ENVIRONMENT_OBSERVERS (env);
809
810 for (; !SCM_NULLP (observers); observers = SCM_CDR (observers))
811 {
812 struct update_data data;
813 SCM observer = handling_weaks
814 ? SCM_CDAR (observers)
815 : SCM_CAR (observers);
816 SCM error;
817
818 data.observer = observer;
819 data.environment = env;
820
821 error = scm_internal_catch (SCM_BOOL_T,
822 update_catch_body, &data,
823 update_catch_handler, &data);
824
825 if (!SCM_UNBNDP (error))
826 errors = scm_cons (error, errors);
827 }
828 }
829
830 if (!SCM_NULLP (errors))
831 {
832 /* Dirk:FIXME:: As soon as scm_misc_error is fixed to handle the name
833 * parameter correctly it should not be necessary any more to also pass
834 * namestr in order to get the desired information from the error
835 * message.
836 */
837 SCM ordered_errors = scm_reverse (errors);
838 scm_misc_error
839 (FUNC_NAME,
840 "Observers of `~A' have signalled the following errors: ~S",
841 scm_cons2 (env, ordered_errors, SCM_EOL));
842 }
843}
844#undef FUNC_NAME
845
846\f
847
848/* leaf environments
849 *
850 * A leaf environment is simply a mutable set of definitions. A leaf
851 * environment supports no operations beyond the common set.
852 *
853 * Implementation: The obarray of the leaf environment holds (symbol . value)
854 * pairs. No further information is necessary, since all bindings and
855 * locations in a leaf environment are mutable.
856 */
857
858
859struct leaf_environment {
860 struct core_environments_base base;
861
862 SCM obarray;
863};
864
865
866#define LEAF_ENVIRONMENT(env) \
867 ((struct leaf_environment *) SCM_CELL_WORD_1 (env))
868
869\f
870
871static SCM
872leaf_environment_ref (SCM env, SCM sym)
873{
874 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
875 SCM binding = obarray_retrieve (obarray, sym);
876 return SCM_UNBNDP (binding) ? binding : SCM_CDR (binding);
877}
878
879
880static SCM
881leaf_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
882{
1be6b49c 883 size_t i;
5d3e2388
DH
884 SCM result = init;
885 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
886
c35738c1 887 for (i = 0; i < SCM_HASHTABLE_N_BUCKETS (obarray); i++)
5d3e2388
DH
888 {
889 SCM l;
c35738c1
MD
890 for (l = SCM_HASHTABLE_BUCKETS (obarray)[i];
891 !SCM_NULLP (l);
892 l = SCM_CDR (l))
5d3e2388
DH
893 {
894 SCM binding = SCM_CAR (l);
895 SCM symbol = SCM_CAR (binding);
896 SCM value = SCM_CDR (binding);
897 result = (*proc) (data, symbol, value, result);
898 }
899 }
900 return result;
901}
902
903
904static SCM
905leaf_environment_define (SCM env, SCM sym, SCM val)
906#define FUNC_NAME "leaf_environment_define"
907{
908 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
5d3e2388 909
a2d47b23 910 obarray_replace (obarray, sym, val);
5d3e2388
DH
911 core_environments_broadcast (env);
912
913 return SCM_ENVIRONMENT_SUCCESS;
914}
915#undef FUNC_NAME
916
917
918static SCM
919leaf_environment_undefine (SCM env, SCM sym)
920#define FUNC_NAME "leaf_environment_undefine"
921{
922 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
a2d47b23 923 SCM removed = obarray_remove (obarray, sym);
5d3e2388 924
7888309b 925 if (scm_is_true (removed))
a2d47b23 926 core_environments_broadcast (env);
5d3e2388
DH
927
928 return SCM_ENVIRONMENT_SUCCESS;
929}
930#undef FUNC_NAME
931
932
933static SCM
934leaf_environment_set_x (SCM env, SCM sym, SCM val)
935#define FUNC_NAME "leaf_environment_set_x"
936{
937 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
938 SCM binding = obarray_retrieve (obarray, sym);
939
940 if (!SCM_UNBNDP (binding))
941 {
942 SCM_SETCDR (binding, val);
943 return SCM_ENVIRONMENT_SUCCESS;
944 }
945 else
946 {
947 return SCM_UNDEFINED;
948 }
949}
950#undef FUNC_NAME
951
952
953static SCM
e81d98ec 954leaf_environment_cell (SCM env, SCM sym, int for_write SCM_UNUSED)
5d3e2388
DH
955{
956 SCM obarray = LEAF_ENVIRONMENT (env)->obarray;
957 SCM binding = obarray_retrieve (obarray, sym);
958 return binding;
959}
960
961
962static SCM
e841c3e0 963leaf_environment_mark (SCM env)
5d3e2388
DH
964{
965 scm_gc_mark (LEAF_ENVIRONMENT (env)->obarray);
966 return core_environments_mark (env);
967}
968
969
4c9419ac 970static void
e841c3e0 971leaf_environment_free (SCM env)
5d3e2388
DH
972{
973 core_environments_finalize (env);
4c9419ac
MV
974 scm_gc_free (LEAF_ENVIRONMENT (env), sizeof (struct leaf_environment),
975 "leaf environment");
5d3e2388
DH
976}
977
978
979static int
e81d98ec 980leaf_environment_print (SCM type, SCM port, scm_print_state *pstate SCM_UNUSED)
5d3e2388 981{
b9bd8526 982 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 983 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
984
985 scm_puts ("#<leaf environment ", port);
18f9d343 986 scm_display (base16, port);
5d3e2388
DH
987 scm_puts (">", port);
988
989 return 1;
990}
991
992
993static struct scm_environment_funcs leaf_environment_funcs = {
994 leaf_environment_ref,
995 leaf_environment_fold,
996 leaf_environment_define,
997 leaf_environment_undefine,
998 leaf_environment_set_x,
999 leaf_environment_cell,
1000 core_environments_observe,
1001 core_environments_unobserve,
e841c3e0
KN
1002 leaf_environment_mark,
1003 leaf_environment_free,
1004 leaf_environment_print
5d3e2388
DH
1005};
1006
1007
1008void *scm_type_leaf_environment = &leaf_environment_funcs;
1009
1010
1011SCM_DEFINE (scm_make_leaf_environment, "make-leaf-environment", 0, 0, 0,
1012 (),
1013 "Create a new leaf environment, containing no bindings.\n"
1014 "All bindings and locations created in the new environment\n"
1015 "will be mutable.")
1016#define FUNC_NAME s_scm_make_leaf_environment
1017{
1be6b49c 1018 size_t size = sizeof (struct leaf_environment);
4c9419ac 1019 struct leaf_environment *body = scm_gc_malloc (size, "leaf environment");
5d3e2388
DH
1020 SCM env;
1021
1022 core_environments_preinit (&body->base);
1023 body->obarray = SCM_BOOL_F;
1024
1025 env = scm_make_environment (body);
1026
1027 core_environments_init (&body->base, &leaf_environment_funcs);
00ffa0e7 1028 body->obarray = scm_c_make_hash_table (DEFAULT_OBARRAY_SIZE);
5d3e2388
DH
1029
1030 return env;
1031}
1032#undef FUNC_NAME
1033
1034
1035SCM_DEFINE (scm_leaf_environment_p, "leaf-environment?", 1, 0, 0,
1036 (SCM object),
0fb104ed
MG
1037 "Return @code{#t} if object is a leaf environment, or @code{#f}\n"
1038 "otherwise.")
5d3e2388
DH
1039#define FUNC_NAME s_scm_leaf_environment_p
1040{
7888309b 1041 return scm_from_bool (SCM_LEAF_ENVIRONMENT_P (object));
5d3e2388
DH
1042}
1043#undef FUNC_NAME
1044
1045\f
1046
1047/* eval environments
1048 *
1049 * A module's source code refers to definitions imported from other modules,
1050 * and definitions made within itself. An eval environment combines two
1051 * environments -- a local environment and an imported environment -- to
1052 * produce a new environment in which both sorts of references can be
1053 * resolved.
1054 *
1055 * Implementation: The obarray of the eval environment is used to cache
1056 * entries from the local and imported environments such that in most of the
1057 * cases only a single lookup is necessary. Since for neither the local nor
1058 * the imported environment it is known, what kind of environment they form,
1059 * the most general case is assumed. Therefore, entries in the obarray take
1060 * one of the following forms:
1061 *
1062 * 1) (<symbol> location mutability . source-env), where mutability indicates
1063 * one of the following states: IMMUTABLE if the location is known to be
1064 * immutable, MUTABLE if the location is known to be mutable, UNKNOWN if
1065 * the location has only been requested for non modifying accesses.
1066 *
1067 * 2) (symbol . source-env) if the symbol has a binding in the source-env, but
1068 * if the source-env can't provide a cell for the binding. Thus, for every
1069 * access, the source-env has to be contacted directly.
1070 */
1071
1072
1073struct eval_environment {
1074 struct core_environments_base base;
1075
1076 SCM obarray;
1077
1078 SCM imported;
1079 SCM imported_observer;
1080 SCM local;
1081 SCM local_observer;
1082};
1083
1084
1085#define EVAL_ENVIRONMENT(env) \
1086 ((struct eval_environment *) SCM_CELL_WORD_1 (env))
1087
93ccaef0
MV
1088#define IMMUTABLE SCM_I_MAKINUM (0)
1089#define MUTABLE SCM_I_MAKINUM (1)
1090#define UNKNOWN SCM_I_MAKINUM (2)
5d3e2388
DH
1091
1092#define CACHED_LOCATION(x) SCM_CAR (x)
1093#define CACHED_MUTABILITY(x) SCM_CADR (x)
1094#define SET_CACHED_MUTABILITY(x, v) SCM_SETCAR (SCM_CDR (x), (v))
1095#define CACHED_SOURCE_ENVIRONMENT(x) SCM_CDDR (x)
1096
1097\f
1098
1099/* eval_environment_lookup will report one of the following distinct results:
1100 * a) (<object> . value) if a cell could be obtained.
1101 * b) <environment> if the environment has to be contacted directly.
1102 * c) IMMUTABLE if an immutable cell was requested for write.
1103 * d) SCM_UNDEFINED if there is no binding for the symbol.
1104 */
1105static SCM
1106eval_environment_lookup (SCM env, SCM sym, int for_write)
1107{
1108 SCM obarray = EVAL_ENVIRONMENT (env)->obarray;
1109 SCM binding = obarray_retrieve (obarray, sym);
1110
1111 if (!SCM_UNBNDP (binding))
1112 {
1113 /* The obarray holds an entry for the symbol. */
1114
1115 SCM entry = SCM_CDR (binding);
1116
1117 if (SCM_CONSP (entry))
1118 {
1119 /* The entry in the obarray is a cached location. */
1120
1121 SCM location = CACHED_LOCATION (entry);
1122 SCM mutability;
1123
1124 if (!for_write)
1125 return location;
1126
1127 mutability = CACHED_MUTABILITY (entry);
bc36d050 1128 if (scm_is_eq (mutability, MUTABLE))
5d3e2388
DH
1129 return location;
1130
bc36d050 1131 if (scm_is_eq (mutability, UNKNOWN))
5d3e2388
DH
1132 {
1133 SCM source_env = CACHED_SOURCE_ENVIRONMENT (entry);
1134 SCM location = SCM_ENVIRONMENT_CELL (source_env, sym, 1);
1135
1136 if (SCM_CONSP (location))
1137 {
1138 SET_CACHED_MUTABILITY (entry, MUTABLE);
1139 return location;
1140 }
1141 else /* IMMUTABLE */
1142 {
1143 SET_CACHED_MUTABILITY (entry, IMMUTABLE);
1144 return IMMUTABLE;
1145 }
1146 }
1147
1148 return IMMUTABLE;
1149 }
1150 else
1151 {
1152 /* The obarray entry is an environment */
1153
1154 return entry;
1155 }
1156 }
1157 else
1158 {
1159 /* There is no entry for the symbol in the obarray. This can either
1160 * mean that there has not been a request for the symbol yet, or that
1161 * the symbol is really undefined. We are looking for the symbol in
1162 * both the local and the imported environment. If we find a binding, a
1163 * cached entry is created.
1164 */
1165
1166 struct eval_environment *body = EVAL_ENVIRONMENT (env);
1167 unsigned int handling_import;
1168
1169 for (handling_import = 0; handling_import <= 1; ++handling_import)
1170 {
1171 SCM source_env = handling_import ? body->imported : body->local;
1172 SCM location = SCM_ENVIRONMENT_CELL (source_env, sym, for_write);
1173
1174 if (!SCM_UNBNDP (location))
1175 {
1176 if (SCM_CONSP (location))
1177 {
1178 SCM mutability = for_write ? MUTABLE : UNKNOWN;
1179 SCM entry = scm_cons2 (location, mutability, source_env);
1180 obarray_enter (obarray, sym, entry);
1181 return location;
1182 }
bc36d050 1183 else if (scm_is_eq (location, SCM_ENVIRONMENT_LOCATION_NO_CELL))
5d3e2388
DH
1184 {
1185 obarray_enter (obarray, sym, source_env);
1186 return source_env;
1187 }
1188 else
1189 {
1190 return IMMUTABLE;
1191 }
1192 }
1193 }
1194
1195 return SCM_UNDEFINED;
1196 }
1197}
1198
1199
1200static SCM
1201eval_environment_ref (SCM env, SCM sym)
1202#define FUNC_NAME "eval_environment_ref"
1203{
1204 SCM location = eval_environment_lookup (env, sym, 0);
1205
1206 if (SCM_CONSP (location))
1207 return SCM_CDR (location);
1208 else if (!SCM_UNBNDP (location))
1209 return SCM_ENVIRONMENT_REF (location, sym);
1210 else
1211 return SCM_UNDEFINED;
1212}
1213#undef FUNC_NAME
1214
1215
1216static SCM
1217eval_environment_folder (SCM extended_data, SCM symbol, SCM value, SCM tail)
1218{
1219 SCM local = SCM_CAR (extended_data);
1220
1221 if (!SCM_ENVIRONMENT_BOUND_P (local, symbol))
1222 {
1223 SCM proc_as_nr = SCM_CADR (extended_data);
b9bd8526 1224 unsigned long int proc_as_ul = scm_to_ulong (proc_as_nr);
5d3e2388
DH
1225 scm_environment_folder proc = (scm_environment_folder) proc_as_ul;
1226 SCM data = SCM_CDDR (extended_data);
1227
1228 return (*proc) (data, symbol, value, tail);
1229 }
1230 else
1231 {
1232 return tail;
1233 }
1234}
1235
1236
1237static SCM
1238eval_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
1239{
1240 SCM local = EVAL_ENVIRONMENT (env)->local;
1241 SCM imported = EVAL_ENVIRONMENT (env)->imported;
b9bd8526 1242 SCM proc_as_nr = scm_from_ulong ((unsigned long) proc);
5d3e2388
DH
1243 SCM extended_data = scm_cons2 (local, proc_as_nr, data);
1244 SCM tmp_result = scm_c_environment_fold (imported, eval_environment_folder, extended_data, init);
1245
1246 return scm_c_environment_fold (local, proc, data, tmp_result);
1247}
1248
1249
1250static SCM
1251eval_environment_define (SCM env, SCM sym, SCM val)
1252#define FUNC_NAME "eval_environment_define"
1253{
1254 SCM local = EVAL_ENVIRONMENT (env)->local;
1255 return SCM_ENVIRONMENT_DEFINE (local, sym, val);
1256}
1257#undef FUNC_NAME
1258
1259
1260static SCM
1261eval_environment_undefine (SCM env, SCM sym)
1262#define FUNC_NAME "eval_environment_undefine"
1263{
1264 SCM local = EVAL_ENVIRONMENT (env)->local;
1265 return SCM_ENVIRONMENT_UNDEFINE (local, sym);
1266}
1267#undef FUNC_NAME
1268
1269
1270static SCM
1271eval_environment_set_x (SCM env, SCM sym, SCM val)
1272#define FUNC_NAME "eval_environment_set_x"
1273{
1274 SCM location = eval_environment_lookup (env, sym, 1);
1275
1276 if (SCM_CONSP (location))
1277 {
1278 SCM_SETCDR (location, val);
1279 return SCM_ENVIRONMENT_SUCCESS;
1280 }
1281 else if (SCM_ENVIRONMENT_P (location))
1282 {
1283 return SCM_ENVIRONMENT_SET (location, sym, val);
1284 }
bc36d050 1285 else if (scm_is_eq (location, IMMUTABLE))
5d3e2388
DH
1286 {
1287 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
1288 }
1289 else
1290 {
1291 return SCM_UNDEFINED;
1292 }
1293}
1294#undef FUNC_NAME
1295
1296
1297static SCM
1298eval_environment_cell (SCM env, SCM sym, int for_write)
1299#define FUNC_NAME "eval_environment_cell"
1300{
1301 SCM location = eval_environment_lookup (env, sym, for_write);
1302
1303 if (SCM_CONSP (location))
1304 return location;
1305 else if (SCM_ENVIRONMENT_P (location))
1306 return SCM_ENVIRONMENT_LOCATION_NO_CELL;
bc36d050 1307 else if (scm_is_eq (location, IMMUTABLE))
5d3e2388
DH
1308 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
1309 else
1310 return SCM_UNDEFINED;
1311}
1312#undef FUNC_NAME
1313
1314
1315static SCM
e841c3e0 1316eval_environment_mark (SCM env)
5d3e2388
DH
1317{
1318 struct eval_environment *body = EVAL_ENVIRONMENT (env);
1319
1320 scm_gc_mark (body->obarray);
1321 scm_gc_mark (body->imported);
1322 scm_gc_mark (body->imported_observer);
1323 scm_gc_mark (body->local);
1324 scm_gc_mark (body->local_observer);
1325
1326 return core_environments_mark (env);
1327}
1328
1329
4c9419ac 1330static void
e841c3e0 1331eval_environment_free (SCM env)
5d3e2388
DH
1332{
1333 core_environments_finalize (env);
4c9419ac
MV
1334 scm_gc_free (EVAL_ENVIRONMENT (env), sizeof (struct eval_environment),
1335 "eval environment");
5d3e2388
DH
1336}
1337
1338
1339static int
e81d98ec 1340eval_environment_print (SCM type, SCM port, scm_print_state *pstate SCM_UNUSED)
5d3e2388 1341{
b9bd8526 1342 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 1343 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
1344
1345 scm_puts ("#<eval environment ", port);
18f9d343 1346 scm_display (base16, port);
5d3e2388
DH
1347 scm_puts (">", port);
1348
1349 return 1;
1350}
1351
1352
1353static struct scm_environment_funcs eval_environment_funcs = {
1354 eval_environment_ref,
1355 eval_environment_fold,
1356 eval_environment_define,
1357 eval_environment_undefine,
1358 eval_environment_set_x,
1359 eval_environment_cell,
1360 core_environments_observe,
1361 core_environments_unobserve,
e841c3e0
KN
1362 eval_environment_mark,
1363 eval_environment_free,
1364 eval_environment_print
5d3e2388
DH
1365};
1366
1367
1368void *scm_type_eval_environment = &eval_environment_funcs;
1369
1370
1371static void
e81d98ec 1372eval_environment_observer (SCM caller SCM_UNUSED, SCM eval_env)
5d3e2388
DH
1373{
1374 SCM obarray = EVAL_ENVIRONMENT (eval_env)->obarray;
1375
1376 obarray_remove_all (obarray);
1377 core_environments_broadcast (eval_env);
1378}
1379
1380
1381SCM_DEFINE (scm_make_eval_environment, "make-eval-environment", 2, 0, 0,
1382 (SCM local, SCM imported),
1383 "Return a new environment object eval whose bindings are the\n"
0fb104ed
MG
1384 "union of the bindings in the environments @var{local} and\n"
1385 "@var{imported}, with bindings from @var{local} taking\n"
1386 "precedence. Definitions made in eval are placed in @var{local}.\n"
1387 "Applying @code{environment-define} or\n"
1388 "@code{environment-undefine} to eval has the same effect as\n"
1389 "applying the procedure to @var{local}.\n"
1390 "Note that eval incorporates @var{local} and @var{imported} by\n"
1391 "reference:\n"
5d3e2388 1392 "If, after creating eval, the program changes the bindings of\n"
0fb104ed
MG
1393 "@var{local} or @var{imported}, those changes will be visible\n"
1394 "in eval.\n"
5d3e2388 1395 "Since most Scheme evaluation takes place in eval environments,\n"
0fb104ed
MG
1396 "they transparently cache the bindings received from @var{local}\n"
1397 "and @var{imported}. Thus, the first time the program looks up\n"
1398 "a symbol in eval, eval may make calls to @var{local} or\n"
1399 "@var{imported} to find their bindings, but subsequent\n"
1400 "references to that symbol will be as fast as references to\n"
1401 "bindings in finite environments.\n"
1402 "In typical use, @var{local} will be a finite environment, and\n"
1403 "@var{imported} will be an import environment")
5d3e2388
DH
1404#define FUNC_NAME s_scm_make_eval_environment
1405{
1406 SCM env;
1407 struct eval_environment *body;
1408
1409 SCM_ASSERT (SCM_ENVIRONMENT_P (local), local, SCM_ARG1, FUNC_NAME);
1410 SCM_ASSERT (SCM_ENVIRONMENT_P (imported), imported, SCM_ARG2, FUNC_NAME);
1411
4c9419ac 1412 body = scm_gc_malloc (sizeof (struct eval_environment), "eval environment");
5d3e2388
DH
1413
1414 core_environments_preinit (&body->base);
1415 body->obarray = SCM_BOOL_F;
1416 body->imported = SCM_BOOL_F;
1417 body->imported_observer = SCM_BOOL_F;
1418 body->local = SCM_BOOL_F;
1419 body->local_observer = SCM_BOOL_F;
1420
1421 env = scm_make_environment (body);
1422
1423 core_environments_init (&body->base, &eval_environment_funcs);
00ffa0e7 1424 body->obarray = scm_c_make_hash_table (DEFAULT_OBARRAY_SIZE);
5d3e2388
DH
1425 body->imported = imported;
1426 body->imported_observer
1427 = SCM_ENVIRONMENT_OBSERVE (imported, eval_environment_observer, env, 1);
1428 body->local = local;
1429 body->local_observer
1430 = SCM_ENVIRONMENT_OBSERVE (local, eval_environment_observer, env, 1);
1431
1432 return env;
1433}
1434#undef FUNC_NAME
1435
1436
1437SCM_DEFINE (scm_eval_environment_p, "eval-environment?", 1, 0, 0,
1438 (SCM object),
0fb104ed
MG
1439 "Return @code{#t} if object is an eval environment, or @code{#f}\n"
1440 "otherwise.")
5d3e2388
DH
1441#define FUNC_NAME s_scm_eval_environment_p
1442{
7888309b 1443 return scm_from_bool (SCM_EVAL_ENVIRONMENT_P (object));
5d3e2388
DH
1444}
1445#undef FUNC_NAME
1446
1447
1448SCM_DEFINE (scm_eval_environment_local, "eval-environment-local", 1, 0, 0,
1449 (SCM env),
0fb104ed 1450 "Return the local environment of eval environment @var{env}.")
5d3e2388
DH
1451#define FUNC_NAME s_scm_eval_environment_local
1452{
1453 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1454
1455 return EVAL_ENVIRONMENT (env)->local;
1456}
1457#undef FUNC_NAME
1458
1459
1460SCM_DEFINE (scm_eval_environment_set_local_x, "eval-environment-set-local!", 2, 0, 0,
1461 (SCM env, SCM local),
0fb104ed 1462 "Change @var{env}'s local environment to @var{local}.")
5d3e2388
DH
1463#define FUNC_NAME s_scm_eval_environment_set_local_x
1464{
1465 struct eval_environment *body;
1466
1467 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1468 SCM_ASSERT (SCM_ENVIRONMENT_P (local), local, SCM_ARG2, FUNC_NAME);
1469
1470 body = EVAL_ENVIRONMENT (env);
1471
1472 obarray_remove_all (body->obarray);
1473 SCM_ENVIRONMENT_UNOBSERVE (body->local, body->local_observer);
1474
1475 body->local = local;
1476 body->local_observer
1477 = SCM_ENVIRONMENT_OBSERVE (local, eval_environment_observer, env, 1);
1478
1479 core_environments_broadcast (env);
1480
1481 return SCM_UNSPECIFIED;
1482}
1483#undef FUNC_NAME
1484
1485
1486SCM_DEFINE (scm_eval_environment_imported, "eval-environment-imported", 1, 0, 0,
1487 (SCM env),
0fb104ed 1488 "Return the imported environment of eval environment @var{env}.")
5d3e2388
DH
1489#define FUNC_NAME s_scm_eval_environment_imported
1490{
1491 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1492
1493 return EVAL_ENVIRONMENT (env)->imported;
1494}
1495#undef FUNC_NAME
1496
1497
1498SCM_DEFINE (scm_eval_environment_set_imported_x, "eval-environment-set-imported!", 2, 0, 0,
1499 (SCM env, SCM imported),
0fb104ed 1500 "Change @var{env}'s imported environment to @var{imported}.")
5d3e2388
DH
1501#define FUNC_NAME s_scm_eval_environment_set_imported_x
1502{
1503 struct eval_environment *body;
1504
1505 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1506 SCM_ASSERT (SCM_ENVIRONMENT_P (imported), imported, SCM_ARG2, FUNC_NAME);
1507
1508 body = EVAL_ENVIRONMENT (env);
1509
1510 obarray_remove_all (body->obarray);
1511 SCM_ENVIRONMENT_UNOBSERVE (body->imported, body->imported_observer);
1512
1513 body->imported = imported;
1514 body->imported_observer
1515 = SCM_ENVIRONMENT_OBSERVE (imported, eval_environment_observer, env, 1);
1516
1517 core_environments_broadcast (env);
1518
1519 return SCM_UNSPECIFIED;
1520}
1521#undef FUNC_NAME
1522
1523\f
1524
1525/* import environments
1526 *
1527 * An import environment combines the bindings of a set of argument
1528 * environments, and checks for naming clashes.
1529 *
1530 * Implementation: The import environment does no caching at all. For every
1531 * access, the list of imported environments is scanned.
1532 */
1533
1534
1535struct import_environment {
1536 struct core_environments_base base;
1537
1538 SCM imports;
1539 SCM import_observers;
1540
1541 SCM conflict_proc;
1542};
1543
1544
1545#define IMPORT_ENVIRONMENT(env) \
1546 ((struct import_environment *) SCM_CELL_WORD_1 (env))
1547
1548\f
1549
1550/* Lookup will report one of the following distinct results:
1551 * a) <environment> if only environment binds the symbol.
1552 * b) (env-1 env-2 ...) for conflicting bindings in env-1, ...
1553 * c) SCM_UNDEFINED if there is no binding for the symbol.
1554 */
1555static SCM
1556import_environment_lookup (SCM env, SCM sym)
1557{
1558 SCM imports = IMPORT_ENVIRONMENT (env)->imports;
1559 SCM result = SCM_UNDEFINED;
1560 SCM l;
1561
1562 for (l = imports; !SCM_NULLP (l); l = SCM_CDR (l))
1563 {
1564 SCM imported = SCM_CAR (l);
1565
1566 if (SCM_ENVIRONMENT_BOUND_P (imported, sym))
1567 {
1568 if (SCM_UNBNDP (result))
1569 result = imported;
1570 else if (SCM_CONSP (result))
1571 result = scm_cons (imported, result);
1572 else
1573 result = scm_cons2 (imported, result, SCM_EOL);
1574 }
1575 }
1576
1577 if (SCM_CONSP (result))
1578 return scm_reverse (result);
1579 else
1580 return result;
1581}
1582
1583
1584static SCM
1585import_environment_conflict (SCM env, SCM sym, SCM imports)
1586{
1587 SCM conflict_proc = IMPORT_ENVIRONMENT (env)->conflict_proc;
1588 SCM args = scm_cons2 (env, sym, scm_cons (imports, SCM_EOL));
1589
fdc28395 1590 return scm_apply_0 (conflict_proc, args);
5d3e2388
DH
1591}
1592
1593
1594static SCM
1595import_environment_ref (SCM env, SCM sym)
1596#define FUNC_NAME "import_environment_ref"
1597{
1598 SCM owner = import_environment_lookup (env, sym);
1599
1600 if (SCM_UNBNDP (owner))
1601 {
1602 return SCM_UNDEFINED;
1603 }
1604 else if (SCM_CONSP (owner))
1605 {
1606 SCM resolve = import_environment_conflict (env, sym, owner);
1607
1608 if (SCM_ENVIRONMENT_P (resolve))
1609 return SCM_ENVIRONMENT_REF (resolve, sym);
1610 else
1611 return SCM_UNSPECIFIED;
1612 }
1613 else
1614 {
1615 return SCM_ENVIRONMENT_REF (owner, sym);
1616 }
1617}
1618#undef FUNC_NAME
1619
1620
1621static SCM
1622import_environment_folder (SCM extended_data, SCM symbol, SCM value, SCM tail)
1623#define FUNC_NAME "import_environment_fold"
1624{
1625 SCM import_env = SCM_CAR (extended_data);
1626 SCM imported_env = SCM_CADR (extended_data);
1627 SCM owner = import_environment_lookup (import_env, symbol);
1628 SCM proc_as_nr = SCM_CADDR (extended_data);
b9bd8526 1629 unsigned long int proc_as_ul = scm_to_ulong (proc_as_nr);
5d3e2388
DH
1630 scm_environment_folder proc = (scm_environment_folder) proc_as_ul;
1631 SCM data = SCM_CDDDR (extended_data);
1632
bc36d050 1633 if (SCM_CONSP (owner) && scm_is_eq (SCM_CAR (owner), imported_env))
5d3e2388
DH
1634 owner = import_environment_conflict (import_env, symbol, owner);
1635
1636 if (SCM_ENVIRONMENT_P (owner))
1637 return (*proc) (data, symbol, value, tail);
1638 else /* unresolved conflict */
1639 return (*proc) (data, symbol, SCM_UNSPECIFIED, tail);
1640}
1641#undef FUNC_NAME
1642
1643
1644static SCM
1645import_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
1646{
b9bd8526 1647 SCM proc_as_nr = scm_from_ulong ((unsigned long) proc);
5d3e2388
DH
1648 SCM result = init;
1649 SCM l;
1650
1651 for (l = IMPORT_ENVIRONMENT (env)->imports; !SCM_NULLP (l); l = SCM_CDR (l))
1652 {
1653 SCM imported_env = SCM_CAR (l);
1654 SCM extended_data = scm_cons (env, scm_cons2 (imported_env, proc_as_nr, data));
1655
1656 result = scm_c_environment_fold (imported_env, import_environment_folder, extended_data, result);
1657 }
1658
1659 return result;
1660}
1661
1662
1663static SCM
e81d98ec
DH
1664import_environment_define (SCM env SCM_UNUSED,
1665 SCM sym SCM_UNUSED,
1666 SCM val SCM_UNUSED)
5d3e2388
DH
1667#define FUNC_NAME "import_environment_define"
1668{
1669 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1670}
1671#undef FUNC_NAME
1672
1673
1674static SCM
e81d98ec
DH
1675import_environment_undefine (SCM env SCM_UNUSED,
1676 SCM sym SCM_UNUSED)
5d3e2388
DH
1677#define FUNC_NAME "import_environment_undefine"
1678{
1679 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1680}
1681#undef FUNC_NAME
1682
1683
1684static SCM
1685import_environment_set_x (SCM env, SCM sym, SCM val)
1686#define FUNC_NAME "import_environment_set_x"
1687{
1688 SCM owner = import_environment_lookup (env, sym);
1689
1690 if (SCM_UNBNDP (owner))
1691 {
1692 return SCM_UNDEFINED;
1693 }
1694 else if (SCM_CONSP (owner))
1695 {
1696 SCM resolve = import_environment_conflict (env, sym, owner);
1697
1698 if (SCM_ENVIRONMENT_P (resolve))
1699 return SCM_ENVIRONMENT_SET (resolve, sym, val);
1700 else
1701 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
1702 }
1703 else
1704 {
1705 return SCM_ENVIRONMENT_SET (owner, sym, val);
1706 }
1707}
1708#undef FUNC_NAME
1709
1710
1711static SCM
1712import_environment_cell (SCM env, SCM sym, int for_write)
1713#define FUNC_NAME "import_environment_cell"
1714{
1715 SCM owner = import_environment_lookup (env, sym);
1716
1717 if (SCM_UNBNDP (owner))
1718 {
1719 return SCM_UNDEFINED;
1720 }
1721 else if (SCM_CONSP (owner))
1722 {
1723 SCM resolve = import_environment_conflict (env, sym, owner);
1724
1725 if (SCM_ENVIRONMENT_P (resolve))
1726 return SCM_ENVIRONMENT_CELL (resolve, sym, for_write);
1727 else
1728 return SCM_ENVIRONMENT_LOCATION_NO_CELL;
1729 }
1730 else
1731 {
1732 return SCM_ENVIRONMENT_CELL (owner, sym, for_write);
1733 }
1734}
1735#undef FUNC_NAME
1736
1737
1738static SCM
e841c3e0 1739import_environment_mark (SCM env)
5d3e2388
DH
1740{
1741 scm_gc_mark (IMPORT_ENVIRONMENT (env)->imports);
1742 scm_gc_mark (IMPORT_ENVIRONMENT (env)->import_observers);
1743 scm_gc_mark (IMPORT_ENVIRONMENT (env)->conflict_proc);
1744 return core_environments_mark (env);
1745}
1746
1747
4c9419ac 1748static void
e841c3e0 1749import_environment_free (SCM env)
5d3e2388
DH
1750{
1751 core_environments_finalize (env);
4c9419ac
MV
1752 scm_gc_free (IMPORT_ENVIRONMENT (env), sizeof (struct import_environment),
1753 "import environment");
5d3e2388
DH
1754}
1755
1756
1757static int
e81d98ec
DH
1758import_environment_print (SCM type, SCM port,
1759 scm_print_state *pstate SCM_UNUSED)
5d3e2388 1760{
b9bd8526 1761 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 1762 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
1763
1764 scm_puts ("#<import environment ", port);
18f9d343 1765 scm_display (base16, port);
5d3e2388
DH
1766 scm_puts (">", port);
1767
1768 return 1;
1769}
1770
1771
1772static struct scm_environment_funcs import_environment_funcs = {
1773 import_environment_ref,
1774 import_environment_fold,
1775 import_environment_define,
1776 import_environment_undefine,
1777 import_environment_set_x,
1778 import_environment_cell,
1779 core_environments_observe,
1780 core_environments_unobserve,
e841c3e0
KN
1781 import_environment_mark,
1782 import_environment_free,
1783 import_environment_print
5d3e2388
DH
1784};
1785
1786
1787void *scm_type_import_environment = &import_environment_funcs;
1788
1789
1790static void
e81d98ec 1791import_environment_observer (SCM caller SCM_UNUSED, SCM import_env)
5d3e2388
DH
1792{
1793 core_environments_broadcast (import_env);
1794}
1795
1796
1797SCM_DEFINE (scm_make_import_environment, "make-import-environment", 2, 0, 0,
1798 (SCM imports, SCM conflict_proc),
0fb104ed
MG
1799 "Return a new environment @var{imp} whose bindings are the union\n"
1800 "of the bindings from the environments in @var{imports};\n"
1801 "@var{imports} must be a list of environments. That is,\n"
1802 "@var{imp} binds a symbol to a location when some element of\n"
1803 "@var{imports} does.\n"
1804 "If two different elements of @var{imports} have a binding for\n"
1805 "the same symbol, the @var{conflict-proc} is called with the\n"
1806 "following parameters: the import environment, the symbol and\n"
1807 "the list of the imported environments that bind the symbol.\n"
1808 "If the @var{conflict-proc} returns an environment @var{env},\n"
1809 "the conflict is considered as resolved and the binding from\n"
1810 "@var{env} is used. If the @var{conflict-proc} returns some\n"
1811 "non-environment object, the conflict is considered unresolved\n"
1812 "and the symbol is treated as unspecified in the import\n"
1813 "environment.\n"
1814 "The checking for conflicts may be performed lazily, i. e. at\n"
5d3e2388
DH
1815 "the moment when a value or binding for a certain symbol is\n"
1816 "requested instead of the moment when the environment is\n"
1817 "created or the bindings of the imports change.\n"
0fb104ed
MG
1818 "All bindings in @var{imp} are immutable. If you apply\n"
1819 "@code{environment-define} or @code{environment-undefine} to\n"
1820 "@var{imp}, Guile will signal an\n"
1821 " @code{environment:immutable-binding} error. However,\n"
1822 "notice that the set of bindings in @var{imp} may still change,\n"
1823 "if one of its imported environments changes.")
5d3e2388
DH
1824#define FUNC_NAME s_scm_make_import_environment
1825{
1be6b49c 1826 size_t size = sizeof (struct import_environment);
4c9419ac 1827 struct import_environment *body = scm_gc_malloc (size, "import environment");
5d3e2388
DH
1828 SCM env;
1829
1830 core_environments_preinit (&body->base);
1831 body->imports = SCM_BOOL_F;
1832 body->import_observers = SCM_BOOL_F;
1833 body->conflict_proc = SCM_BOOL_F;
1834
1835 env = scm_make_environment (body);
1836
1837 core_environments_init (&body->base, &import_environment_funcs);
1838 body->imports = SCM_EOL;
1839 body->import_observers = SCM_EOL;
1840 body->conflict_proc = conflict_proc;
1841
1842 scm_import_environment_set_imports_x (env, imports);
1843
1844 return env;
1845}
1846#undef FUNC_NAME
1847
1848
1849SCM_DEFINE (scm_import_environment_p, "import-environment?", 1, 0, 0,
1850 (SCM object),
0fb104ed
MG
1851 "Return @code{#t} if object is an import environment, or\n"
1852 "@code{#f} otherwise.")
5d3e2388
DH
1853#define FUNC_NAME s_scm_import_environment_p
1854{
7888309b 1855 return scm_from_bool (SCM_IMPORT_ENVIRONMENT_P (object));
5d3e2388
DH
1856}
1857#undef FUNC_NAME
1858
1859
1860SCM_DEFINE (scm_import_environment_imports, "import-environment-imports", 1, 0, 0,
1861 (SCM env),
0fb104ed
MG
1862 "Return the list of environments imported by the import\n"
1863 "environment @var{env}.")
5d3e2388
DH
1864#define FUNC_NAME s_scm_import_environment_imports
1865{
1866 SCM_ASSERT (SCM_IMPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1867
1868 return IMPORT_ENVIRONMENT (env)->imports;
1869}
1870#undef FUNC_NAME
1871
1872
1873SCM_DEFINE (scm_import_environment_set_imports_x, "import-environment-set-imports!", 2, 0, 0,
1874 (SCM env, SCM imports),
0fb104ed
MG
1875 "Change @var{env}'s list of imported environments to\n"
1876 "@var{imports}, and check for conflicts.")
5d3e2388
DH
1877#define FUNC_NAME s_scm_import_environment_set_imports_x
1878{
1879 struct import_environment *body = IMPORT_ENVIRONMENT (env);
1880 SCM import_observers = SCM_EOL;
1881 SCM l;
1882
1883 SCM_ASSERT (SCM_IMPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
1884 for (l = imports; SCM_CONSP (l); l = SCM_CDR (l))
1885 {
1886 SCM obj = SCM_CAR (l);
dd85ce47 1887 SCM_ASSERT (SCM_ENVIRONMENT_P (obj), imports, SCM_ARG2, FUNC_NAME);
5d3e2388 1888 }
dd85ce47 1889 SCM_ASSERT (SCM_NULLP (l), imports, SCM_ARG2, FUNC_NAME);
5d3e2388
DH
1890
1891 for (l = body->import_observers; !SCM_NULLP (l); l = SCM_CDR (l))
1892 {
1893 SCM obs = SCM_CAR (l);
1894 SCM_ENVIRONMENT_UNOBSERVE (env, obs);
1895 }
1896
1897 for (l = imports; !SCM_NULLP (l); l = SCM_CDR (l))
1898 {
1899 SCM imp = SCM_CAR (l);
1900 SCM obs = SCM_ENVIRONMENT_OBSERVE (imp, import_environment_observer, env, 1);
1901 import_observers = scm_cons (obs, import_observers);
1902 }
1903
1904 body->imports = imports;
1905 body->import_observers = import_observers;
1906
1907 return SCM_UNSPECIFIED;
1908}
1909#undef FUNC_NAME
1910
1911\f
1912
1913/* export environments
1914 *
1915 * An export environment restricts an environment to a specified set of
1916 * bindings.
1917 *
1918 * Implementation: The export environment does no caching at all. For every
1919 * access, the signature is scanned. The signature that is stored internally
1920 * is an alist of pairs (symbol . (mutability)).
1921 */
1922
1923
1924struct export_environment {
1925 struct core_environments_base base;
1926
1927 SCM private;
1928 SCM private_observer;
1929
1930 SCM signature;
1931};
1932
1933
1934#define EXPORT_ENVIRONMENT(env) \
1935 ((struct export_environment *) SCM_CELL_WORD_1 (env))
1936
1937
1938SCM_SYMBOL (symbol_immutable_location, "immutable-location");
1939SCM_SYMBOL (symbol_mutable_location, "mutable-location");
1940
1941\f
1942
1943static SCM
1944export_environment_ref (SCM env, SCM sym)
1945#define FUNC_NAME "export_environment_ref"
1946{
1947 struct export_environment *body = EXPORT_ENVIRONMENT (env);
1948 SCM entry = scm_assq (sym, body->signature);
1949
7888309b 1950 if (scm_is_false (entry))
5d3e2388
DH
1951 return SCM_UNDEFINED;
1952 else
1953 return SCM_ENVIRONMENT_REF (body->private, sym);
1954}
1955#undef FUNC_NAME
1956
1957
1958static SCM
1959export_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init)
1960{
1961 struct export_environment *body = EXPORT_ENVIRONMENT (env);
1962 SCM result = init;
1963 SCM l;
1964
1965 for (l = body->signature; !SCM_NULLP (l); l = SCM_CDR (l))
1966 {
1967 SCM symbol = SCM_CAR (l);
1968 SCM value = SCM_ENVIRONMENT_REF (body->private, symbol);
1969 if (!SCM_UNBNDP (value))
1970 result = (*proc) (data, symbol, value, result);
1971 }
1972 return result;
1973}
1974
1975
1976static SCM
e81d98ec
DH
1977export_environment_define (SCM env SCM_UNUSED,
1978 SCM sym SCM_UNUSED,
1979 SCM val SCM_UNUSED)
5d3e2388
DH
1980#define FUNC_NAME "export_environment_define"
1981{
1982 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1983}
1984#undef FUNC_NAME
1985
1986
1987static SCM
e81d98ec 1988export_environment_undefine (SCM env SCM_UNUSED, SCM sym SCM_UNUSED)
5d3e2388
DH
1989#define FUNC_NAME "export_environment_undefine"
1990{
1991 return SCM_ENVIRONMENT_BINDING_IMMUTABLE;
1992}
1993#undef FUNC_NAME
1994
1995
1996static SCM
1997export_environment_set_x (SCM env, SCM sym, SCM val)
1998#define FUNC_NAME "export_environment_set_x"
1999{
2000 struct export_environment *body = EXPORT_ENVIRONMENT (env);
2001 SCM entry = scm_assq (sym, body->signature);
2002
7888309b 2003 if (scm_is_false (entry))
5d3e2388
DH
2004 {
2005 return SCM_UNDEFINED;
2006 }
2007 else
2008 {
bc36d050 2009 if (scm_is_eq (SCM_CADR (entry), symbol_mutable_location))
5d3e2388
DH
2010 return SCM_ENVIRONMENT_SET (body->private, sym, val);
2011 else
2012 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
2013 }
2014}
2015#undef FUNC_NAME
2016
2017
2018static SCM
2019export_environment_cell (SCM env, SCM sym, int for_write)
2020#define FUNC_NAME "export_environment_cell"
2021{
2022 struct export_environment *body = EXPORT_ENVIRONMENT (env);
2023 SCM entry = scm_assq (sym, body->signature);
2024
7888309b 2025 if (scm_is_false (entry))
5d3e2388
DH
2026 {
2027 return SCM_UNDEFINED;
2028 }
2029 else
2030 {
bc36d050 2031 if (!for_write || scm_is_eq (SCM_CADR (entry), symbol_mutable_location))
5d3e2388
DH
2032 return SCM_ENVIRONMENT_CELL (body->private, sym, for_write);
2033 else
2034 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE;
2035 }
2036}
2037#undef FUNC_NAME
2038
2039
2040static SCM
e841c3e0 2041export_environment_mark (SCM env)
5d3e2388
DH
2042{
2043 struct export_environment *body = EXPORT_ENVIRONMENT (env);
2044
2045 scm_gc_mark (body->private);
2046 scm_gc_mark (body->private_observer);
2047 scm_gc_mark (body->signature);
2048
2049 return core_environments_mark (env);
2050}
2051
2052
4c9419ac 2053static void
e841c3e0 2054export_environment_free (SCM env)
5d3e2388
DH
2055{
2056 core_environments_finalize (env);
4c9419ac
MV
2057 scm_gc_free (EXPORT_ENVIRONMENT (env), sizeof (struct export_environment),
2058 "export environment");
5d3e2388
DH
2059}
2060
2061
2062static int
e81d98ec
DH
2063export_environment_print (SCM type, SCM port,
2064 scm_print_state *pstate SCM_UNUSED)
5d3e2388 2065{
b9bd8526 2066 SCM address = scm_from_size_t (SCM_UNPACK (type));
e11e83f3 2067 SCM base16 = scm_number_to_string (address, scm_from_int (16));
5d3e2388
DH
2068
2069 scm_puts ("#<export environment ", port);
18f9d343 2070 scm_display (base16, port);
5d3e2388
DH
2071 scm_puts (">", port);
2072
2073 return 1;
2074}
2075
2076
2077static struct scm_environment_funcs export_environment_funcs = {
2078 export_environment_ref,
2079 export_environment_fold,
2080 export_environment_define,
2081 export_environment_undefine,
2082 export_environment_set_x,
2083 export_environment_cell,
2084 core_environments_observe,
2085 core_environments_unobserve,
e841c3e0
KN
2086 export_environment_mark,
2087 export_environment_free,
2088 export_environment_print
5d3e2388
DH
2089};
2090
2091
2092void *scm_type_export_environment = &export_environment_funcs;
2093
2094
2095static void
e81d98ec 2096export_environment_observer (SCM caller SCM_UNUSED, SCM export_env)
5d3e2388
DH
2097{
2098 core_environments_broadcast (export_env);
2099}
2100
2101
2102SCM_DEFINE (scm_make_export_environment, "make-export-environment", 2, 0, 0,
2103 (SCM private, SCM signature),
0fb104ed
MG
2104 "Return a new environment @var{exp} containing only those\n"
2105 "bindings in private whose symbols are present in\n"
2106 "@var{signature}. The @var{private} argument must be an\n"
2107 "environment.\n\n"
2108 "The environment @var{exp} binds symbol to location when\n"
2109 "@var{env} does, and symbol is exported by @var{signature}.\n\n"
2110 "@var{signature} is a list specifying which of the bindings in\n"
2111 "@var{private} should be visible in @var{exp}. Each element of\n"
2112 "@var{signature} should be a list of the form:\n"
5d3e2388
DH
2113 " (symbol attribute ...)\n"
2114 "where each attribute is one of the following:\n"
0fb104ed
MG
2115 "@table @asis\n"
2116 "@item the symbol @code{mutable-location}\n"
2117 " @var{exp} should treat the\n"
2118 " location bound to symbol as mutable. That is, @var{exp}\n"
2119 " will pass calls to @code{environment-set!} or\n"
2120 " @code{environment-cell} directly through to private.\n"
2121 "@item the symbol @code{immutable-location}\n"
2122 " @var{exp} should treat\n"
2123 " the location bound to symbol as immutable. If the program\n"
2124 " applies @code{environment-set!} to @var{exp} and symbol, or\n"
2125 " calls @code{environment-cell} to obtain a writable value\n"
2126 " cell, @code{environment-set!} will signal an\n"
2127 " @code{environment:immutable-location} error. Note that, even\n"
2128 " if an export environment treats a location as immutable, the\n"
5d3e2388
DH
2129 " underlying environment may treat it as mutable, so its\n"
2130 " value may change.\n"
0fb104ed 2131 "@end table\n"
5d3e2388 2132 "It is an error for an element of signature to specify both\n"
0fb104ed
MG
2133 "@code{mutable-location} and @code{immutable-location}. If\n"
2134 "neither is specified, @code{immutable-location} is assumed.\n\n"
5d3e2388 2135 "As a special case, if an element of signature is a lone\n"
0fb104ed
MG
2136 "symbol @var{sym}, it is equivalent to an element of the form\n"
2137 "@code{(sym)}.\n\n"
2138 "All bindings in @var{exp} are immutable. If you apply\n"
2139 "@code{environment-define} or @code{environment-undefine} to\n"
2140 "@var{exp}, Guile will signal an\n"
2141 "@code{environment:immutable-binding} error. However,\n"
2142 "notice that the set of bindings in @var{exp} may still change,\n"
2143 "if the bindings in private change.")
5d3e2388
DH
2144#define FUNC_NAME s_scm_make_export_environment
2145{
1be6b49c 2146 size_t size;
5d3e2388
DH
2147 struct export_environment *body;
2148 SCM env;
2149
2150 SCM_ASSERT (SCM_ENVIRONMENT_P (private), private, SCM_ARG1, FUNC_NAME);
2151
2152 size = sizeof (struct export_environment);
4c9419ac 2153 body = scm_gc_malloc (size, "export environment");
5d3e2388
DH
2154
2155 core_environments_preinit (&body->base);
2156 body->private = SCM_BOOL_F;
2157 body->private_observer = SCM_BOOL_F;
2158 body->signature = SCM_BOOL_F;
2159
2160 env = scm_make_environment (body);
2161
2162 core_environments_init (&body->base, &export_environment_funcs);
2163 body->private = private;
2164 body->private_observer
2165 = SCM_ENVIRONMENT_OBSERVE (private, export_environment_observer, env, 1);
2166 body->signature = SCM_EOL;
2167
2168 scm_export_environment_set_signature_x (env, signature);
2169
2170 return env;
2171}
2172#undef FUNC_NAME
2173
2174
2175SCM_DEFINE (scm_export_environment_p, "export-environment?", 1, 0, 0,
2176 (SCM object),
0fb104ed
MG
2177 "Return @code{#t} if object is an export environment, or\n"
2178 "@code{#f} otherwise.")
5d3e2388
DH
2179#define FUNC_NAME s_scm_export_environment_p
2180{
7888309b 2181 return scm_from_bool (SCM_EXPORT_ENVIRONMENT_P (object));
5d3e2388
DH
2182}
2183#undef FUNC_NAME
2184
2185
2186SCM_DEFINE (scm_export_environment_private, "export-environment-private", 1, 0, 0,
2187 (SCM env),
0fb104ed 2188 "Return the private environment of export environment @var{env}.")
5d3e2388
DH
2189#define FUNC_NAME s_scm_export_environment_private
2190{
2191 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2192
2193 return EXPORT_ENVIRONMENT (env)->private;
2194}
2195#undef FUNC_NAME
2196
2197
2198SCM_DEFINE (scm_export_environment_set_private_x, "export-environment-set-private!", 2, 0, 0,
2199 (SCM env, SCM private),
0fb104ed 2200 "Change the private environment of export environment @var{env}.")
5d3e2388
DH
2201#define FUNC_NAME s_scm_export_environment_set_private_x
2202{
2203 struct export_environment *body;
2204
2205 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2206 SCM_ASSERT (SCM_ENVIRONMENT_P (private), private, SCM_ARG2, FUNC_NAME);
2207
2208 body = EXPORT_ENVIRONMENT (env);
2209 SCM_ENVIRONMENT_UNOBSERVE (private, body->private_observer);
2210
2211 body->private = private;
2212 body->private_observer
2213 = SCM_ENVIRONMENT_OBSERVE (private, export_environment_observer, env, 1);
2214
2215 return SCM_UNSPECIFIED;
2216}
2217#undef FUNC_NAME
2218
2219
2220SCM_DEFINE (scm_export_environment_signature, "export-environment-signature", 1, 0, 0,
2221 (SCM env),
0fb104ed 2222 "Return the signature of export environment @var{env}.")
5d3e2388
DH
2223#define FUNC_NAME s_scm_export_environment_signature
2224{
2225 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2226
2227 return EXPORT_ENVIRONMENT (env)->signature;
2228}
2229#undef FUNC_NAME
2230
2231
2232static SCM
2233export_environment_parse_signature (SCM signature, const char* caller)
2234{
2235 SCM result = SCM_EOL;
2236 SCM l;
2237
2238 for (l = signature; SCM_CONSP (l); l = SCM_CDR (l))
2239 {
2240 SCM entry = SCM_CAR (l);
2241
cc95e00a 2242 if (scm_is_symbol (entry))
5d3e2388
DH
2243 {
2244 SCM new_entry = scm_cons2 (entry, symbol_immutable_location, SCM_EOL);
2245 result = scm_cons (new_entry, result);
2246 }
2247 else
2248 {
2249 SCM sym;
2250 SCM new_entry;
2251 int immutable = 0;
2252 int mutable = 0;
2253 SCM mutability;
2254 SCM l2;
2255
2256 SCM_ASSERT (SCM_CONSP (entry), entry, SCM_ARGn, caller);
cc95e00a 2257 SCM_ASSERT (scm_is_symbol (SCM_CAR (entry)), entry, SCM_ARGn, caller);
5d3e2388
DH
2258
2259 sym = SCM_CAR (entry);
2260
2261 for (l2 = SCM_CDR (entry); SCM_CONSP (l2); l2 = SCM_CDR (l2))
2262 {
2263 SCM attribute = SCM_CAR (l2);
bc36d050 2264 if (scm_is_eq (attribute, symbol_immutable_location))
5d3e2388 2265 immutable = 1;
bc36d050 2266 else if (scm_is_eq (attribute, symbol_mutable_location))
5d3e2388
DH
2267 mutable = 1;
2268 else
2269 SCM_ASSERT (0, entry, SCM_ARGn, caller);
2270 }
2271 SCM_ASSERT (SCM_NULLP (l2), entry, SCM_ARGn, caller);
2272 SCM_ASSERT (!mutable || !immutable, entry, SCM_ARGn, caller);
2273
2274 if (!mutable && !immutable)
2275 immutable = 1;
2276
2277 mutability = mutable ? symbol_mutable_location : symbol_immutable_location;
2278 new_entry = scm_cons2 (sym, mutability, SCM_EOL);
2279 result = scm_cons (new_entry, result);
2280 }
2281 }
2282 SCM_ASSERT (SCM_NULLP (l), signature, SCM_ARGn, caller);
2283
2284 /* Dirk:FIXME:: Now we know that signature is syntactically correct. There
2285 * are, however, no checks for symbols entered twice with contradicting
2286 * mutabilities. It would be nice, to implement this test, to be able to
2287 * call the sort functions conveniently from C.
2288 */
2289
2290 return scm_reverse (result);
2291}
2292
2293
2294SCM_DEFINE (scm_export_environment_set_signature_x, "export-environment-set-signature!", 2, 0, 0,
2295 (SCM env, SCM signature),
0fb104ed 2296 "Change the signature of export environment @var{env}.")
5d3e2388
DH
2297#define FUNC_NAME s_scm_export_environment_set_signature_x
2298{
2299 SCM parsed_sig;
2300
2301 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env), env, SCM_ARG1, FUNC_NAME);
2302 parsed_sig = export_environment_parse_signature (signature, FUNC_NAME);
2303
2304 EXPORT_ENVIRONMENT (env)->signature = parsed_sig;
2305
2306 return SCM_UNSPECIFIED;
2307}
2308#undef FUNC_NAME
2309
2310\f
2311
2312void
2313scm_environments_prehistory ()
2314{
2315 /* create environment smob */
2316 scm_tc16_environment = scm_make_smob_type ("environment", 0);
e841c3e0
KN
2317 scm_set_smob_mark (scm_tc16_environment, environment_mark);
2318 scm_set_smob_free (scm_tc16_environment, environment_free);
2319 scm_set_smob_print (scm_tc16_environment, environment_print);
5d3e2388
DH
2320
2321 /* create observer smob */
2322 scm_tc16_observer = scm_make_smob_type ("observer", 0);
e841c3e0
KN
2323 scm_set_smob_mark (scm_tc16_observer, observer_mark);
2324 scm_set_smob_print (scm_tc16_observer, observer_print);
de42a0ee
DH
2325
2326 /* create system environment */
2327 scm_system_environment = scm_make_leaf_environment ();
2328 scm_permanent_object (scm_system_environment);
5d3e2388
DH
2329}
2330
2331
2332void
2333scm_init_environments ()
2334{
480a873c 2335#include "libguile/environments.x"
5d3e2388
DH
2336}
2337
2338
2339/*
2340 Local Variables:
2341 c-file-style: "gnu"
2342 End:
2343*/