guile/libguile/modules.c

913 lines
23 KiB
C
Raw Normal View History

/* Copyright (C) 1998,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
2007-05-05 20:38:57 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdarg.h>
#include "libguile/_scm.h"
#include "libguile/eval.h"
#include "libguile/smob.h"
#include "libguile/procprop.h"
#include "libguile/vectors.h"
#include "libguile/hashtab.h"
#include "libguile/struct.h"
#include "libguile/variable.h"
#include "libguile/fluids.h"
#include "libguile/deprecation.h"
#include "libguile/modules.h"
2001-05-15 14:57:22 +00:00
int scm_module_system_booted_p = 0;
2001-06-14 19:50:43 +00:00
scm_t_bits scm_module_tag;
/* The current module, a fluid. */
static SCM the_module;
/* Most of the module system is implemented in Scheme. These bindings from
boot-9 are needed to provide the Scheme interface. */
static SCM the_root_module_var;
static SCM module_make_local_var_x_var;
static SCM define_module_star_var;
static SCM process_use_modules_var;
static SCM resolve_module_var;
static SCM module_public_interface_var;
static SCM module_export_x_var;
static SCM default_duplicate_binding_procedures_var;
static SCM unbound_variable (const char *func, SCM sym)
{
scm_error (scm_from_locale_symbol ("unbound-variable"), func,
"Unbound variable: ~S", scm_list_1 (sym), SCM_BOOL_F);
}
SCM
scm_the_root_module (void)
{
if (scm_module_system_booted_p)
return SCM_VARIABLE_REF (the_root_module_var);
else
return SCM_BOOL_F;
}
SCM_DEFINE (scm_current_module, "current-module", 0, 0, 0,
(),
"Return the current module.")
#define FUNC_NAME s_scm_current_module
{
SCM curr = scm_fluid_ref (the_module);
return scm_is_true (curr) ? curr : scm_the_root_module ();
}
#undef FUNC_NAME
2001-05-15 14:57:22 +00:00
static void scm_post_boot_init_modules (void);
SCM_DEFINE (scm_set_current_module, "set-current-module", 1, 0, 0,
(SCM module),
2001-11-11 15:01:52 +00:00
"Set the current module to @var{module} and return\n"
"the previous current module.")
#define FUNC_NAME s_scm_set_current_module
{
SCM old;
2001-05-15 14:57:22 +00:00
if (!scm_module_system_booted_p)
scm_post_boot_init_modules ();
SCM_VALIDATE_MODULE (SCM_ARG1, module);
old = scm_current_module ();
scm_fluid_set_x (the_module, module);
return old;
}
#undef FUNC_NAME
SCM_DEFINE (scm_interaction_environment, "interaction-environment", 0, 0, 0,
(),
"Return a specifier for the environment that contains\n"
"implementation--defined bindings, typically a superset of those\n"
"listed in the report. The intent is that this procedure will\n"
"return the environment in which the implementation would\n"
"evaluate expressions dynamically typed by the user.")
#define FUNC_NAME s_scm_interaction_environment
{
return scm_current_module ();
}
#undef FUNC_NAME
SCM
scm_c_call_with_current_module (SCM module,
SCM (*func)(void *), void *data)
{
return scm_c_with_fluid (the_module, module, func, data);
}
2005-03-02 20:14:59 +00:00
void
scm_dynwind_current_module (SCM module)
2005-03-02 20:14:59 +00:00
{
scm_dynwind_fluid (the_module, module);
2005-03-02 20:14:59 +00:00
}
/*
convert "A B C" to scheme list (A B C)
*/
static SCM
convert_module_name (const char *name)
{
SCM list = SCM_EOL;
SCM *tail = &list;
const char *ptr;
while (*name)
{
while (*name == ' ')
name++;
ptr = name;
while (*ptr && *ptr != ' ')
ptr++;
if (ptr > name)
{
SCM sym = scm_from_locale_symboln (name, ptr-name);
*tail = scm_cons (sym, SCM_EOL);
tail = SCM_CDRLOC (*tail);
}
name = ptr;
}
return list;
}
SCM
scm_c_resolve_module (const char *name)
{
return scm_resolve_module (convert_module_name (name));
}
SCM
scm_resolve_module (SCM name)
{
return scm_call_1 (SCM_VARIABLE_REF (resolve_module_var), name);
}
SCM
scm_c_define_module (const char *name,
void (*init)(void *), void *data)
{
SCM module = scm_call_1 (SCM_VARIABLE_REF (define_module_star_var),
convert_module_name (name));
if (init)
scm_c_call_with_current_module (module, (SCM (*)(void*))init, data);
return module;
}
void
scm_c_use_module (const char *name)
{
scm_call_1 (SCM_VARIABLE_REF (process_use_modules_var),
scm_list_1 (scm_list_1 (convert_module_name (name))));
}
2007-05-05 20:38:57 +00:00
SCM
scm_module_export (SCM module, SCM namelist)
{
return scm_call_2 (SCM_VARIABLE_REF (module_export_x_var),
module, namelist);
}
/*
@code{scm_c_export}(@var{name-list})
@code{scm_c_export} exports the named bindings from the current
module, making them visible to users of the module. This function
takes a list of string arguments, terminated by NULL, e.g.
@example
scm_c_export ("add-double-record", "bamboozle-money", NULL);
@end example
*/
void
scm_c_export (const char *name, ...)
{
if (name)
{
va_list ap;
SCM names = scm_cons (scm_from_locale_symbol (name), SCM_EOL);
SCM *tail = SCM_CDRLOC (names);
va_start (ap, name);
while (1)
{
const char *n = va_arg (ap, const char *);
if (n == NULL)
break;
*tail = scm_cons (scm_from_locale_symbol (n), SCM_EOL);
tail = SCM_CDRLOC (*tail);
}
va_end (ap);
2007-05-05 20:38:57 +00:00
scm_module_export (scm_current_module (), names);
}
}
/* Environments */
2001-05-15 14:57:22 +00:00
SCM_SYMBOL (sym_module, "module");
SCM
scm_lookup_closure_module (SCM proc)
{
if (scm_is_false (proc))
return scm_the_root_module ();
2001-05-15 14:57:22 +00:00
else if (SCM_EVAL_CLOSURE_P (proc))
return SCM_PACK (SCM_SMOB_DATA (proc));
else
{
SCM mod;
/* FIXME: The `module' property is no longer set on eval closures, as it
introduced a circular reference that precludes garbage collection of
modules with the current weak hash table semantics (see
http://lists.gnu.org/archive/html/guile-devel/2009-01/msg00102.html and
http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/2465
for details). Since it doesn't appear to be used (only in this
function, which has 1 caller), we no longer extend
`set-module-eval-closure!' to set the `module' property. */
abort ();
mod = scm_procedure_property (proc, sym_module);
if (scm_is_false (mod))
mod = scm_the_root_module ();
2001-05-15 14:57:22 +00:00
return mod;
}
}
/*
* C level implementation of the standard eval closure
*
* This increases loading speed substantially. The code may be
* replaced by something based on environments.[ch], in a future
* release.
*/
2007-05-05 20:38:57 +00:00
/* Return the list of default duplicate binding handlers (procedures). */
static inline SCM
default_duplicate_binding_handlers (void)
{
SCM get_handlers;
get_handlers = SCM_VARIABLE_REF (default_duplicate_binding_procedures_var);
return (scm_call_0 (get_handlers));
}
/* Resolve the import of SYM in MODULE, where SYM is currently provided by
both IFACE1 as VAR1 and IFACE2 as VAR2. Return the variable chosen by the
duplicate binding handlers or `#f'. */
static inline SCM
resolve_duplicate_binding (SCM module, SCM sym,
SCM iface1, SCM var1,
SCM iface2, SCM var2)
{
SCM result = SCM_BOOL_F;
if (!scm_is_eq (var1, var2))
{
SCM val1, val2;
SCM handlers, h, handler_args;
val1 = SCM_VARIABLE_REF (var1);
val2 = SCM_VARIABLE_REF (var2);
val1 = (val1 == SCM_UNSPECIFIED) ? SCM_BOOL_F : val1;
val2 = (val2 == SCM_UNSPECIFIED) ? SCM_BOOL_F : val2;
handlers = SCM_MODULE_DUPLICATE_HANDLERS (module);
if (scm_is_false (handlers))
handlers = default_duplicate_binding_handlers ();
handler_args = scm_list_n (module, sym,
iface1, val1, iface2, val2,
var1, val1,
SCM_UNDEFINED);
for (h = handlers;
scm_is_pair (h) && scm_is_false (result);
h = SCM_CDR (h))
{
result = scm_apply (SCM_CAR (h), handler_args, SCM_EOL);
}
}
else
result = var1;
return result;
}
SCM scm_pre_modules_obarray;
2007-05-05 20:38:57 +00:00
/* Lookup SYM as an imported variable of MODULE. */
static inline SCM
module_imported_variable (SCM module, SCM sym)
{
#define SCM_BOUND_THING_P scm_is_true
register SCM var, imports;
/* Search cached imported bindings. */
imports = SCM_MODULE_IMPORT_OBARRAY (module);
var = scm_hashq_ref (imports, sym, SCM_UNDEFINED);
if (SCM_BOUND_THING_P (var))
return var;
{
/* Search the use list for yet uncached imported bindings, possibly
resolving duplicates as needed and caching the result in the import
obarray. */
SCM uses;
SCM found_var = SCM_BOOL_F, found_iface = SCM_BOOL_F;
for (uses = SCM_MODULE_USES (module);
scm_is_pair (uses);
uses = SCM_CDR (uses))
{
SCM iface;
iface = SCM_CAR (uses);
var = scm_module_variable (iface, sym);
if (SCM_BOUND_THING_P (var))
{
if (SCM_BOUND_THING_P (found_var))
{
/* SYM is a duplicate binding (imported more than once) so we
need to resolve it. */
found_var = resolve_duplicate_binding (module, sym,
found_iface, found_var,
iface, var);
if (scm_is_eq (found_var, var))
found_iface = iface;
}
else
/* Keep track of the variable we found and check for other
occurences of SYM in the use list. */
found_var = var, found_iface = iface;
}
}
if (SCM_BOUND_THING_P (found_var))
{
/* Save the lookup result for future reference. */
(void) scm_hashq_set_x (imports, sym, found_var);
return found_var;
}
}
return SCM_BOOL_F;
#undef SCM_BOUND_THING_P
}
SCM_DEFINE (scm_module_local_variable, "module-local-variable", 2, 0, 0,
(SCM module, SCM sym),
"Return the variable bound to @var{sym} in @var{module}. Return "
"@code{#f} is @var{sym} is not bound locally in @var{module}.")
#define FUNC_NAME s_scm_module_local_variable
{
#define SCM_BOUND_THING_P(b) \
(scm_is_true (b))
2007-05-05 20:38:57 +00:00
register SCM b;
if (scm_module_system_booted_p)
SCM_VALIDATE_MODULE (1, module);
SCM_VALIDATE_SYMBOL (2, sym);
if (scm_is_false (module))
return scm_hashq_ref (scm_pre_modules_obarray, sym, SCM_UNDEFINED);
2007-05-05 20:38:57 +00:00
/* 1. Check module obarray */
2007-05-05 20:38:57 +00:00
b = scm_hashq_ref (SCM_MODULE_OBARRAY (module), sym, SCM_UNDEFINED);
if (SCM_BOUND_THING_P (b))
return b;
2007-05-05 20:38:57 +00:00
/* At this point we should just be able to return #f, but there is the
possibility that a custom binder establishes a mapping for this
variable.
However a custom binder should be called only if there is no
imported binding with the name SYM. So here instead of the order:
2. Search imported bindings. In order to be consistent with
`module-variable', the binder gets called only when no
imported binding matches SYM.
3. Query the custom binder.
we first check if there is a binder at all, and if not, just return
#f directly.
*/
2007-05-05 20:38:57 +00:00
{
SCM binder = SCM_MODULE_BINDER (module);
2007-05-05 20:38:57 +00:00
if (scm_is_true (binder))
{
/* 2. */
b = module_imported_variable (module, sym);
if (SCM_BOUND_THING_P (b))
return SCM_BOOL_F;
/* 3. */
b = scm_call_3 (binder, module, sym, SCM_BOOL_F);
if (SCM_BOUND_THING_P (b))
return b;
}
}
2007-05-05 20:38:57 +00:00
return SCM_BOOL_F;
#undef SCM_BOUND_THING_P
}
#undef FUNC_NAME
SCM_DEFINE (scm_module_variable, "module-variable", 2, 0, 0,
(SCM module, SCM sym),
"Return the variable bound to @var{sym} in @var{module}. This "
"may be both a local variable or an imported variable. Return "
"@code{#f} is @var{sym} is not bound in @var{module}.")
#define FUNC_NAME s_scm_module_variable
{
#define SCM_BOUND_THING_P(b) \
(scm_is_true (b))
register SCM var;
if (scm_module_system_booted_p)
SCM_VALIDATE_MODULE (1, module);
SCM_VALIDATE_SYMBOL (2, sym);
if (scm_is_false (module))
return scm_hashq_ref (scm_pre_modules_obarray, sym, SCM_UNDEFINED);
2007-05-05 20:38:57 +00:00
/* 1. Check module obarray */
var = scm_hashq_ref (SCM_MODULE_OBARRAY (module), sym, SCM_UNDEFINED);
if (SCM_BOUND_THING_P (var))
return var;
/* 2. Search among the imported variables. */
var = module_imported_variable (module, sym);
if (SCM_BOUND_THING_P (var))
return var;
{
2007-05-05 20:38:57 +00:00
/* 3. Query the custom binder. */
SCM binder;
binder = SCM_MODULE_BINDER (module);
if (scm_is_true (binder))
{
2007-05-05 20:38:57 +00:00
var = scm_call_3 (binder, module, sym, SCM_BOOL_F);
if (SCM_BOUND_THING_P (var))
return var;
}
}
2007-05-05 20:38:57 +00:00
return SCM_BOOL_F;
#undef SCM_BOUND_THING_P
}
2007-05-05 20:38:57 +00:00
#undef FUNC_NAME
2001-06-14 19:50:43 +00:00
scm_t_bits scm_tc16_eval_closure;
#define SCM_F_EVAL_CLOSURE_INTERFACE (1<<0)
2001-05-15 14:57:22 +00:00
#define SCM_EVAL_CLOSURE_INTERFACE_P(e) \
(SCM_SMOB_FLAGS (e) & SCM_F_EVAL_CLOSURE_INTERFACE)
2001-05-15 14:57:22 +00:00
/* NOTE: This function may be called by a smob application
or from another C function directly. */
SCM
scm_eval_closure_lookup (SCM eclo, SCM sym, SCM definep)
{
SCM module = SCM_PACK (SCM_SMOB_DATA (eclo));
if (scm_is_true (definep))
2001-05-15 14:57:22 +00:00
{
if (SCM_EVAL_CLOSURE_INTERFACE_P (eclo))
return SCM_BOOL_F;
return scm_call_2 (SCM_VARIABLE_REF (module_make_local_var_x_var),
module, sym);
2001-05-15 14:57:22 +00:00
}
else
2007-05-05 20:38:57 +00:00
return scm_module_variable (module, sym);
}
SCM_DEFINE (scm_standard_eval_closure, "standard-eval-closure", 1, 0, 0,
(SCM module),
"Return an eval closure for the module @var{module}.")
#define FUNC_NAME s_scm_standard_eval_closure
{
2000-12-08 17:32:56 +00:00
SCM_RETURN_NEWSMOB (scm_tc16_eval_closure, SCM_UNPACK (module));
}
#undef FUNC_NAME
2005-06-11 01:48:19 +00:00
2001-05-15 14:57:22 +00:00
SCM_DEFINE (scm_standard_interface_eval_closure,
"standard-interface-eval-closure", 1, 0, 0,
(SCM module),
"Return a interface eval closure for the module @var{module}. "
"Such a closure does not allow new bindings to be added.")
#define FUNC_NAME s_scm_standard_interface_eval_closure
{
SCM_RETURN_NEWSMOB (scm_tc16_eval_closure | (SCM_F_EVAL_CLOSURE_INTERFACE<<16),
2001-05-15 14:57:22 +00:00
SCM_UNPACK (module));
}
#undef FUNC_NAME
SCM_DEFINE (scm_eval_closure_module,
"eval-closure-module", 1, 0, 0,
(SCM eval_closure),
"Return the module associated with this eval closure.")
/* the idea is that eval closures are really not the way to do things, they're
superfluous given our module system. this function lets mmacros migrate away
from eval closures. */
#define FUNC_NAME s_scm_eval_closure_module
{
SCM_MAKE_VALIDATE_MSG (SCM_ARG1, eval_closure, EVAL_CLOSURE_P,
"eval-closure");
return SCM_SMOB_OBJECT (eval_closure);
}
#undef FUNC_NAME
SCM
scm_module_lookup_closure (SCM module)
{
if (scm_is_false (module))
return SCM_BOOL_F;
else
return SCM_MODULE_EVAL_CLOSURE (module);
}
SCM
scm_current_module_lookup_closure ()
{
if (scm_module_system_booted_p)
return scm_module_lookup_closure (scm_current_module ());
else
return SCM_BOOL_F;
}
SCM_SYMBOL (sym_macroexpand, "macroexpand");
really boot primitive-eval from scheme. * libguile/eval.c (scm_primitive_eval, scm_c_primitive_eval): (scm_init_eval): Rework so that scm_primitive_eval always calls out to the primitive-eval variable. The previous definition is the default value, which is probably overridden by scm_init_eval_in_scheme. * libguile/init.c (scm_i_init_guile): Move ports and load-path up, so we can debug when initing eval. Call scm_init_eval_in_scheme. Awesome. * libguile/load.h: * libguile/load.c (scm_init_eval_in_scheme): New procedure, loads up ice-9/eval.scm to replace the primitive-eval definition, if everything is there and up-to-date. * libguile/modules.c (scm_module_transformer): Export to Scheme, so it's there for eval.go. * module/ice-9/boot-9.scm: No need to define module-transformer. * module/ice-9/eval.scm (capture-env): Only reference the-root-module if modules are booted. (primitive-eval): Inline a definition for identity. Throw a more standard error for "wrong number of arguments". * module/ice-9/psyntax.scm (chi-install-global): The macro binding for a syncase macro is now a pair: the transformer, and the module that was current when the transformer was installed. The latter is used for hygiene purposes, replacing the use of procedure-module, which didn't work with the interpreter's shared-code closures. (chi-macro): Adapt for the binding being a pair, and get the hygiene from the cdr. (eval-local-transformer): Adapt to new form of macro bindings. * module/ice-9/psyntax-pp.scm: Regenerated. * .gitignore: Ignore eval.go.stamp. * module/Makefile.am: Reorder for fastest serial compilation, now that there are no ordering constraints. I did a number of experiments here and this seems to be the best; but the bulk of the time is compiling psyntax-pp.scm with eval.scm. Not so great. * libguile/vm-engine.c (vm-engine): Throw a more standard error for "wrong type to apply". * test-suite/tests/gc.test ("gc"): Remove a hack that shouldn't affect the new evaluator, and throw in another (gc) for good measure. * test-suite/tests/goops.test ("defining classes"): * test-suite/tests/hooks.test (proc1): We can't currently check what the arity is of a closure made by eval.scm -- or more accurately all closures have 0 required args and no rest args. So punt for now. * test-suite/tests/syntax.test ("letrec"): The scheme evaluator can't check that a variable is unbound, currently; perhaps the full "fixing letrec" expansion could fix this. But barring that, punt.
2009-12-01 23:54:25 +01:00
SCM_DEFINE (scm_module_transformer, "module-transformer", 1, 0, 0,
(SCM module),
"Returns the syntax expander for the given module.")
#define FUNC_NAME s_scm_module_transformer
{
if (SCM_UNLIKELY (scm_is_false (module)))
{
SCM v = scm_hashq_ref (scm_pre_modules_obarray,
sym_macroexpand,
SCM_BOOL_F);
if (scm_is_false (v))
SCM_MISC_ERROR ("no module, and `macroexpand' unbound", SCM_EOL);
return SCM_VARIABLE_REF (v);
}
else
really boot primitive-eval from scheme. * libguile/eval.c (scm_primitive_eval, scm_c_primitive_eval): (scm_init_eval): Rework so that scm_primitive_eval always calls out to the primitive-eval variable. The previous definition is the default value, which is probably overridden by scm_init_eval_in_scheme. * libguile/init.c (scm_i_init_guile): Move ports and load-path up, so we can debug when initing eval. Call scm_init_eval_in_scheme. Awesome. * libguile/load.h: * libguile/load.c (scm_init_eval_in_scheme): New procedure, loads up ice-9/eval.scm to replace the primitive-eval definition, if everything is there and up-to-date. * libguile/modules.c (scm_module_transformer): Export to Scheme, so it's there for eval.go. * module/ice-9/boot-9.scm: No need to define module-transformer. * module/ice-9/eval.scm (capture-env): Only reference the-root-module if modules are booted. (primitive-eval): Inline a definition for identity. Throw a more standard error for "wrong number of arguments". * module/ice-9/psyntax.scm (chi-install-global): The macro binding for a syncase macro is now a pair: the transformer, and the module that was current when the transformer was installed. The latter is used for hygiene purposes, replacing the use of procedure-module, which didn't work with the interpreter's shared-code closures. (chi-macro): Adapt for the binding being a pair, and get the hygiene from the cdr. (eval-local-transformer): Adapt to new form of macro bindings. * module/ice-9/psyntax-pp.scm: Regenerated. * .gitignore: Ignore eval.go.stamp. * module/Makefile.am: Reorder for fastest serial compilation, now that there are no ordering constraints. I did a number of experiments here and this seems to be the best; but the bulk of the time is compiling psyntax-pp.scm with eval.scm. Not so great. * libguile/vm-engine.c (vm-engine): Throw a more standard error for "wrong type to apply". * test-suite/tests/gc.test ("gc"): Remove a hack that shouldn't affect the new evaluator, and throw in another (gc) for good measure. * test-suite/tests/goops.test ("defining classes"): * test-suite/tests/hooks.test (proc1): We can't currently check what the arity is of a closure made by eval.scm -- or more accurately all closures have 0 required args and no rest args. So punt for now. * test-suite/tests/syntax.test ("letrec"): The scheme evaluator can't check that a variable is unbound, currently; perhaps the full "fixing letrec" expansion could fix this. But barring that, punt.
2009-12-01 23:54:25 +01:00
{
SCM_VALIDATE_MODULE (SCM_ARG1, module);
return SCM_MODULE_TRANSFORMER (module);
}
}
really boot primitive-eval from scheme. * libguile/eval.c (scm_primitive_eval, scm_c_primitive_eval): (scm_init_eval): Rework so that scm_primitive_eval always calls out to the primitive-eval variable. The previous definition is the default value, which is probably overridden by scm_init_eval_in_scheme. * libguile/init.c (scm_i_init_guile): Move ports and load-path up, so we can debug when initing eval. Call scm_init_eval_in_scheme. Awesome. * libguile/load.h: * libguile/load.c (scm_init_eval_in_scheme): New procedure, loads up ice-9/eval.scm to replace the primitive-eval definition, if everything is there and up-to-date. * libguile/modules.c (scm_module_transformer): Export to Scheme, so it's there for eval.go. * module/ice-9/boot-9.scm: No need to define module-transformer. * module/ice-9/eval.scm (capture-env): Only reference the-root-module if modules are booted. (primitive-eval): Inline a definition for identity. Throw a more standard error for "wrong number of arguments". * module/ice-9/psyntax.scm (chi-install-global): The macro binding for a syncase macro is now a pair: the transformer, and the module that was current when the transformer was installed. The latter is used for hygiene purposes, replacing the use of procedure-module, which didn't work with the interpreter's shared-code closures. (chi-macro): Adapt for the binding being a pair, and get the hygiene from the cdr. (eval-local-transformer): Adapt to new form of macro bindings. * module/ice-9/psyntax-pp.scm: Regenerated. * .gitignore: Ignore eval.go.stamp. * module/Makefile.am: Reorder for fastest serial compilation, now that there are no ordering constraints. I did a number of experiments here and this seems to be the best; but the bulk of the time is compiling psyntax-pp.scm with eval.scm. Not so great. * libguile/vm-engine.c (vm-engine): Throw a more standard error for "wrong type to apply". * test-suite/tests/gc.test ("gc"): Remove a hack that shouldn't affect the new evaluator, and throw in another (gc) for good measure. * test-suite/tests/goops.test ("defining classes"): * test-suite/tests/hooks.test (proc1): We can't currently check what the arity is of a closure made by eval.scm -- or more accurately all closures have 0 required args and no rest args. So punt for now. * test-suite/tests/syntax.test ("letrec"): The scheme evaluator can't check that a variable is unbound, currently; perhaps the full "fixing letrec" expansion could fix this. But barring that, punt.
2009-12-01 23:54:25 +01:00
#undef FUNC_NAME
SCM
scm_current_module_transformer ()
{
return scm_module_transformer (scm_current_module ());
}
SCM_DEFINE (scm_module_import_interface, "module-import-interface", 2, 0, 0,
(SCM module, SCM sym),
2007-05-05 20:38:57 +00:00
"Return the module or interface from which @var{sym} is imported "
"in @var{module}. If @var{sym} is not imported (i.e., it is not "
"defined in @var{module} or it is a module-local binding instead "
"of an imported one), then @code{#f} is returned.")
#define FUNC_NAME s_scm_module_import_interface
{
2007-05-05 20:38:57 +00:00
SCM var, result = SCM_BOOL_F;
SCM_VALIDATE_MODULE (1, module);
SCM_VALIDATE_SYMBOL (2, sym);
var = scm_module_variable (module, sym);
if (scm_is_true (var))
{
2007-05-05 20:38:57 +00:00
/* Look for the module that provides VAR. */
SCM local_var;
local_var = scm_hashq_ref (SCM_MODULE_OBARRAY (module), sym,
SCM_UNDEFINED);
if (scm_is_eq (local_var, var))
result = module;
else
{
/* Look for VAR among the used modules. */
SCM uses, imported_var;
for (uses = SCM_MODULE_USES (module);
scm_is_pair (uses) && scm_is_false (result);
uses = SCM_CDR (uses))
{
imported_var = scm_module_variable (SCM_CAR (uses), sym);
if (scm_is_eq (imported_var, var))
result = SCM_CAR (uses);
}
}
}
2007-05-05 20:38:57 +00:00
return result;
}
#undef FUNC_NAME
SCM
scm_module_public_interface (SCM module)
{
return scm_call_1 (SCM_VARIABLE_REF (module_public_interface_var), module);
}
2001-05-15 14:57:22 +00:00
/* scm_sym2var
*
* looks up the variable bound to SYM according to PROC. PROC should be
* a `eval closure' of some module.
*
* When no binding exists, and DEFINEP is true, create a new binding
* with a initial value of SCM_UNDEFINED. Return `#f' when DEFINEP as
* false and no binding exists.
*
* When PROC is `#f', it is ignored and the binding is searched for in
* the scm_pre_modules_obarray (a `eq' hash table).
*/
SCM
scm_sym2var (SCM sym, SCM proc, SCM definep)
#define FUNC_NAME "scm_sym2var"
{
SCM var;
if (SCM_NIMP (proc))
{
if (SCM_EVAL_CLOSURE_P (proc))
{
/* Bypass evaluator in the standard case. */
var = scm_eval_closure_lookup (proc, sym, definep);
}
else
var = scm_call_2 (proc, sym, definep);
2001-05-15 14:57:22 +00:00
}
else
{
SCM handle;
if (scm_is_false (definep))
2001-05-15 14:57:22 +00:00
var = scm_hashq_ref (scm_pre_modules_obarray, sym, SCM_BOOL_F);
else
{
handle = scm_hashq_create_handle_x (scm_pre_modules_obarray,
sym, SCM_BOOL_F);
var = SCM_CDR (handle);
if (scm_is_false (var))
2001-05-15 14:57:22 +00:00
{
var = scm_make_variable (SCM_UNDEFINED);
SCM_SETCDR (handle, var);
}
}
}
if (scm_is_true (var) && !SCM_VARIABLEP (var))
SCM_MISC_ERROR ("~S is not bound to a variable", scm_list_1 (sym));
2001-05-15 14:57:22 +00:00
return var;
}
#undef FUNC_NAME
SCM
scm_c_module_lookup (SCM module, const char *name)
{
return scm_module_lookup (module, scm_from_locale_symbol (name));
2001-05-15 14:57:22 +00:00
}
SCM
scm_module_lookup (SCM module, SCM sym)
#define FUNC_NAME "module-lookup"
{
SCM var;
SCM_VALIDATE_MODULE (1, module);
var = scm_sym2var (sym, scm_module_lookup_closure (module), SCM_BOOL_F);
if (scm_is_false (var))
unbound_variable (FUNC_NAME, sym);
2001-05-15 14:57:22 +00:00
return var;
}
#undef FUNC_NAME
SCM
scm_c_lookup (const char *name)
{
return scm_lookup (scm_from_locale_symbol (name));
2001-05-15 14:57:22 +00:00
}
SCM
scm_lookup (SCM sym)
{
SCM var =
scm_sym2var (sym, scm_current_module_lookup_closure (), SCM_BOOL_F);
if (scm_is_false (var))
unbound_variable (NULL, sym);
2001-05-15 14:57:22 +00:00
return var;
}
SCM
scm_c_module_define (SCM module, const char *name, SCM value)
{
return scm_module_define (module, scm_from_locale_symbol (name), value);
2001-05-15 14:57:22 +00:00
}
SCM
scm_module_define (SCM module, SCM sym, SCM value)
#define FUNC_NAME "module-define"
{
SCM var;
SCM_VALIDATE_MODULE (1, module);
var = scm_sym2var (sym, scm_module_lookup_closure (module), SCM_BOOL_T);
SCM_VARIABLE_SET (var, value);
return var;
}
#undef FUNC_NAME
SCM
scm_c_define (const char *name, SCM value)
{
return scm_define (scm_from_locale_symbol (name), value);
2001-05-15 14:57:22 +00:00
}
SCM_DEFINE (scm_define, "define!", 2, 0, 0,
(SCM sym, SCM value),
"Define @var{sym} to be @var{value} in the current module."
"Returns the variable itself. Note that this is a procedure, "
"not a macro.")
#define FUNC_NAME s_scm_define
2001-05-15 14:57:22 +00:00
{
SCM var;
SCM_VALIDATE_SYMBOL (SCM_ARG1, sym);
var = scm_sym2var (sym, scm_current_module_lookup_closure (), SCM_BOOL_T);
2001-05-15 14:57:22 +00:00
SCM_VARIABLE_SET (var, value);
return var;
}
#undef FUNC_NAME
2001-05-15 14:57:22 +00:00
2007-05-05 20:38:57 +00:00
SCM_DEFINE (scm_module_reverse_lookup, "module-reverse-lookup", 2, 0, 0,
(SCM module, SCM variable),
"Return the symbol under which @var{variable} is bound in "
"@var{module} or @var{#f} if @var{variable} is not visible "
"from @var{module}. If @var{module} is @code{#f}, then the "
"pre-module obarray is used.")
#define FUNC_NAME s_scm_module_reverse_lookup
2001-05-15 14:57:22 +00:00
{
SCM obarray;
long i, n;
2001-05-15 14:57:22 +00:00
if (scm_is_false (module))
2001-05-15 14:57:22 +00:00
obarray = scm_pre_modules_obarray;
else
{
SCM_VALIDATE_MODULE (1, module);
obarray = SCM_MODULE_OBARRAY (module);
}
SCM_VALIDATE_VARIABLE (SCM_ARG2, variable);
if (!SCM_HASHTABLE_P (obarray))
return SCM_BOOL_F;
2001-05-15 14:57:22 +00:00
/* XXX - We do not use scm_hash_fold here to avoid searching the
whole obarray. We should have a scm_hash_find procedure. */
* hooks.c (scm_c_hook_add): Fixed bug in append mode. * environments.c (obarray_enter, obarray_retrieve, obarray_remove, leaf_environment_fold, obarray_remove_all): Use hashtable accessors. * gc.c (scm_init_storage): Moved hook initialization to scm_storage_prehistory. (scm_storage_prehistory): New function. (scm_igc): Added commentary about placement of scm_after_sweep_c_hook. * gc-mark.c (scm_mark_all): Use hashtable accessors. (scm_gc_mark_dependencies): Use SCM_WVECT_WEAK_KEY_P and SCM_WVECT_WEAK_VALUE_P. * hashtab.c, hashtab.h (scm_hash_for_each, scm_hash_map): New functions. (scm_vector_to_hash_table, scm_c_make_resizing_hash_table): Removed. (scm_make_weak_key_hash_table, scm_make_weak_value_hash_table, scm_make_doubly_weak_hash_table): Moved here from weaks.c. * init.c (scm_init_guile_1): Removed call to scm_init_weaks; Added calls to scm_storage_prehistory and scm_hashtab_prehistory. * modules.c (module-reverse-lookup): Use hashtable accessors. * symbols.c, symbols.h (scm_i_hash_symbol): New function. * weaks.c, weaks.h (scm_make_weak_key_alist_vector, scm_make_weak_value_alist_vector, scm_make_doubly_weak_alist_vector): New functions. * weaks.c (scm_init_weaks_builtins): New function. * weaks.h (SCM_WVECTF_WEAK_KEY, SCM_WVECTF_WEAK_VALUE, SCM_WVECTF_NOSCAN, SCM_WVECT_WEAK_KEY_P, SCM_WVECT_WEAK_VALUE_P, SCM_WVECT_NOSCAN_P): New macros. * weaks.c (scm_scan_weak_vectors): Use SCM_WVECT_WEAK_KEY_P and SCM_WVECT_WEAK_VALUE_P. * weaks.c, weaks.h (scm_i_allocate_weak_vector): Renamed from allocate_weak_vector and exported. * Makefile.am (ice9_sources): Added weak-vector.scm. * weak-vector.scm: New file. * boot-9.scm (module-clear!): Use hash-clear!. (module-for-each): Use hash-for-each. (module-map): Use hash-map.
2003-02-19 15:04:51 +00:00
n = SCM_HASHTABLE_N_BUCKETS (obarray);
2001-05-15 14:57:22 +00:00
for (i = 0; i < n; ++i)
{
SCM ls = SCM_HASHTABLE_BUCKET (obarray, i), handle;
2004-09-22 17:41:37 +00:00
while (!scm_is_null (ls))
2001-05-15 14:57:22 +00:00
{
handle = SCM_CAR (ls);
if (SCM_CAR (handle) == SCM_PACK (NULL))
{
/* FIXME: We hit a weak pair whose car has become unreachable.
We should remove the pair in question or something. */
}
else
{
if (SCM_CDR (handle) == variable)
return SCM_CAR (handle);
}
2001-05-15 14:57:22 +00:00
ls = SCM_CDR (ls);
}
}
if (!scm_is_false (module))
{
/* Try the `uses' list. */
SCM uses = SCM_MODULE_USES (module);
while (scm_is_pair (uses))
{
SCM sym = scm_module_reverse_lookup (SCM_CAR (uses), variable);
if (scm_is_true (sym))
return sym;
uses = SCM_CDR (uses);
}
}
2001-05-15 14:57:22 +00:00
return SCM_BOOL_F;
}
#undef FUNC_NAME
SCM_DEFINE (scm_get_pre_modules_obarray, "%get-pre-modules-obarray", 0, 0, 0,
(),
"Return the obarray that is used for all new bindings before "
"the module system is booted. The first call to "
"@code{set-current-module} will boot the module system.")
#define FUNC_NAME s_scm_get_pre_modules_obarray
{
return scm_pre_modules_obarray;
}
#undef FUNC_NAME
SCM_SYMBOL (scm_sym_system_module, "system-module");
2001-05-15 14:57:22 +00:00
void
scm_modules_prehistory ()
{
scm_pre_modules_obarray = scm_c_make_hash_table (1533);
2001-05-15 14:57:22 +00:00
}
void
scm_init_modules ()
{
#include "libguile/modules.x"
2001-05-15 14:57:22 +00:00
module_make_local_var_x_var = scm_c_define ("module-make-local-var!",
SCM_UNDEFINED);
2000-12-08 17:32:56 +00:00
scm_tc16_eval_closure = scm_make_smob_type ("eval-closure", 0);
scm_set_smob_apply (scm_tc16_eval_closure, scm_eval_closure_lookup, 2, 0, 0);
the_module = scm_make_fluid ();
}
2001-05-15 14:57:22 +00:00
static void
scm_post_boot_init_modules ()
{
2001-05-15 14:57:22 +00:00
SCM module_type = SCM_VARIABLE_REF (scm_c_lookup ("module-type"));
scm_module_tag = (SCM_CELL_WORD_1 (module_type) + scm_tc3_struct);
resolve_module_var = scm_c_lookup ("resolve-module");
define_module_star_var = scm_c_lookup ("define-module*");
process_use_modules_var = scm_c_lookup ("process-use-modules");
module_export_x_var = scm_c_lookup ("module-export!");
the_root_module_var = scm_c_lookup ("the-root-module");
default_duplicate_binding_procedures_var =
scm_c_lookup ("default-duplicate-binding-procedures");
module_public_interface_var = scm_c_lookup ("module-public-interface");
scm_module_system_booted_p = 1;
}
/*
Local Variables:
c-file-style: "gnu"
End:
*/