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