revert the ill-considered part of the 2001-05-24 changes
[bpt/guile.git] / libguile / modules.c
index a59aec6..5bf40ac 100644 (file)
 
 \f
 
+#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"
 
-SCM scm_module_system_booted_p = 0;
+int scm_module_system_booted_p = 0;
 
 SCM scm_module_tag;
 
-static SCM the_root_module;
-static SCM root_module_lookup_closure;
+static SCM the_module;
 
-SCM
-scm_the_root_module ()
+SCM_DEFINE (scm_current_module, "current-module", 0, 0, 0,
+           (),
+           "Return the current module.")
+#define FUNC_NAME s_scm_current_module
 {
-  return SCM_CDR (the_root_module);
+  return scm_fluid_ref (the_module);
 }
+#undef FUNC_NAME
 
-static SCM the_module;
+static void scm_post_boot_init_modules (void);
 
-SCM
-scm_selected_module ()
+SCM_DEFINE (scm_set_current_module, "set-current-module", 1, 0, 0,
+           (SCM module),
+           "Set the current module to @var{module} and return"
+           "the previous current module.")
+#define FUNC_NAME s_scm_set_current_module
 {
-  return scm_fluid_ref (SCM_CDR (the_module));
-}
+  SCM old;
 
-static SCM set_current_module;
+  if (!scm_module_system_booted_p)
+    scm_post_boot_init_modules ();
 
-/* This is the module selected during loading of code.  Currently,
- * this is the same as (interaction-environment), but need not be in
- * the future.
- */
+  SCM_VALIDATE_MODULE (SCM_ARG1, module);
+
+  old = scm_current_module ();
+  scm_fluid_set_x (the_module, module);
+
+#if SCM_DEBUG_DEPRECATED == 0
+  scm_fluid_set_x (SCM_VARIABLE_REF (scm_top_level_lookup_closure_var),
+                  scm_current_module_lookup_closure ());
+  scm_fluid_set_x (SCM_VARIABLE_REF (scm_system_transformer),
+                  scm_current_module_transformer ());
+#endif
 
-SCM
-scm_select_module (SCM module)
-{
-  SCM old = scm_selected_module ();
-  scm_apply (SCM_CDR (set_current_module), SCM_LIST1 (module), SCM_EOL);
   return old;
 }
+#undef FUNC_NAME
 
 SCM_DEFINE (scm_interaction_environment, "interaction-environment", 0, 0, 0,
            (),
-           "This procedure returns a specifier for the environment that"
-           "contains implementation-defined bindings, typically a superset of"
-           "those listed in the report.  The intent is that this procedure"
-           "will return the environment in which the implementation would"
+           "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_selected_module ();
+  return scm_current_module ();
 }
 #undef FUNC_NAME
 
-SCM_SYMBOL (scm_sym_app, "app");
-SCM_SYMBOL (scm_sym_modules, "modules");
-static SCM module_prefix;
+SCM
+scm_c_call_with_current_module (SCM module,
+                               SCM (*func)(void *), void *data)
+{
+  return scm_c_with_fluid (the_module, module, func, data);
+}
 
 static SCM
-scm_module_full_name (SCM name)
+convert_module_name (const char *name)
 {
-  if (SCM_EQ_P (SCM_CAR (name), scm_sym_app))
-    return name;
-  else
-    return scm_append (SCM_LIST2 (module_prefix, 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)
+       {
+         *tail = scm_cons (scm_mem2symbol (name, ptr-name), SCM_EOL);
+         tail = SCM_CDRLOC (*tail);
+       }
+      name = ptr;
+    }
+
+  return list;
 }
 
-static SCM make_modules_in;
-static SCM beautify_user_module_x;
+static SCM process_define_module_var;
+static SCM process_use_modules_var;
+static SCM resolve_module_var;
 
 SCM
-scm_make_module (SCM name)
+scm_c_resolve_module (const char *name)
 {
-  return scm_apply (SCM_CDR (make_modules_in),
-                   SCM_LIST2 (scm_the_root_module (),
-                              scm_module_full_name (name)),
-                   SCM_EOL);
+  return scm_resolve_module (convert_module_name (name));
 }
 
 SCM
