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