1 /* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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)
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.
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
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
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.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
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.
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. */
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"
55 #include "libguile/environments.h"
59 long scm_tc16_environment
;
60 long scm_tc16_observer
;
64 /* error conditions */
67 * Throw an error if symbol is not bound in environment func
70 scm_error_environment_unbound (const char *func
, SCM env
, SCM symbol
)
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
);
80 * Throw an error if func tried to create (define) or remove
81 * (undefine) a new binding for symbol in env
84 scm_error_environment_immutable_binding (const char *func
, SCM env
, SCM symbol
)
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
);
94 * Throw an error if func tried to change an immutable location.
97 scm_error_environment_immutable_location (const char *func
, SCM env
, SCM symbol
)
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
);
107 /* generic environments */
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.
117 scm_make_environment (void *type
)
122 SCM_SET_CELL_WORD_1 (env
, type
);
123 SCM_SET_CELL_TYPE (env
, scm_tc16_environment
);
129 SCM_DEFINE (scm_environment_p
, "environment?", 1, 0, 0,
131 "Return #t if OBJ is an environment, or #f otherwise.")
132 #define FUNC_NAME s_scm_environment_p
134 return SCM_BOOL (SCM_ENVIRONMENT_P (obj
));
139 SCM_DEFINE (scm_environment_bound_p
, "environment-bound?", 2, 0, 0,
141 "Return #t if SYM is bound in ENV, or #f otherwise.")
142 #define FUNC_NAME s_scm_environment_bound_p
144 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
145 SCM_ASSERT (SCM_SYMBOLP (sym
), sym
, SCM_ARG2
, FUNC_NAME
);
147 return SCM_BOOL (SCM_ENVIRONMENT_BOUND_P (env
, sym
));
152 SCM_DEFINE (scm_environment_ref
, "environment-ref", 2, 0, 0,
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"
157 #define FUNC_NAME s_scm_environment_ref
161 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
162 SCM_ASSERT (SCM_SYMBOLP (sym
), sym
, SCM_ARG2
, FUNC_NAME
);
164 val
= SCM_ENVIRONMENT_REF (env
, sym
);
166 if (!SCM_UNBNDP (val
))
169 scm_error_environment_unbound (FUNC_NAME
, env
, sym
);
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
179 scm_c_environment_ref (SCM env
, SCM sym
)
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
);
188 environment_default_folder (SCM proc
, SCM symbol
, SCM value
, SCM tail
)
190 return gh_call3 (proc
, symbol
, value
, tail
);
194 SCM_DEFINE (scm_environment_fold
, "environment-fold", 3, 0, 0,
195 (SCM env
, SCM proc
, SCM init
),
196 "Iterate over all the bindings in ENV, accumulating some value.\n"
197 "For each binding in ENV, apply PROC to the symbol bound, its\n"
198 "value, and the result from the previous application of PROC.\n"
199 "Use INIT as PROC's third argument the first time PROC is\n"
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"
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"
220 #define FUNC_NAME s_scm_environment_fold
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
);
226 return SCM_ENVIRONMENT_FOLD (env
, environment_default_folder
, proc
, init
);
231 /* This is the C-level analog of environment-fold. For each binding in ENV,
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.
238 scm_c_environment_fold (SCM env
, scm_environment_folder proc
, SCM data
, SCM init
)
240 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, "scm_c_environment_fold");
242 return SCM_ENVIRONMENT_FOLD (env
, proc
, data
, init
);
246 SCM_DEFINE (scm_environment_define
, "environment-define", 3, 0, 0,
247 (SCM env
, SCM sym
, SCM val
),
248 "Bind SYM to a new location containing VAL in ENV. If SYM is\n"
249 "already bound to another location in ENV and the binding is\n"
250 "mutable, that binding is replaced. The new binding and\n"
251 "location are both mutable. The return value is unspecified.\n"
252 "If SYM is already bound in ENV, and the binding is immutable,\n"
253 "signal an environment:immutable-binding error.")
254 #define FUNC_NAME s_scm_environment_define
258 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
259 SCM_ASSERT (SCM_SYMBOLP (sym
), sym
, SCM_ARG2
, FUNC_NAME
);
261 status
= SCM_ENVIRONMENT_DEFINE (env
, sym
, val
);
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
);
273 SCM_DEFINE (scm_environment_undefine
, "environment-undefine", 2, 0, 0,
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
283 SCM_ASSERT(SCM_ENVIRONMENT_P(env
), env
, SCM_ARG1
, FUNC_NAME
);
284 SCM_ASSERT(SCM_SYMBOLP(sym
), sym
, SCM_ARG2
, FUNC_NAME
);
286 status
= SCM_ENVIRONMENT_UNDEFINE (env
, sym
);
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
);
298 SCM_DEFINE (scm_environment_set_x
, "environment-set!", 3, 0, 0,
299 (SCM env
, SCM sym
, SCM val
),
300 "If ENV binds SYM to some location, change that location's\n"
301 "value to VAL. The return value is unspecified.\n"
302 "If SYM is not bound in ENV, signal an environment:unbound\n"
303 "error. If ENV binds SYM to an immutable location, signal an\n"
304 "environment:immutable-location error.")
305 #define FUNC_NAME s_scm_environment_set_x
309 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
310 SCM_ASSERT (SCM_SYMBOLP (sym
), sym
, SCM_ARG2
, FUNC_NAME
);
312 status
= SCM_ENVIRONMENT_SET (env
, sym
, val
);
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
);
326 SCM_DEFINE (scm_environment_cell
, "environment-cell", 3, 0, 0,
327 (SCM env
, SCM sym
, SCM for_write
),
328 "Return the value cell which ENV binds to SYM, or #f if the\n"
329 "binding does not live in a value cell.\n"
330 "The argument FOR-WRITE indicates whether the caller intends\n"
331 "to modify the variable's value by mutating the value cell. If\n"
332 "the variable is immutable, then environment-cell signals an\n"
333 "environment:immutable-location error.\n"
334 "If SYM is unbound in ENV, signal an environment:unbound error.\n"
335 "If you use this function, you should consider using\n"
336 "environment-observe, to be notified when SYM gets re-bound to\n"
337 "a new value cell, or becomes undefined.")
338 #define FUNC_NAME s_scm_environment_cell
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
);
346 location
= SCM_ENVIRONMENT_CELL (env
, sym
, !SCM_FALSEP (for_write
));
347 if (!SCM_IMP (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
);
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.
366 scm_c_environment_cell(SCM env
, SCM sym
, int for_write
)
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");
371 return SCM_ENVIRONMENT_CELL (env
, sym
, for_write
);
376 environment_default_observer (SCM env
, SCM proc
)
378 gh_call1 (proc
, env
);
382 SCM_DEFINE (scm_environment_observe
, "environment-observe", 2, 0, 0,
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"
389 #define FUNC_NAME s_scm_environment_observe
391 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
393 return SCM_ENVIRONMENT_OBSERVE (env
, environment_default_observer
, proc
, 0);
398 SCM_DEFINE (scm_environment_observe_weak
, "environment-observe-weak", 2, 0, 0,
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
407 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
409 return SCM_ENVIRONMENT_OBSERVE (env
, environment_default_observer
, proc
, 1);
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.
423 scm_c_environment_observe (SCM env
, scm_environment_observer proc
, SCM data
, int weak_p
)
424 #define FUNC_NAME "scm_c_environment_observe"
426 SCM_ASSERT (SCM_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
428 return SCM_ENVIRONMENT_OBSERVE (env
, proc
, data
, weak_p
);
433 SCM_DEFINE (scm_environment_unobserve
, "environment-unobserve", 1, 0, 0,
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
444 SCM_ASSERT (SCM_OBSERVER_P (token
), token
, SCM_ARG1
, FUNC_NAME
);
446 env
= SCM_OBSERVER_ENVIRONMENT (token
);
447 SCM_ENVIRONMENT_UNOBSERVE (env
, token
);
449 return SCM_UNSPECIFIED
;
455 mark_environment (SCM env
)
457 return (*(SCM_ENVIRONMENT_FUNCS (env
)->mark
)) (env
);
462 free_environment (SCM env
)
464 return (*(SCM_ENVIRONMENT_FUNCS (env
)->free
)) (env
);
469 print_environment (SCM env
, SCM port
, scm_print_state
*pstate
)
471 return (*(SCM_ENVIRONMENT_FUNCS (env
)->print
)) (env
, port
, pstate
);
479 mark_observer (SCM observer
)
481 scm_gc_mark (SCM_OBSERVER_ENVIRONMENT (observer
));
482 scm_gc_mark (SCM_OBSERVER_DATA (observer
));
488 free_observer (SCM observer_smob
)
495 print_observer (SCM type
, SCM port
, scm_print_state
*pstate
)
497 SCM address
= scm_ulong2num (SCM_UNPACK (type
));
498 SCM base16
= scm_number_to_string (address
, SCM_MAKINUM (16));
500 scm_puts ("#<observer ", port
);
501 scm_puts (SCM_CHARS (base16
), port
);
502 scm_puts (">", port
);
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.
518 * Copy symbol to obarray. The symbol must not already exist in obarray.
521 obarray_enter (SCM obarray
, SCM symbol
, SCM data
)
523 scm_sizet hash
= SCM_SYMBOL_HASH (symbol
);
524 SCM entry
= scm_cons (symbol
, data
);
525 SCM slot
= scm_cons (entry
, SCM_VELTS (obarray
)[hash
]);
526 SCM_VELTS (obarray
)[hash
] = slot
;
533 * Look up symbol in obarray
536 obarray_retrieve (SCM obarray
, SCM sym
)
538 scm_sizet hash
= SCM_SYMBOL_HASH (sym
);
541 for (lsym
= SCM_VELTS (obarray
)[hash
]; !SCM_NULLP (lsym
); lsym
= SCM_CDR (lsym
))
543 SCM entry
= SCM_CAR (lsym
);
544 if (SCM_CAR (entry
) == sym
)
548 return SCM_UNDEFINED
;
553 * remove entry from obarray
556 obarray_remove (SCM obarray
, SCM sym
)
558 scm_sizet hash
= SCM_SYMBOL_HASH (sym
);
562 /* Dirk:FIXME:: gc problem due to use of &SCM_VELTS[hash] */
563 for (lsym
= *(lsymp
= &SCM_VELTS (obarray
)[hash
]);
565 lsym
= *(lsymp
= SCM_CDRLOC (lsym
)))
567 SCM entry
= SCM_CAR (lsym
);
568 if (SCM_CAR (entry
) == sym
)
570 *lsymp
= SCM_CDR (lsym
);
579 obarray_remove_all (SCM obarray
)
581 scm_sizet size
= SCM_LENGTH (obarray
);
584 for (i
= 0; i
< size
; i
++)
586 SCM_VELTS (obarray
)[i
] = SCM_EOL
;
592 /* core environments base
594 * This struct and the corresponding functions form a base class for guile's
595 * built-in environment types.
599 struct core_environments_base
{
600 struct scm_environment_funcs
*funcs
;
607 #define CORE_ENVIRONMENTS_BASE(env) \
608 ((struct core_environments_base *) SCM_CELL_WORD_1 (env))
609 #define CORE_ENVIRONMENT_OBSERVERS(env) \
610 (CORE_ENVIRONMENTS_BASE (env)->observers)
611 #define SCM_SET_CORE_ENVIRONMENT_OBSERVERS(env, v) \
612 (CORE_ENVIRONMENT_OBSERVERS (env) = (v))
613 #define CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR(env) \
614 (CORE_ENVIRONMENTS_BASE (env)->weak_observers)
615 #define CORE_ENVIRONMENT_WEAK_OBSERVERS(env) \
616 (SCM_VELTS (CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env)) [0])
617 #define SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS(env, v) \
618 (SCM_VELTS (CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env)) [0] = (v))
623 core_environments_observe (SCM env
, scm_environment_observer proc
, SCM data
, int weak_p
)
627 SCM_NEWCELL2 (observer
);
628 SCM_SET_CELL_OBJECT_1 (observer
, env
);
629 SCM_SET_CELL_OBJECT_2 (observer
, data
);
630 SCM_SET_CELL_WORD_3 (observer
, proc
);
631 SCM_SET_CELL_TYPE (observer
, scm_tc16_observer
);
635 SCM observers
= CORE_ENVIRONMENT_OBSERVERS (env
);
636 SCM new_observers
= scm_cons (observer
, observers
);
637 SCM_SET_CORE_ENVIRONMENT_OBSERVERS (env
, new_observers
);
641 SCM observers
= CORE_ENVIRONMENT_WEAK_OBSERVERS (env
);
642 SCM new_observers
= scm_acons (SCM_BOOL_F
, observer
, observers
);
643 SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS (env
, new_observers
);
651 core_environments_unobserve (SCM env
, SCM observer
)
653 unsigned int handling_weaks
;
654 for (handling_weaks
= 0; handling_weaks
<= 1; ++handling_weaks
)
656 SCM l
= handling_weaks
657 ? CORE_ENVIRONMENT_WEAK_OBSERVERS (env
)
658 : CORE_ENVIRONMENT_OBSERVERS (env
);
662 SCM rest
= SCM_CDR (l
);
663 SCM first
= handling_weaks
667 if (SCM_EQ_P (first
, observer
))
669 /* Remove the first observer */
671 ? SCM_SET_CORE_ENVIRONMENT_WEAK_OBSERVERS (env
, rest
)
672 : SCM_SET_CORE_ENVIRONMENT_OBSERVERS (env
, rest
);
677 SCM rest
= SCM_CDR (l
);
679 if (!SCM_NULLP (rest
))
681 SCM next
= handling_weaks
685 if (SCM_EQ_P (next
, observer
))
687 SCM_SETCDR (l
, SCM_CDR (rest
));
693 } while (!SCM_NULLP (l
));
697 /* Dirk:FIXME:: What to do now, since the observer is not found? */
702 core_environments_mark (SCM env
)
704 scm_gc_mark (CORE_ENVIRONMENT_OBSERVERS (env
));
705 return CORE_ENVIRONMENT_WEAK_OBSERVER_VECTOR (env
);
710 core_environments_finalize (SCM env
)
716 core_environments_preinit (struct core_environments_base
*body
)
719 body
->observers
= SCM_BOOL_F
;
720 body
->weak_observers
= SCM_BOOL_F
;
725 core_environments_init (struct core_environments_base
*body
,
726 struct scm_environment_funcs
*funcs
)
729 body
->observers
= SCM_EOL
;
730 body
->weak_observers
= scm_make_weak_value_hash_table (SCM_MAKINUM (1));
734 /* Tell all observers to clear their caches.
736 * Environments have to be informed about changes in the following cases:
737 * - The observed env has a new binding. This must be always reported.
738 * - The observed env has dropped a binding. This must be always reported.
739 * - A binding in the observed environment has changed. This must only be
740 * reported, if there is a chance that the binding is being cached outside.
741 * However, this potential optimization is not performed currently.
743 * Errors that occur while the observers are called are accumulated and
744 * signalled as one single error message to the caller.
755 update_catch_body (void *ptr
)
757 struct update_data
*data
= (struct update_data
*) ptr
;
758 SCM observer
= data
->observer
;
760 (*SCM_OBSERVER_PROC (observer
))
761 (data
->environment
, SCM_OBSERVER_DATA (observer
));
763 return SCM_UNDEFINED
;
768 update_catch_handler (void *ptr
, SCM tag
, SCM args
)
770 struct update_data
*data
= (struct update_data
*) ptr
;
771 SCM observer
= data
->observer
;
772 SCM message
= scm_makfrom0str ("Observer `~A' signals `~A' error: ~S");
774 return scm_cons (message
, scm_listify (observer
, tag
, args
, SCM_UNDEFINED
));
779 core_environments_broadcast (SCM env
)
780 #define FUNC_NAME "core_environments_broadcast"
782 unsigned int handling_weaks
;
783 SCM errors
= SCM_EOL
;
785 for (handling_weaks
= 0; handling_weaks
<= 1; ++handling_weaks
)
787 SCM observers
= handling_weaks
788 ? CORE_ENVIRONMENT_WEAK_OBSERVERS (env
)
789 : CORE_ENVIRONMENT_OBSERVERS (env
);
791 for (; !SCM_NULLP (observers
); observers
= SCM_CDR (observers
))
793 struct update_data data
;
794 SCM observer
= handling_weaks
795 ? SCM_CDAR (observers
)
796 : SCM_CAR (observers
);
799 data
.observer
= observer
;
800 data
.environment
= env
;
802 error
= scm_internal_catch (SCM_BOOL_T
,
803 update_catch_body
, &data
,
804 update_catch_handler
, &data
);
806 if (!SCM_UNBNDP (error
))
807 errors
= scm_cons (error
, errors
);
811 if (!SCM_NULLP (errors
))
813 /* Dirk:FIXME:: As soon as scm_misc_error is fixed to handle the name
814 * parameter correctly it should not be necessary any more to also pass
815 * namestr in order to get the desired information from the error
818 SCM ordered_errors
= scm_reverse (errors
);
821 "Observers of `~A' have signalled the following errors: ~S",
822 scm_cons2 (env
, ordered_errors
, SCM_EOL
));
831 * A leaf environment is simply a mutable set of definitions. A leaf
832 * environment supports no operations beyond the common set.
834 * Implementation: The obarray of the leaf environment holds (symbol . value)
835 * pairs. No further information is necessary, since all bindings and
836 * locations in a leaf environment are mutable.
840 struct leaf_environment
{
841 struct core_environments_base base
;
847 #define LEAF_ENVIRONMENT(env) \
848 ((struct leaf_environment *) SCM_CELL_WORD_1 (env))
853 leaf_environment_ref (SCM env
, SCM sym
)
855 SCM obarray
= LEAF_ENVIRONMENT (env
)->obarray
;
856 SCM binding
= obarray_retrieve (obarray
, sym
);
857 return SCM_UNBNDP (binding
) ? binding
: SCM_CDR (binding
);
862 leaf_environment_fold (SCM env
, scm_environment_folder proc
, SCM data
, SCM init
)
866 SCM obarray
= LEAF_ENVIRONMENT (env
)->obarray
;
868 for (i
= 0; i
< SCM_LENGTH (obarray
); i
++)
871 for (l
= SCM_VELTS (obarray
)[i
]; !SCM_NULLP (l
); l
= SCM_CDR (l
))
873 SCM binding
= SCM_CAR (l
);
874 SCM symbol
= SCM_CAR (binding
);
875 SCM value
= SCM_CDR (binding
);
876 result
= (*proc
) (data
, symbol
, value
, result
);
884 leaf_environment_define (SCM env
, SCM sym
, SCM val
)
885 #define FUNC_NAME "leaf_environment_define"
887 SCM obarray
= LEAF_ENVIRONMENT (env
)->obarray
;
888 SCM old_binding
= obarray_retrieve (obarray
, sym
);
891 if (!SCM_UNBNDP (old_binding
))
892 obarray_remove (obarray
, sym
);
894 new_binding
= obarray_enter (obarray
, sym
, val
);
895 core_environments_broadcast (env
);
897 return SCM_ENVIRONMENT_SUCCESS
;
903 leaf_environment_undefine (SCM env
, SCM sym
)
904 #define FUNC_NAME "leaf_environment_undefine"
906 SCM obarray
= LEAF_ENVIRONMENT (env
)->obarray
;
907 SCM binding
= obarray_retrieve (obarray
, sym
);
909 if (!SCM_UNBNDP (binding
))
911 obarray_remove (obarray
, sym
);
912 core_environments_broadcast (env
);
915 return SCM_ENVIRONMENT_SUCCESS
;
921 leaf_environment_set_x (SCM env
, SCM sym
, SCM val
)
922 #define FUNC_NAME "leaf_environment_set_x"
924 SCM obarray
= LEAF_ENVIRONMENT (env
)->obarray
;
925 SCM binding
= obarray_retrieve (obarray
, sym
);
927 if (!SCM_UNBNDP (binding
))
929 SCM_SETCDR (binding
, val
);
930 return SCM_ENVIRONMENT_SUCCESS
;
934 return SCM_UNDEFINED
;
941 leaf_environment_cell(SCM env
, SCM sym
, int for_write
)
943 SCM obarray
= LEAF_ENVIRONMENT (env
)->obarray
;
944 SCM binding
= obarray_retrieve (obarray
, sym
);
950 mark_leaf_environment (SCM env
)
952 scm_gc_mark (LEAF_ENVIRONMENT (env
)->obarray
);
953 return core_environments_mark (env
);
958 free_leaf_environment (SCM env
)
960 core_environments_finalize (env
);
962 free (LEAF_ENVIRONMENT (env
));
963 return sizeof (struct leaf_environment
);
968 print_leaf_environment (SCM type
, SCM port
, scm_print_state
*pstate
)
970 SCM address
= scm_ulong2num (SCM_UNPACK (type
));
971 SCM base16
= scm_number_to_string (address
, SCM_MAKINUM (16));
973 scm_puts ("#<leaf environment ", port
);
974 scm_puts (SCM_CHARS (base16
), port
);
975 scm_puts (">", port
);
981 static struct scm_environment_funcs leaf_environment_funcs
= {
982 leaf_environment_ref
,
983 leaf_environment_fold
,
984 leaf_environment_define
,
985 leaf_environment_undefine
,
986 leaf_environment_set_x
,
987 leaf_environment_cell
,
988 core_environments_observe
,
989 core_environments_unobserve
,
990 mark_leaf_environment
,
991 free_leaf_environment
,
992 print_leaf_environment
996 void *scm_type_leaf_environment
= &leaf_environment_funcs
;
999 SCM_DEFINE (scm_make_leaf_environment
, "make-leaf-environment", 0, 0, 0,
1001 "Create a new leaf environment, containing no bindings.\n"
1002 "All bindings and locations created in the new environment\n"
1004 #define FUNC_NAME s_scm_make_leaf_environment
1006 scm_sizet size
= sizeof (struct leaf_environment
);
1007 struct leaf_environment
*body
= scm_must_malloc (size
, FUNC_NAME
);
1010 core_environments_preinit (&body
->base
);
1011 body
->obarray
= SCM_BOOL_F
;
1013 env
= scm_make_environment (body
);
1015 core_environments_init (&body
->base
, &leaf_environment_funcs
);
1016 body
->obarray
= scm_make_vector (SCM_MAKINUM (scm_symhash_dim
), SCM_EOL
);
1023 SCM_DEFINE (scm_leaf_environment_p
, "leaf-environment?", 1, 0, 0,
1025 "Return #t if object is a leaf environment, or #f otherwise.")
1026 #define FUNC_NAME s_scm_leaf_environment_p
1028 return SCM_BOOL (SCM_LEAF_ENVIRONMENT_P (object
));
1034 /* eval environments
1036 * A module's source code refers to definitions imported from other modules,
1037 * and definitions made within itself. An eval environment combines two
1038 * environments -- a local environment and an imported environment -- to
1039 * produce a new environment in which both sorts of references can be
1042 * Implementation: The obarray of the eval environment is used to cache
1043 * entries from the local and imported environments such that in most of the
1044 * cases only a single lookup is necessary. Since for neither the local nor
1045 * the imported environment it is known, what kind of environment they form,
1046 * the most general case is assumed. Therefore, entries in the obarray take
1047 * one of the following forms:
1049 * 1) (<symbol> location mutability . source-env), where mutability indicates
1050 * one of the following states: IMMUTABLE if the location is known to be
1051 * immutable, MUTABLE if the location is known to be mutable, UNKNOWN if
1052 * the location has only been requested for non modifying accesses.
1054 * 2) (symbol . source-env) if the symbol has a binding in the source-env, but
1055 * if the source-env can't provide a cell for the binding. Thus, for every
1056 * access, the source-env has to be contacted directly.
1060 struct eval_environment
{
1061 struct core_environments_base base
;
1066 SCM imported_observer
;
1072 #define EVAL_ENVIRONMENT(env) \
1073 ((struct eval_environment *) SCM_CELL_WORD_1 (env))
1075 #define IMMUTABLE SCM_MAKINUM (0)
1076 #define MUTABLE SCM_MAKINUM (1)
1077 #define UNKNOWN SCM_MAKINUM (2)
1079 #define CACHED_LOCATION(x) SCM_CAR (x)
1080 #define CACHED_MUTABILITY(x) SCM_CADR (x)
1081 #define SET_CACHED_MUTABILITY(x, v) SCM_SETCAR (SCM_CDR (x), (v))
1082 #define CACHED_SOURCE_ENVIRONMENT(x) SCM_CDDR (x)
1086 /* eval_environment_lookup will report one of the following distinct results:
1087 * a) (<object> . value) if a cell could be obtained.
1088 * b) <environment> if the environment has to be contacted directly.
1089 * c) IMMUTABLE if an immutable cell was requested for write.
1090 * d) SCM_UNDEFINED if there is no binding for the symbol.
1093 eval_environment_lookup (SCM env
, SCM sym
, int for_write
)
1095 SCM obarray
= EVAL_ENVIRONMENT (env
)->obarray
;
1096 SCM binding
= obarray_retrieve (obarray
, sym
);
1098 if (!SCM_UNBNDP (binding
))
1100 /* The obarray holds an entry for the symbol. */
1102 SCM entry
= SCM_CDR (binding
);
1104 if (SCM_CONSP (entry
))
1106 /* The entry in the obarray is a cached location. */
1108 SCM location
= CACHED_LOCATION (entry
);
1114 mutability
= CACHED_MUTABILITY (entry
);
1115 if (SCM_EQ_P (mutability
, MUTABLE
))
1118 if (SCM_EQ_P (mutability
, UNKNOWN
))
1120 SCM source_env
= CACHED_SOURCE_ENVIRONMENT (entry
);
1121 SCM location
= SCM_ENVIRONMENT_CELL (source_env
, sym
, 1);
1123 if (SCM_CONSP (location
))
1125 SET_CACHED_MUTABILITY (entry
, MUTABLE
);
1128 else /* IMMUTABLE */
1130 SET_CACHED_MUTABILITY (entry
, IMMUTABLE
);
1139 /* The obarray entry is an environment */
1146 /* There is no entry for the symbol in the obarray. This can either
1147 * mean that there has not been a request for the symbol yet, or that
1148 * the symbol is really undefined. We are looking for the symbol in
1149 * both the local and the imported environment. If we find a binding, a
1150 * cached entry is created.
1153 struct eval_environment
*body
= EVAL_ENVIRONMENT (env
);
1154 unsigned int handling_import
;
1156 for (handling_import
= 0; handling_import
<= 1; ++handling_import
)
1158 SCM source_env
= handling_import
? body
->imported
: body
->local
;
1159 SCM location
= SCM_ENVIRONMENT_CELL (source_env
, sym
, for_write
);
1161 if (!SCM_UNBNDP (location
))
1163 if (SCM_CONSP (location
))
1165 SCM mutability
= for_write
? MUTABLE
: UNKNOWN
;
1166 SCM entry
= scm_cons2 (location
, mutability
, source_env
);
1167 obarray_enter (obarray
, sym
, entry
);
1170 else if (SCM_EQ_P (location
, SCM_ENVIRONMENT_LOCATION_NO_CELL
))
1172 obarray_enter (obarray
, sym
, source_env
);
1182 return SCM_UNDEFINED
;
1188 eval_environment_ref (SCM env
, SCM sym
)
1189 #define FUNC_NAME "eval_environment_ref"
1191 SCM location
= eval_environment_lookup (env
, sym
, 0);
1193 if (SCM_CONSP (location
))
1194 return SCM_CDR (location
);
1195 else if (!SCM_UNBNDP (location
))
1196 return SCM_ENVIRONMENT_REF (location
, sym
);
1198 return SCM_UNDEFINED
;
1204 eval_environment_folder (SCM extended_data
, SCM symbol
, SCM value
, SCM tail
)
1206 SCM local
= SCM_CAR (extended_data
);
1208 if (!SCM_ENVIRONMENT_BOUND_P (local
, symbol
))
1210 SCM proc_as_nr
= SCM_CADR (extended_data
);
1211 unsigned long int proc_as_ul
= scm_num2ulong (proc_as_nr
, NULL
, NULL
);
1212 scm_environment_folder proc
= (scm_environment_folder
) proc_as_ul
;
1213 SCM data
= SCM_CDDR (extended_data
);
1215 return (*proc
) (data
, symbol
, value
, tail
);
1225 eval_environment_fold (SCM env
, scm_environment_folder proc
, SCM data
, SCM init
)
1227 SCM local
= EVAL_ENVIRONMENT (env
)->local
;
1228 SCM imported
= EVAL_ENVIRONMENT (env
)->imported
;
1229 SCM proc_as_nr
= scm_ulong2num ((unsigned long int) proc
);
1230 SCM extended_data
= scm_cons2 (local
, proc_as_nr
, data
);
1231 SCM tmp_result
= scm_c_environment_fold (imported
, eval_environment_folder
, extended_data
, init
);
1233 return scm_c_environment_fold (local
, proc
, data
, tmp_result
);
1238 eval_environment_define (SCM env
, SCM sym
, SCM val
)
1239 #define FUNC_NAME "eval_environment_define"
1241 SCM local
= EVAL_ENVIRONMENT (env
)->local
;
1242 return SCM_ENVIRONMENT_DEFINE (local
, sym
, val
);
1248 eval_environment_undefine (SCM env
, SCM sym
)
1249 #define FUNC_NAME "eval_environment_undefine"
1251 SCM local
= EVAL_ENVIRONMENT (env
)->local
;
1252 return SCM_ENVIRONMENT_UNDEFINE (local
, sym
);
1258 eval_environment_set_x (SCM env
, SCM sym
, SCM val
)
1259 #define FUNC_NAME "eval_environment_set_x"
1261 SCM location
= eval_environment_lookup (env
, sym
, 1);
1263 if (SCM_CONSP (location
))
1265 SCM_SETCDR (location
, val
);
1266 return SCM_ENVIRONMENT_SUCCESS
;
1268 else if (SCM_ENVIRONMENT_P (location
))
1270 return SCM_ENVIRONMENT_SET (location
, sym
, val
);
1272 else if (SCM_EQ_P (location
, IMMUTABLE
))
1274 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE
;
1278 return SCM_UNDEFINED
;
1285 eval_environment_cell (SCM env
, SCM sym
, int for_write
)
1286 #define FUNC_NAME "eval_environment_cell"
1288 SCM location
= eval_environment_lookup (env
, sym
, for_write
);
1290 if (SCM_CONSP (location
))
1292 else if (SCM_ENVIRONMENT_P (location
))
1293 return SCM_ENVIRONMENT_LOCATION_NO_CELL
;
1294 else if (SCM_EQ_P (location
, IMMUTABLE
))
1295 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE
;
1297 return SCM_UNDEFINED
;
1303 mark_eval_environment (SCM env
)
1305 struct eval_environment
*body
= EVAL_ENVIRONMENT (env
);
1307 scm_gc_mark (body
->obarray
);
1308 scm_gc_mark (body
->imported
);
1309 scm_gc_mark (body
->imported_observer
);
1310 scm_gc_mark (body
->local
);
1311 scm_gc_mark (body
->local_observer
);
1313 return core_environments_mark (env
);
1318 free_eval_environment (SCM env
)
1320 core_environments_finalize (env
);
1322 free (EVAL_ENVIRONMENT (env
));
1323 return sizeof (struct eval_environment
);
1328 print_eval_environment (SCM type
, SCM port
, scm_print_state
*pstate
)
1330 SCM address
= scm_ulong2num (SCM_UNPACK (type
));
1331 SCM base16
= scm_number_to_string (address
, SCM_MAKINUM (16));
1333 scm_puts ("#<eval environment ", port
);
1334 scm_puts (SCM_CHARS (base16
), port
);
1335 scm_puts (">", port
);
1341 static struct scm_environment_funcs eval_environment_funcs
= {
1342 eval_environment_ref
,
1343 eval_environment_fold
,
1344 eval_environment_define
,
1345 eval_environment_undefine
,
1346 eval_environment_set_x
,
1347 eval_environment_cell
,
1348 core_environments_observe
,
1349 core_environments_unobserve
,
1350 mark_eval_environment
,
1351 free_eval_environment
,
1352 print_eval_environment
1356 void *scm_type_eval_environment
= &eval_environment_funcs
;
1360 eval_environment_observer (SCM caller
, SCM eval_env
)
1362 SCM obarray
= EVAL_ENVIRONMENT (eval_env
)->obarray
;
1364 obarray_remove_all (obarray
);
1365 core_environments_broadcast (eval_env
);
1369 SCM_DEFINE (scm_make_eval_environment
, "make-eval-environment", 2, 0, 0,
1370 (SCM local
, SCM imported
),
1371 "Return a new environment object eval whose bindings are the\n"
1372 "union of the bindings in the environments local and imported,\n"
1373 "with bindings from local taking precedence. Definitions made\n"
1374 "in eval are placed in local.\n"
1375 "Applying environment-define or environment-undefine to eval\n"
1376 "has the same effect as applying the procedure to local.\n"
1377 "Note that eval incorporates local and imported by reference:\n"
1378 "If, after creating eval, the program changes the bindings of\n"
1379 "local or imported, those changes will be visible in eval.\n"
1380 "Since most Scheme evaluation takes place in eval environments,\n"
1381 "they transparenty cache the bindings received from local and\n"
1382 "imported. Thus, the first time the program looks up a symbol\n"
1383 "in eval, eval may make calls to local or imported to find\n"
1384 "their bindings, but subsequent references to that symbol will\n"
1385 "be as fast as references to bindings in finite environments.\n"
1386 "In typical use, local will be a finite environment, and\n"
1387 "imported will be an import environment")
1388 #define FUNC_NAME s_scm_make_eval_environment
1391 struct eval_environment
*body
;
1393 SCM_ASSERT (SCM_ENVIRONMENT_P (local
), local
, SCM_ARG1
, FUNC_NAME
);
1394 SCM_ASSERT (SCM_ENVIRONMENT_P (imported
), imported
, SCM_ARG2
, FUNC_NAME
);
1396 body
= scm_must_malloc (sizeof (struct eval_environment
), FUNC_NAME
);
1398 core_environments_preinit (&body
->base
);
1399 body
->obarray
= SCM_BOOL_F
;
1400 body
->imported
= SCM_BOOL_F
;
1401 body
->imported_observer
= SCM_BOOL_F
;
1402 body
->local
= SCM_BOOL_F
;
1403 body
->local_observer
= SCM_BOOL_F
;
1405 env
= scm_make_environment (body
);
1407 core_environments_init (&body
->base
, &eval_environment_funcs
);
1408 body
->obarray
= scm_make_vector (SCM_MAKINUM (scm_symhash_dim
), SCM_EOL
);
1409 body
->imported
= imported
;
1410 body
->imported_observer
1411 = SCM_ENVIRONMENT_OBSERVE (imported
, eval_environment_observer
, env
, 1);
1412 body
->local
= local
;
1413 body
->local_observer
1414 = SCM_ENVIRONMENT_OBSERVE (local
, eval_environment_observer
, env
, 1);
1421 SCM_DEFINE (scm_eval_environment_p
, "eval-environment?", 1, 0, 0,
1423 "Return #t if object is an eval environment, or #f otherwise.")
1424 #define FUNC_NAME s_scm_eval_environment_p
1426 return SCM_BOOL (SCM_EVAL_ENVIRONMENT_P (object
));
1431 SCM_DEFINE (scm_eval_environment_local
, "eval-environment-local", 1, 0, 0,
1433 "Return the local environment of eval environment env.")
1434 #define FUNC_NAME s_scm_eval_environment_local
1436 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
1438 return EVAL_ENVIRONMENT (env
)->local
;
1443 SCM_DEFINE (scm_eval_environment_set_local_x
, "eval-environment-set-local!", 2, 0, 0,
1444 (SCM env
, SCM local
),
1445 "Change env's local environment to LOCAL.")
1446 #define FUNC_NAME s_scm_eval_environment_set_local_x
1448 struct eval_environment
*body
;
1450 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
1451 SCM_ASSERT (SCM_ENVIRONMENT_P (local
), local
, SCM_ARG2
, FUNC_NAME
);
1453 body
= EVAL_ENVIRONMENT (env
);
1455 obarray_remove_all (body
->obarray
);
1456 SCM_ENVIRONMENT_UNOBSERVE (body
->local
, body
->local_observer
);
1458 body
->local
= local
;
1459 body
->local_observer
1460 = SCM_ENVIRONMENT_OBSERVE (local
, eval_environment_observer
, env
, 1);
1462 core_environments_broadcast (env
);
1464 return SCM_UNSPECIFIED
;
1469 SCM_DEFINE (scm_eval_environment_imported
, "eval-environment-imported", 1, 0, 0,
1471 "Return the imported environment of eval environment env.")
1472 #define FUNC_NAME s_scm_eval_environment_imported
1474 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
1476 return EVAL_ENVIRONMENT (env
)->imported
;
1481 SCM_DEFINE (scm_eval_environment_set_imported_x
, "eval-environment-set-imported!", 2, 0, 0,
1482 (SCM env
, SCM imported
),
1483 "Change env's imported environment to IMPORTED.")
1484 #define FUNC_NAME s_scm_eval_environment_set_imported_x
1486 struct eval_environment
*body
;
1488 SCM_ASSERT (SCM_EVAL_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
1489 SCM_ASSERT (SCM_ENVIRONMENT_P (imported
), imported
, SCM_ARG2
, FUNC_NAME
);
1491 body
= EVAL_ENVIRONMENT (env
);
1493 obarray_remove_all (body
->obarray
);
1494 SCM_ENVIRONMENT_UNOBSERVE (body
->imported
, body
->imported_observer
);
1496 body
->imported
= imported
;
1497 body
->imported_observer
1498 = SCM_ENVIRONMENT_OBSERVE (imported
, eval_environment_observer
, env
, 1);
1500 core_environments_broadcast (env
);
1502 return SCM_UNSPECIFIED
;
1508 /* import environments
1510 * An import environment combines the bindings of a set of argument
1511 * environments, and checks for naming clashes.
1513 * Implementation: The import environment does no caching at all. For every
1514 * access, the list of imported environments is scanned.
1518 struct import_environment
{
1519 struct core_environments_base base
;
1522 SCM import_observers
;
1528 #define IMPORT_ENVIRONMENT(env) \
1529 ((struct import_environment *) SCM_CELL_WORD_1 (env))
1533 /* Lookup will report one of the following distinct results:
1534 * a) <environment> if only environment binds the symbol.
1535 * b) (env-1 env-2 ...) for conflicting bindings in env-1, ...
1536 * c) SCM_UNDEFINED if there is no binding for the symbol.
1539 import_environment_lookup (SCM env
, SCM sym
)
1541 SCM imports
= IMPORT_ENVIRONMENT (env
)->imports
;
1542 SCM result
= SCM_UNDEFINED
;
1545 for (l
= imports
; !SCM_NULLP (l
); l
= SCM_CDR (l
))
1547 SCM imported
= SCM_CAR (l
);
1549 if (SCM_ENVIRONMENT_BOUND_P (imported
, sym
))
1551 if (SCM_UNBNDP (result
))
1553 else if (SCM_CONSP (result
))
1554 result
= scm_cons (imported
, result
);
1556 result
= scm_cons2 (imported
, result
, SCM_EOL
);
1560 if (SCM_CONSP (result
))
1561 return scm_reverse (result
);
1568 import_environment_conflict (SCM env
, SCM sym
, SCM imports
)
1570 SCM conflict_proc
= IMPORT_ENVIRONMENT (env
)->conflict_proc
;
1571 SCM args
= scm_cons2 (env
, sym
, scm_cons (imports
, SCM_EOL
));
1573 return scm_apply (conflict_proc
, args
, SCM_EOL
);
1578 import_environment_ref (SCM env
, SCM sym
)
1579 #define FUNC_NAME "import_environment_ref"
1581 SCM owner
= import_environment_lookup (env
, sym
);
1583 if (SCM_UNBNDP (owner
))
1585 return SCM_UNDEFINED
;
1587 else if (SCM_CONSP (owner
))
1589 SCM resolve
= import_environment_conflict (env
, sym
, owner
);
1591 if (SCM_ENVIRONMENT_P (resolve
))
1592 return SCM_ENVIRONMENT_REF (resolve
, sym
);
1594 return SCM_UNSPECIFIED
;
1598 return SCM_ENVIRONMENT_REF (owner
, sym
);
1605 import_environment_folder (SCM extended_data
, SCM symbol
, SCM value
, SCM tail
)
1606 #define FUNC_NAME "import_environment_fold"
1608 SCM import_env
= SCM_CAR (extended_data
);
1609 SCM imported_env
= SCM_CADR (extended_data
);
1610 SCM owner
= import_environment_lookup (import_env
, symbol
);
1611 SCM proc_as_nr
= SCM_CADDR (extended_data
);
1612 unsigned long int proc_as_ul
= scm_num2ulong (proc_as_nr
, NULL
, NULL
);
1613 scm_environment_folder proc
= (scm_environment_folder
) proc_as_ul
;
1614 SCM data
= SCM_CDDDR (extended_data
);
1616 if (SCM_CONSP (owner
) && SCM_EQ_P (SCM_CAR (owner
), imported_env
))
1617 owner
= import_environment_conflict (import_env
, symbol
, owner
);
1619 if (SCM_ENVIRONMENT_P (owner
))
1620 return (*proc
) (data
, symbol
, value
, tail
);
1621 else /* unresolved conflict */
1622 return (*proc
) (data
, symbol
, SCM_UNSPECIFIED
, tail
);
1628 import_environment_fold (SCM env
, scm_environment_folder proc
, SCM data
, SCM init
)
1630 SCM proc_as_nr
= scm_ulong2num ((unsigned long int) proc
);
1634 for (l
= IMPORT_ENVIRONMENT (env
)->imports
; !SCM_NULLP (l
); l
= SCM_CDR (l
))
1636 SCM imported_env
= SCM_CAR (l
);
1637 SCM extended_data
= scm_cons (env
, scm_cons2 (imported_env
, proc_as_nr
, data
));
1639 result
= scm_c_environment_fold (imported_env
, import_environment_folder
, extended_data
, result
);
1647 import_environment_define (SCM env
, SCM sym
, SCM val
)
1648 #define FUNC_NAME "import_environment_define"
1650 return SCM_ENVIRONMENT_BINDING_IMMUTABLE
;
1656 import_environment_undefine (SCM env
, SCM sym
)
1657 #define FUNC_NAME "import_environment_undefine"
1659 return SCM_ENVIRONMENT_BINDING_IMMUTABLE
;
1665 import_environment_set_x (SCM env
, SCM sym
, SCM val
)
1666 #define FUNC_NAME "import_environment_set_x"
1668 SCM owner
= import_environment_lookup (env
, sym
);
1670 if (SCM_UNBNDP (owner
))
1672 return SCM_UNDEFINED
;
1674 else if (SCM_CONSP (owner
))
1676 SCM resolve
= import_environment_conflict (env
, sym
, owner
);
1678 if (SCM_ENVIRONMENT_P (resolve
))
1679 return SCM_ENVIRONMENT_SET (resolve
, sym
, val
);
1681 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE
;
1685 return SCM_ENVIRONMENT_SET (owner
, sym
, val
);
1692 import_environment_cell (SCM env
, SCM sym
, int for_write
)
1693 #define FUNC_NAME "import_environment_cell"
1695 SCM owner
= import_environment_lookup (env
, sym
);
1697 if (SCM_UNBNDP (owner
))
1699 return SCM_UNDEFINED
;
1701 else if (SCM_CONSP (owner
))
1703 SCM resolve
= import_environment_conflict (env
, sym
, owner
);
1705 if (SCM_ENVIRONMENT_P (resolve
))
1706 return SCM_ENVIRONMENT_CELL (resolve
, sym
, for_write
);
1708 return SCM_ENVIRONMENT_LOCATION_NO_CELL
;
1712 return SCM_ENVIRONMENT_CELL (owner
, sym
, for_write
);
1719 mark_import_environment (SCM env
)
1721 scm_gc_mark (IMPORT_ENVIRONMENT (env
)->imports
);
1722 scm_gc_mark (IMPORT_ENVIRONMENT (env
)->import_observers
);
1723 scm_gc_mark (IMPORT_ENVIRONMENT (env
)->conflict_proc
);
1724 return core_environments_mark (env
);
1729 free_import_environment (SCM env
)
1731 core_environments_finalize (env
);
1733 free (IMPORT_ENVIRONMENT (env
));
1734 return sizeof (struct import_environment
);
1739 print_import_environment (SCM type
, SCM port
, scm_print_state
*pstate
)
1741 SCM address
= scm_ulong2num (SCM_UNPACK (type
));
1742 SCM base16
= scm_number_to_string (address
, SCM_MAKINUM (16));
1744 scm_puts ("#<import environment ", port
);
1745 scm_puts (SCM_CHARS (base16
), port
);
1746 scm_puts (">", port
);
1752 static struct scm_environment_funcs import_environment_funcs
= {
1753 import_environment_ref
,
1754 import_environment_fold
,
1755 import_environment_define
,
1756 import_environment_undefine
,
1757 import_environment_set_x
,
1758 import_environment_cell
,
1759 core_environments_observe
,
1760 core_environments_unobserve
,
1761 mark_import_environment
,
1762 free_import_environment
,
1763 print_import_environment
1767 void *scm_type_import_environment
= &import_environment_funcs
;
1771 import_environment_observer (SCM caller
, SCM import_env
)
1773 core_environments_broadcast (import_env
);
1777 SCM_DEFINE (scm_make_import_environment
, "make-import-environment", 2, 0, 0,
1778 (SCM imports
, SCM conflict_proc
),
1779 "Return a new environment imp whose bindings are the union of\n"
1780 "the bindings from the environments in imports; imports must\n"
1781 "be a list of environments. That is, imp binds symbol to\n"
1782 "location when some element of imports does.\n"
1783 "If two different elements of imports have a binding for the\n"
1784 "same symbol, the conflict-proc is called with the following\n"
1785 "parameters: the import environment, the symbol and the list\n"
1786 "of the imported environments that bind the symbol. If the\n"
1787 "conflict-proc returns an environment env, the conflict is\n"
1788 "considered as resolved and the binding from env is used. If\n"
1789 "the conflict-proc returns some non-environment object, the\n"
1790 "conflict is considered unresolved and the symbol is treated\n"
1791 "as unspecified in the import environment.\n"
1792 "The checking for conflicts may be performed lazily, i. e. at\m"
1793 "the moment when a value or binding for a certain symbol is\n"
1794 "requested instead of the moment when the environment is\n"
1795 "created or the bindings of the imports change.\n"
1796 "All bindings in imp are immutable. If you apply\n"
1797 "environment-define or environment-undefine to imp, Guile\n"
1798 "will signal an environment:immutable-binding error. However,\n"
1799 "notice that the set of bindings in imp may still change, if\n"
1800 "one of its imported environments changes.")
1801 #define FUNC_NAME s_scm_make_import_environment
1803 scm_sizet size
= sizeof (struct import_environment
);
1804 struct import_environment
*body
= scm_must_malloc (size
, FUNC_NAME
);
1807 core_environments_preinit (&body
->base
);
1808 body
->imports
= SCM_BOOL_F
;
1809 body
->import_observers
= SCM_BOOL_F
;
1810 body
->conflict_proc
= SCM_BOOL_F
;
1812 env
= scm_make_environment (body
);
1814 core_environments_init (&body
->base
, &import_environment_funcs
);
1815 body
->imports
= SCM_EOL
;
1816 body
->import_observers
= SCM_EOL
;
1817 body
->conflict_proc
= conflict_proc
;
1819 scm_import_environment_set_imports_x (env
, imports
);
1826 SCM_DEFINE (scm_import_environment_p
, "import-environment?", 1, 0, 0,
1828 "Return #t if object is an import environment, or #f otherwise.")
1829 #define FUNC_NAME s_scm_import_environment_p
1831 return SCM_BOOL (SCM_IMPORT_ENVIRONMENT_P (object
));
1836 SCM_DEFINE (scm_import_environment_imports
, "import-environment-imports", 1, 0, 0,
1838 "Return the list of environments imported by the import environment env.")
1839 #define FUNC_NAME s_scm_import_environment_imports
1841 SCM_ASSERT (SCM_IMPORT_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
1843 return IMPORT_ENVIRONMENT (env
)->imports
;
1848 SCM_DEFINE (scm_import_environment_set_imports_x
, "import-environment-set-imports!", 2, 0, 0,
1849 (SCM env
, SCM imports
),
1850 "Change env's list of imported environments to imports, and check for conflicts.")
1851 #define FUNC_NAME s_scm_import_environment_set_imports_x
1853 struct import_environment
*body
= IMPORT_ENVIRONMENT (env
);
1854 SCM import_observers
= SCM_EOL
;
1857 SCM_ASSERT (SCM_IMPORT_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
1858 for (l
= imports
; SCM_CONSP (l
); l
= SCM_CDR (l
))
1860 SCM obj
= SCM_CAR (l
);
1861 SCM_ASSERT (SCM_ENVIRONMENT_P (obj
), imports
, SCM_ARG1
, FUNC_NAME
);
1863 SCM_ASSERT (SCM_NULLP (l
), imports
, SCM_ARG1
, FUNC_NAME
);
1865 for (l
= body
->import_observers
; !SCM_NULLP (l
); l
= SCM_CDR (l
))
1867 SCM obs
= SCM_CAR (l
);
1868 SCM_ENVIRONMENT_UNOBSERVE (env
, obs
);
1871 for (l
= imports
; !SCM_NULLP (l
); l
= SCM_CDR (l
))
1873 SCM imp
= SCM_CAR (l
);
1874 SCM obs
= SCM_ENVIRONMENT_OBSERVE (imp
, import_environment_observer
, env
, 1);
1875 import_observers
= scm_cons (obs
, import_observers
);
1878 body
->imports
= imports
;
1879 body
->import_observers
= import_observers
;
1881 return SCM_UNSPECIFIED
;
1887 /* export environments
1889 * An export environment restricts an environment to a specified set of
1892 * Implementation: The export environment does no caching at all. For every
1893 * access, the signature is scanned. The signature that is stored internally
1894 * is an alist of pairs (symbol . (mutability)).
1898 struct export_environment
{
1899 struct core_environments_base base
;
1902 SCM private_observer
;
1908 #define EXPORT_ENVIRONMENT(env) \
1909 ((struct export_environment *) SCM_CELL_WORD_1 (env))
1912 SCM_SYMBOL (symbol_immutable_location
, "immutable-location");
1913 SCM_SYMBOL (symbol_mutable_location
, "mutable-location");
1918 export_environment_ref (SCM env
, SCM sym
)
1919 #define FUNC_NAME "export_environment_ref"
1921 struct export_environment
*body
= EXPORT_ENVIRONMENT (env
);
1922 SCM entry
= scm_assq (sym
, body
->signature
);
1924 if (SCM_FALSEP (entry
))
1925 return SCM_UNDEFINED
;
1927 return SCM_ENVIRONMENT_REF (body
->private, sym
);
1933 export_environment_fold (SCM env
, scm_environment_folder proc
, SCM data
, SCM init
)
1935 struct export_environment
*body
= EXPORT_ENVIRONMENT (env
);
1939 for (l
= body
->signature
; !SCM_NULLP (l
); l
= SCM_CDR (l
))
1941 SCM symbol
= SCM_CAR (l
);
1942 SCM value
= SCM_ENVIRONMENT_REF (body
->private, symbol
);
1943 if (!SCM_UNBNDP (value
))
1944 result
= (*proc
) (data
, symbol
, value
, result
);
1951 export_environment_define (SCM env
, SCM sym
, SCM val
)
1952 #define FUNC_NAME "export_environment_define"
1954 return SCM_ENVIRONMENT_BINDING_IMMUTABLE
;
1960 export_environment_undefine (SCM env
, SCM sym
)
1961 #define FUNC_NAME "export_environment_undefine"
1963 return SCM_ENVIRONMENT_BINDING_IMMUTABLE
;
1969 export_environment_set_x (SCM env
, SCM sym
, SCM val
)
1970 #define FUNC_NAME "export_environment_set_x"
1972 struct export_environment
*body
= EXPORT_ENVIRONMENT (env
);
1973 SCM entry
= scm_assq (sym
, body
->signature
);
1975 if (SCM_FALSEP (entry
))
1977 return SCM_UNDEFINED
;
1981 if (SCM_EQ_P (SCM_CADR (entry
), symbol_mutable_location
))
1982 return SCM_ENVIRONMENT_SET (body
->private, sym
, val
);
1984 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE
;
1991 export_environment_cell (SCM env
, SCM sym
, int for_write
)
1992 #define FUNC_NAME "export_environment_cell"
1994 struct export_environment
*body
= EXPORT_ENVIRONMENT (env
);
1995 SCM entry
= scm_assq (sym
, body
->signature
);
1997 if (SCM_FALSEP (entry
))
1999 return SCM_UNDEFINED
;
2003 if (!for_write
|| SCM_EQ_P (SCM_CADR (entry
), symbol_mutable_location
))
2004 return SCM_ENVIRONMENT_CELL (body
->private, sym
, for_write
);
2006 return SCM_ENVIRONMENT_LOCATION_IMMUTABLE
;
2013 mark_export_environment (SCM env
)
2015 struct export_environment
*body
= EXPORT_ENVIRONMENT (env
);
2017 scm_gc_mark (body
->private);
2018 scm_gc_mark (body
->private_observer
);
2019 scm_gc_mark (body
->signature
);
2021 return core_environments_mark (env
);
2026 free_export_environment (SCM env
)
2028 core_environments_finalize (env
);
2030 free (EXPORT_ENVIRONMENT (env
));
2031 return sizeof (struct export_environment
);
2036 print_export_environment (SCM type
, SCM port
, scm_print_state
*pstate
)
2038 SCM address
= scm_ulong2num (SCM_UNPACK (type
));
2039 SCM base16
= scm_number_to_string (address
, SCM_MAKINUM (16));
2041 scm_puts ("#<export environment ", port
);
2042 scm_puts (SCM_CHARS (base16
), port
);
2043 scm_puts (">", port
);
2049 static struct scm_environment_funcs export_environment_funcs
= {
2050 export_environment_ref
,
2051 export_environment_fold
,
2052 export_environment_define
,
2053 export_environment_undefine
,
2054 export_environment_set_x
,
2055 export_environment_cell
,
2056 core_environments_observe
,
2057 core_environments_unobserve
,
2058 mark_export_environment
,
2059 free_export_environment
,
2060 print_export_environment
2064 void *scm_type_export_environment
= &export_environment_funcs
;
2068 export_environment_observer (SCM caller
, SCM export_env
)
2070 core_environments_broadcast (export_env
);
2074 SCM_DEFINE (scm_make_export_environment
, "make-export-environment", 2, 0, 0,
2075 (SCM
private, SCM signature
),
2076 "Return a new environment exp containing only those bindings\n"
2077 "in private whose symbols are present in signature. The\n"
2078 "private argument must be an environment.\n\n"
2079 "The environment exp binds symbol to location when env does,\n"
2080 "and symbol is exported by signature.\n\n"
2081 "Signature is a list specifying which of the bindings in\n"
2082 "private should be visible in exp. Each element of signature\n"
2083 "should be a list of the form:\n"
2084 " (symbol attribute ...)\n"
2085 "where each attribute is one of the following:\n"
2086 "* the symbol mutable-location exp should treat the location\n"
2087 " bound to symbol as mutable. That is, exp will pass calls\n"
2088 " to env-set! or environment-cell directly through to\n"
2090 "* the symbol immutable-location exp should treat the\n"
2091 " location bound to symbol as immutable. If the program\n"
2092 " applies environment-set! to exp and symbol, or calls\n"
2093 " environment-cell to obtain a writable value cell,\n"
2094 " environment-set! will signal an\n"
2095 " environment:immutable-location error. Note that, even if\n"
2096 " an export environment treats a location as immutable, the\n"
2097 " underlying environment may treat it as mutable, so its\n"
2098 " value may change.\n"
2099 "It is an error for an element of signature to specify both\n"
2100 "mutable-location and immutable-location. If neither is\n"
2101 "specified, immutable-location is assumed.\n\n"
2102 "As a special case, if an element of signature is a lone\n"
2103 "symbol sym, it is equivalent to an element of the form\n"
2105 "All bindings in exp are immutable. If you apply\n"
2106 "environment-define or environment-undefine to exp, Guile\n"
2107 "will signal an environment:immutable-binding error. However,\n"
2108 "notice that the set of bindings in exp may still change, if\n"
2109 "the bindings in private change.")
2110 #define FUNC_NAME s_scm_make_export_environment
2113 struct export_environment
*body
;
2116 SCM_ASSERT (SCM_ENVIRONMENT_P (private), private, SCM_ARG1
, FUNC_NAME
);
2118 size
= sizeof (struct export_environment
);
2119 body
= scm_must_malloc (size
, FUNC_NAME
);
2121 core_environments_preinit (&body
->base
);
2122 body
->private = SCM_BOOL_F
;
2123 body
->private_observer
= SCM_BOOL_F
;
2124 body
->signature
= SCM_BOOL_F
;
2126 env
= scm_make_environment (body
);
2128 core_environments_init (&body
->base
, &export_environment_funcs
);
2129 body
->private = private;
2130 body
->private_observer
2131 = SCM_ENVIRONMENT_OBSERVE (private, export_environment_observer
, env
, 1);
2132 body
->signature
= SCM_EOL
;
2134 scm_export_environment_set_signature_x (env
, signature
);
2141 SCM_DEFINE (scm_export_environment_p
, "export-environment?", 1, 0, 0,
2143 "Return #t if object is an export environment, or #f otherwise.")
2144 #define FUNC_NAME s_scm_export_environment_p
2146 return SCM_BOOL (SCM_EXPORT_ENVIRONMENT_P (object
));
2151 SCM_DEFINE (scm_export_environment_private
, "export-environment-private", 1, 0, 0,
2153 "Return the private environment of export environment env.")
2154 #define FUNC_NAME s_scm_export_environment_private
2156 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
2158 return EXPORT_ENVIRONMENT (env
)->private;
2163 SCM_DEFINE (scm_export_environment_set_private_x
, "export-environment-set-private!", 2, 0, 0,
2164 (SCM env
, SCM
private),
2165 "Change the private environment of export environment env.")
2166 #define FUNC_NAME s_scm_export_environment_set_private_x
2168 struct export_environment
*body
;
2170 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
2171 SCM_ASSERT (SCM_ENVIRONMENT_P (private), private, SCM_ARG2
, FUNC_NAME
);
2173 body
= EXPORT_ENVIRONMENT (env
);
2174 SCM_ENVIRONMENT_UNOBSERVE (private, body
->private_observer
);
2176 body
->private = private;
2177 body
->private_observer
2178 = SCM_ENVIRONMENT_OBSERVE (private, export_environment_observer
, env
, 1);
2180 return SCM_UNSPECIFIED
;
2185 SCM_DEFINE (scm_export_environment_signature
, "export-environment-signature", 1, 0, 0,
2187 "Return the signature of export environment env.")
2188 #define FUNC_NAME s_scm_export_environment_signature
2190 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
2192 return EXPORT_ENVIRONMENT (env
)->signature
;
2198 export_environment_parse_signature (SCM signature
, const char* caller
)
2200 SCM result
= SCM_EOL
;
2203 for (l
= signature
; SCM_CONSP (l
); l
= SCM_CDR (l
))
2205 SCM entry
= SCM_CAR (l
);
2207 if (SCM_SYMBOLP (entry
))
2209 SCM new_entry
= scm_cons2 (entry
, symbol_immutable_location
, SCM_EOL
);
2210 result
= scm_cons (new_entry
, result
);
2221 SCM_ASSERT (SCM_CONSP (entry
), entry
, SCM_ARGn
, caller
);
2222 SCM_ASSERT (SCM_SYMBOLP (SCM_CAR (entry
)), entry
, SCM_ARGn
, caller
);
2224 sym
= SCM_CAR (entry
);
2226 for (l2
= SCM_CDR (entry
); SCM_CONSP (l2
); l2
= SCM_CDR (l2
))
2228 SCM attribute
= SCM_CAR (l2
);
2229 if (SCM_EQ_P (attribute
, symbol_immutable_location
))
2231 else if (SCM_EQ_P (attribute
, symbol_mutable_location
))
2234 SCM_ASSERT (0, entry
, SCM_ARGn
, caller
);
2236 SCM_ASSERT (SCM_NULLP (l2
), entry
, SCM_ARGn
, caller
);
2237 SCM_ASSERT (!mutable || !immutable
, entry
, SCM_ARGn
, caller
);
2239 if (!mutable && !immutable
)
2242 mutability
= mutable ? symbol_mutable_location
: symbol_immutable_location
;
2243 new_entry
= scm_cons2 (sym
, mutability
, SCM_EOL
);
2244 result
= scm_cons (new_entry
, result
);
2247 SCM_ASSERT (SCM_NULLP (l
), signature
, SCM_ARGn
, caller
);
2249 /* Dirk:FIXME:: Now we know that signature is syntactically correct. There
2250 * are, however, no checks for symbols entered twice with contradicting
2251 * mutabilities. It would be nice, to implement this test, to be able to
2252 * call the sort functions conveniently from C.
2255 return scm_reverse (result
);
2259 SCM_DEFINE (scm_export_environment_set_signature_x
, "export-environment-set-signature!", 2, 0, 0,
2260 (SCM env
, SCM signature
),
2261 "Change the signature of export environment env.")
2262 #define FUNC_NAME s_scm_export_environment_set_signature_x
2266 SCM_ASSERT (SCM_EXPORT_ENVIRONMENT_P (env
), env
, SCM_ARG1
, FUNC_NAME
);
2267 parsed_sig
= export_environment_parse_signature (signature
, FUNC_NAME
);
2269 EXPORT_ENVIRONMENT (env
)->signature
= parsed_sig
;
2271 return SCM_UNSPECIFIED
;
2278 scm_environments_prehistory ()
2280 /* create environment smob */
2281 scm_tc16_environment
= scm_make_smob_type ("environment", 0);
2282 scm_set_smob_mark (scm_tc16_environment
, mark_environment
);
2283 scm_set_smob_free (scm_tc16_environment
, free_environment
);
2284 scm_set_smob_print (scm_tc16_environment
, print_environment
);
2286 /* create observer smob */
2287 scm_tc16_observer
= scm_make_smob_type ("observer", 0);
2288 scm_set_smob_mark (scm_tc16_observer
, mark_observer
);
2289 scm_set_smob_free (scm_tc16_observer
, free_observer
);
2290 scm_set_smob_print (scm_tc16_observer
, print_observer
);
2295 scm_init_environments ()
2297 #include "environments.x"