-scm_ensure_user_module (SCM module)
+scm_resolve_module (SCM name)
 {
-  scm_apply (SCM_CDR (beautify_user_module_x), SCM_LIST1 (module), SCM_EOL);
-  return SCM_UNSPECIFIED;
+  return scm_apply (SCM_VARIABLE_REF (resolve_module_var),
+                   SCM_LIST1 (name), SCM_EOL);
 }
 
 SCM
-scm_module_lookup_closure (SCM module)
+scm_c_define_module (const char *name,
+                    void (*init)(void *), void *data)
 {
-  return SCM_MODULE_EVAL_CLOSURE (module);
+  SCM module = scm_apply (SCM_VARIABLE_REF (process_define_module_var),
+                         SCM_LIST1 (SCM_LIST1 (convert_module_name (name))),
+                         SCM_EOL);
+  if (init)
+    scm_c_call_with_current_module (module, (SCM (*)(void*))init, data);
+  return module;
 }
 
-static SCM resolve_module;
-
-SCM
-scm_resolve_module (SCM name)
+void
+scm_c_use_module (const char *name)
 {
-  return scm_apply (SCM_CDR (resolve_module), SCM_LIST1 (name), SCM_EOL);
+  scm_apply (SCM_VARIABLE_REF (process_use_modules_var),
+            SCM_LIST1 (SCM_LIST1 (convert_module_name (name))),
+            SCM_EOL);
 }
 
-static SCM try_module_autoload;
+static SCM module_export_x_var;
 
-SCM
-scm_load_scheme_module (SCM name)
+void
+scm_c_export (const char *name, ...)
 {
-  return scm_apply (SCM_CDR (try_module_autoload), SCM_LIST1 (name), SCM_EOL);
+  va_list ap;
+  SCM names = scm_cons (scm_str2symbol (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_str2symbol (n), SCM_EOL);
+      tail = SCM_CDRLOC (*tail);
+    }
+  scm_apply (SCM_VARIABLE_REF (module_export_x_var),
+            SCM_LIST2 (scm_current_module (),
+                       names),
+            SCM_EOL);
 }
 
 /* Environments */
@@ -183,20 +233,43 @@ scm_env_top_level (SCM env)
   return SCM_BOOL_F;
 }
 
+SCM_SYMBOL (sym_module, "module");
 
-SCM_SYMBOL (scm_sym_system_module, "system-module");
+static SCM the_root_module_var;
+
+static SCM
+the_root_module ()
+{
+  if (scm_module_system_booted_p)
+    return SCM_VARIABLE_REF (the_root_module_var);
+  else
+    return SCM_BOOL_F;
+}
 
 SCM
-scm_system_module_env_p (SCM env)
+scm_lookup_closure_module (SCM proc)
 {
-  SCM proc = scm_env_top_level (env);
   if (SCM_FALSEP (proc))
-    proc = root_module_lookup_closure;
-  return ((SCM_NFALSEP (scm_procedure_property (proc,
-                                               scm_sym_system_module)))
-         ? SCM_BOOL_T
-         : SCM_BOOL_F);
+    return the_root_module ();
+  else if (SCM_EVAL_CLOSURE_P (proc))
+    return SCM_PACK (SCM_SMOB_DATA (proc));
+  else
+    {
+      SCM mod = scm_procedure_property (proc, sym_module);
+      if (mod == SCM_BOOL_F)
+       mod = the_root_module ();
+      return mod;
+    }
+}
+
+SCM_DEFINE (scm_env_module, "env-module", 1, 0, 0,
+           (SCM env),
+           "Return the module of @var{ENV}, a lexical environment.")
+#define FUNC_NAME s_scm_env_module
+{
+  return scm_lookup_closure_module (scm_env_top_level (env));
 }
+#undef FUNC_NAME
 
 /*
  * C level implementation of the standard eval closure
@@ -205,7 +278,7 @@ scm_system_module_env_p (SCM env)
  * The code will be replaced by the low-level environments in next release.
  */
 
