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