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