-static SCM module_make_local_var_x;
+static SCM module_make_local_var_x_var;
 
 static SCM
 module_variable (SCM module, SCM sym)
@@ -240,62 +313,408 @@ module_variable (SCM module, SCM sym)
   }
 }
 
-static SCM f_eval_closure;
+scm_bits_t scm_tc16_eval_closure;
 
-static SCM
-eval_closure (SCM cclo, SCM sym, SCM definep)
+#define SCM_F_EVAL_CLOSURE_INTERFACE (1<<16)
+#define SCM_EVAL_CLOSURE_INTERFACE_P(e) \
+  (SCM_CELL_WORD_0 (e) & SCM_F_EVAL_CLOSURE_INTERFACE)
+
+/* 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_VELTS (cclo) [1];
+  SCM module = SCM_PACK (SCM_SMOB_DATA (eclo));
   if (SCM_NFALSEP (definep))
-    return scm_apply (SCM_CDR (module_make_local_var_x),
-                     SCM_LIST2 (module, sym),
-                     SCM_EOL);
+    {
+      if (SCM_EVAL_CLOSURE_INTERFACE_P (eclo))
+       return SCM_BOOL_F;
+      return scm_apply (SCM_VARIABLE_REF (module_make_local_var_x_var),
+                       SCM_LIST2 (module, sym),
+                       SCM_EOL);
+    }
   else
     return 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
 {
-  SCM cclo = scm_makcclo (f_eval_closure, 2);
-  SCM_VELTS (cclo) [1] = module;
-  return cclo;
+  SCM_RETURN_NEWSMOB (scm_tc16_eval_closure, SCM_UNPACK (module));
+}
+#undef FUNC_NAME
+
+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,
+                     SCM_UNPACK (module));
+}
+#undef FUNC_NAME
+
+SCM
+scm_module_lookup_closure (SCM module)
+{
+  if (module == SCM_BOOL_F)
+    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
+scm_module_transformer (SCM module)
+{
+  if (module == SCM_BOOL_F)
+    return SCM_BOOL_F;
+  else
+    return SCM_MODULE_TRANSFORMER (module);
+}
+
+SCM
+scm_current_module_transformer ()
+{
+  if (scm_module_system_booted_p)
+    return scm_module_transformer (scm_current_module ());
+  else
+    return SCM_BOOL_F;
+}
+
+/* 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_pre_modules_obarray;
+
+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_apply (proc, sym, scm_cons (definep, scm_listofnull));
+    }
+  else
+    {
+      SCM handle;
+
+      if (definep == SCM_BOOL_F)
+       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 (var == SCM_BOOL_F)
+           {
+             var = scm_make_variable (SCM_UNDEFINED);
+#if SCM_ENABLE_VCELLS
+             scm_variable_set_name_hint (var, sym);
+#endif
+             SCM_SETCDR (handle, var);
+           }
+       }
+    }
+
+  if (var != SCM_BOOL_F && !SCM_VARIABLEP (var))
+    SCM_MISC_ERROR ("~S is not bound to a variable", SCM_LIST1 (sym));
+
+  return var;
+}
+#undef FUNC_NAME
+
+SCM
+scm_c_module_lookup (SCM module, const char *name)
+{
+  return scm_module_lookup (module, scm_str2symbol (name));
+}
+
+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_FALSEP (var))
+    SCM_MISC_ERROR ("unbound variable: ~S", SCM_LIST1 (sym));
+  return var;
+}
+#undef FUNC_NAME
+
+SCM
+scm_c_lookup (const char *name)
+{
+  return scm_lookup (scm_str2symbol (name));
+}
+
+SCM
+scm_lookup (SCM sym)
+{
+  SCM var = 
+    scm_sym2var (sym, scm_current_module_lookup_closure (), SCM_BOOL_F);
+  if (SCM_FALSEP (var))
+    scm_misc_error ("scm_lookup", "unbound variable: ~S", SCM_LIST1 (sym));
+  return var;
+}
+
+SCM
+scm_c_module_define (SCM module, const char *name, SCM value)
+{
+  return scm_module_define (module, scm_str2symbol (name), value);
+}
+
+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_str2symbol (name), value);
+}
+
+SCM
+scm_define (SCM sym, SCM value)
+{
+  SCM var =
+    scm_sym2var (sym, scm_current_module_lookup_closure (), SCM_BOOL_T);
+  SCM_VARIABLE_SET (var, value);
+  return var;
+}
+
+SCM
+scm_module_reverse_lookup (SCM module, SCM variable)
+#define FUNC_NAME "module-reverse-lookup"
+{
+  SCM obarray;
+  long i, n;
+
+  if (module == SCM_BOOL_F)
+    obarray = scm_pre_modules_obarray;
+  else
+    {
+      SCM_VALIDATE_MODULE (1, module);
+      obarray = SCM_MODULE_OBARRAY (module);
+    }
+
+  /* XXX - We do not use scm_hash_fold here to avoid searching the
+     whole obarray.  We should have a scm_hash_find procedure. */
+
+  n = SCM_VECTOR_LENGTH (obarray);
+  for (i = 0; i < n; ++i)
+    {
+      SCM ls = SCM_VELTS (obarray)[i], handle;
+      while (!SCM_NULLP (ls))
+       {
+         handle = SCM_CAR (ls);
+         if (SCM_CDR (handle) == variable)
+           return SCM_CAR (handle);
+         ls = SCM_CDR (ls);
+       }
+    }
+
+  /* Try the `uses' list. 
+   */
+  {
+    SCM uses = SCM_MODULE_USES (module);
+    while (SCM_CONSP (uses))
+      {
+       SCM sym = scm_module_reverse_lookup (SCM_CAR (uses), variable);
+       if (sym != SCM_BOOL_F)
+         return sym;
+       uses = SCM_CDR (uses);
+      }
+  }
+
+  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
 
