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