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