+#if SCM_DEBUG_DEPRECATED == 0
+
+static SCM root_module_lookup_closure;
+SCM_SYMBOL (scm_sym_app, "app");
+SCM_SYMBOL (scm_sym_modules, "modules");
+static SCM module_prefix;
+static SCM make_modules_in_var;
+static SCM beautify_user_module_x_var;
+static SCM try_module_autoload_var;
+
+#endif
+
+SCM_SYMBOL (scm_sym_system_module, "system-module");
+
+SCM
+scm_system_module_env_p (SCM env)
+{
+  SCM proc = scm_env_top_level (env);
+  if (SCM_FALSEP (proc))
+    return SCM_BOOL_T;
+  return ((SCM_NFALSEP (scm_procedure_property (proc,
+                                               scm_sym_system_module)))
+         ? SCM_BOOL_T
+         : SCM_BOOL_F);
+}
+
+void
+scm_modules_prehistory ()
+{
+  scm_pre_modules_obarray 
+    = scm_permanent_object (scm_c_make_hash_table (2001));
+}
+
 void
 scm_init_modules ()
 {
+#ifndef SCM_MAGIC_SNARFER
 #include "libguile/modules.x"
-  module_make_local_var_x = scm_sysintern ("module-make-local-var!",
-                                          SCM_UNDEFINED);
-  f_eval_closure = scm_make_subr_opt ("eval-closure",
-                                     scm_tc7_subr_3,
-                                     eval_closure,
-                                     0);
+#endif
+  module_make_local_var_x_var = scm_c_define ("module-make-local-var!",
+                                           SCM_UNDEFINED);
+  scm_tc16_eval_closure = scm_make_smob_type ("eval-closure", 0);
+  scm_set_smob_mark (scm_tc16_eval_closure, scm_markcdr);
+  scm_set_smob_apply (scm_tc16_eval_closure, scm_eval_closure_lookup, 2, 0, 0);
+
+  the_module = scm_permanent_object (scm_make_fluid ());
 }
 
