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