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