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