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