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