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