-void
+static void
 scm_post_boot_init_modules ()
 {
-  scm_module_tag = (SCM_CELL_WORD_1 (SCM_CDR (scm_intern0 ("module-type")))
-                   + scm_tc3_cons_gloc);
-  the_root_module = scm_intern0 ("the-root-module");
-  the_module = scm_intern0 ("the-module");
-  set_current_module = scm_intern0 ("set-current-module");
-  module_prefix = scm_permanent_object (SCM_LIST2 (scm_sym_app,
-                                                  scm_sym_modules));
-  make_modules_in = scm_intern0 ("make-modules-in");
-  beautify_user_module_x = scm_intern0 ("beautify-user-module!");
-  root_module_lookup_closure = scm_permanent_object
-    (scm_module_lookup_closure (SCM_CDR (the_root_module)));
-  resolve_module = scm_intern0 ("resolve-module");
-  try_module_autoload = scm_intern0 ("try-module-autoload");
+#define PERM(x) scm_permanent_object(x)
+
+  SCM module_type = SCM_VARIABLE_REF (scm_c_lookup ("module-type"));
+  scm_module_tag = (SCM_CELL_WORD_1 (module_type) + scm_tc3_cons_gloc);
+
+  resolve_module_var = PERM (scm_c_lookup ("resolve-module"));
+  process_define_module_var = PERM (scm_c_lookup ("process-define-module"));
+  process_use_modules_var = PERM (scm_c_lookup ("process-use-modules"));
+  module_export_x_var = PERM (scm_c_lookup ("module-export!"));
+  the_root_module_var = PERM (scm_c_lookup ("the-root-module"));
+
+#if SCM_DEBUG_DEPRECATED == 0
+
+  module_prefix = PERM (SCM_LIST2 (scm_sym_app, scm_sym_modules));
+  make_modules_in_var = PERM (scm_c_lookup ("make-modules-in"));
+  root_module_lookup_closure =
+    PERM (scm_module_lookup_closure (SCM_VARIABLE_REF (the_root_module_var)));
+  beautify_user_module_x_var = PERM (scm_c_lookup ("beautify-user-module!"));
+  try_module_autoload_var = PERM (scm_c_lookup ("try-module-autoload"));
+
+#endif
+
   scm_module_system_booted_p = 1;
 }
 
+#if SCM_DEBUG_DEPRECATED == 0
+
+SCM
+scm_the_root_module ()
+{
+  scm_c_issue_deprecation_warning ("`scm_the_root_module' is deprecated. "
+                                  "Use `scm_c_resolve_module (\"guile\") "
+                                  "instead.");
+
+  return the_root_module ();
+}
+
+static SCM
+scm_module_full_name (SCM name)
+{
+  if (SCM_EQ_P (SCM_CAR (name), scm_sym_app))
+    return name;
+  else
+    return scm_append (SCM_LIST2 (module_prefix, name));
+}
+
+SCM
+scm_make_module (SCM name)
+{
+  scm_c_issue_deprecation_warning ("`scm_make_module' is deprecated. "
+                                  "Use `scm_c_define_module instead.");
+
+  return scm_apply (SCM_VARIABLE_REF (make_modules_in_var),
+                   SCM_LIST2 (scm_the_root_module (),
+                              scm_module_full_name (name)),
+                   SCM_EOL);
+}
+
+SCM
+scm_ensure_user_module (SCM module)
+{
+  scm_c_issue_deprecation_warning ("`scm_ensure_user_module' is deprecated. "
+                                  "Use `scm_c_define_module instead.");
+
+  scm_apply (SCM_VARIABLE_REF (beautify_user_module_x_var),
+            SCM_LIST1 (module), SCM_EOL);
+  return SCM_UNSPECIFIED;
+}
+
+SCM
+scm_load_scheme_module (SCM name)
+{
+  scm_c_issue_deprecation_warning ("`scm_load_scheme_module' is deprecated. "
+                                  "Use `scm_c_resolve_module instead.");
+
+  return scm_apply (SCM_VARIABLE_REF (try_module_autoload_var),
+                   SCM_LIST1 (name), SCM_EOL);
+}
+
+#endif
+
 /*
   Local Variables:
   c-file-style: "gnu"