Optimize 'string-hash'.
[bpt/guile.git] / libguile / throw.c
index 486228e..663a48b 100644 (file)
    baggage. */
 
 
-#define CACHE_VAR(var,name)                                             \
-  static SCM var = SCM_BOOL_F;                                          \
-  if (scm_is_false (var))                                               \
-    {                                                                   \
-      var = scm_module_variable (scm_the_root_module (),                \
-                                 scm_from_locale_symbol (name));        \
-      if (scm_is_false (var))                                           \
-        abort ();                                                       \
-    }
-
 \f
 
+static SCM catch_var, throw_var, with_throw_handler_var;
+
 SCM
 scm_catch (SCM key, SCM thunk, SCM handler)
 {
-  CACHE_VAR (var, "catch");
-
-  return scm_call_3 (scm_variable_ref (var), key, thunk, handler);
+  return scm_call_3 (scm_variable_ref (catch_var), key, thunk, handler);
 }
 
 SCM
@@ -80,28 +70,32 @@ scm_catch_with_pre_unwind_handler (SCM key, SCM thunk, SCM handler,
   if (SCM_UNBNDP (pre_unwind_handler))
     return scm_catch (key, thunk, handler);
   else
-    {
-      CACHE_VAR (var, "catch");
-      
-      return scm_call_4 (scm_variable_ref (var), key, thunk, handler,
-                         pre_unwind_handler);
-    }
+    return scm_call_4 (scm_variable_ref (catch_var), key, thunk, handler,
+                       pre_unwind_handler);
+}
+
+static void
+init_with_throw_handler_var (void)
+{
+  with_throw_handler_var
+    = scm_module_variable (scm_the_root_module (),
+                           scm_from_latin1_symbol ("with-throw-handler"));
 }
 
 SCM
 scm_with_throw_handler (SCM key, SCM thunk, SCM handler)
 {
-  CACHE_VAR (var, "with-throw-handler");
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_i_pthread_once (&once, init_with_throw_handler_var);
 
-  return scm_call_3 (scm_variable_ref (var), key, thunk, handler);
+  return scm_call_3 (scm_variable_ref (with_throw_handler_var),
+                     key, thunk, handler);
 }
 
 SCM
 scm_throw (SCM key, SCM args)
 {
-  CACHE_VAR (var, "throw");
-
-  return scm_apply_1 (scm_variable_ref (var), key, args);
+  return scm_apply_1 (scm_variable_ref (throw_var), key, args);
 }
 
 \f
@@ -335,109 +329,43 @@ scm_exit_status (SCM args)
 }
        
 
+static int
+should_print_backtrace (SCM tag, SCM stack)
+{
+  return SCM_BACKTRACE_P
+    && scm_is_true (stack)
+    && scm_initialized_p
+    /* It's generally not useful to print backtraces for errors reading
+       or expanding code in these fallback catch statements. */
+    && !scm_is_eq (tag, scm_from_latin1_symbol ("read-error"))
+    && !scm_is_eq (tag, scm_from_latin1_symbol ("syntax-error"));
+}
+
 static void
 handler_message (void *handler_data, SCM tag, SCM args)
 {
-  char *prog_name = (char *) handler_data;
-  SCM p = scm_current_error_port ();
-
-  if (scm_is_eq (tag, scm_from_latin1_symbol ("syntax-error"))
-      && scm_ilength (args) >= 5)
+  SCM p, stack, frame;
+
+  p = scm_current_error_port ();
+  /* Usually we get here via a throw to a catch-all.  In that case
+     there is the throw frame active, and the catch closure, so narrow by
+     two frames.  It is possible for a user to invoke
+     scm_handle_by_message directly, though, so it could be this
+     narrows too much.  We'll have to see how this works out in
+     practice.  */
+  stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
+  frame = scm_is_true (stack) ? scm_stack_ref (stack, SCM_INUM0) : SCM_BOOL_F;
+
+  if (should_print_backtrace (tag, stack))
     {
-      SCM who = SCM_CAR (args);
-      SCM what = SCM_CADR (args);
-      SCM where = SCM_CADDR (args);
-      SCM form = SCM_CADDDR (args);
-      SCM subform = SCM_CAR (SCM_CDDDDR (args));
-
-      scm_puts ("Syntax error:\n", p);
-
-      if (scm_is_true (where))
-        {
-          SCM file, line, col;
-
-          file = scm_assq_ref (where, scm_sym_filename);
-          line = scm_assq_ref (where, scm_sym_line);
-          col = scm_assq_ref (where, scm_sym_column);
-
-          if (scm_is_true (file))
-            scm_display (file, p);
-          else
-            scm_puts ("unknown file", p);
-          scm_puts (":", p);
-          scm_display (line, p);
-          scm_puts (":", p);
-          scm_display (col, p);
-          scm_puts (": ", p);
-        }
-      else
-        scm_puts ("unknown location: ", p);
-
-      if (scm_is_true (who))
-        {
-          scm_display (who, p);
-          scm_puts (": ", p);
-        }
-      
-      scm_display (what, p);
-
-      if (scm_is_true (subform))
-        {
-          scm_puts (" in subform ", p);
-          scm_write (subform, p);
-          scm_puts (" of ", p);
-          scm_write (form, p);
-        }
-      else if (scm_is_true (form))
-        {
-          scm_puts (" in form ", p);
-          scm_write (form, p);
-        }
-
+      scm_puts ("Backtrace:\n", p);
+      scm_display_backtrace_with_highlights (stack, p,
+                                             SCM_BOOL_F, SCM_BOOL_F,
+                                             SCM_EOL);
       scm_newline (p);
     }
-  else if (scm_ilength (args) == 4)
-    {
-      SCM stack   = scm_make_stack (SCM_BOOL_T, SCM_EOL);
-      SCM subr    = SCM_CAR (args);
-      SCM message = SCM_CADR (args);
-      SCM parts   = SCM_CADDR (args);
-      SCM rest    = SCM_CADDDR (args);
-
-      if (SCM_BACKTRACE_P && scm_is_true (stack) && scm_initialized_p)
-       {
-         SCM highlights;
-
-         if (scm_is_eq (tag, scm_arg_type_key)
-             || scm_is_eq (tag, scm_out_of_range_key))
-           highlights = rest;
-         else
-           highlights = SCM_EOL;
-
-         scm_puts ("Backtrace:\n", p);
-         scm_display_backtrace_with_highlights (stack, p,
-                                                SCM_BOOL_F, SCM_BOOL_F,
-                                                highlights);
-         scm_newline (p);
-       }
-      scm_i_display_error (scm_is_true (stack)
-                           ? scm_stack_ref (stack, SCM_INUM0) : SCM_BOOL_F,
-                           p, subr, message, parts, rest);
-    }
-  else
-    {
-      if (! prog_name)
-       prog_name = "guile";
-
-      scm_puts (prog_name, p);
-      scm_puts (": ", p);
 
-      scm_puts ("uncaught throw to ", p);
-      scm_prin1 (tag, p, 0);
-      scm_puts (": ", p);
-      scm_prin1 (args, p, 1);
-      scm_putc ('\n', p);
-    }
+  scm_print_exception (p, frame, tag, args);
 }
 
 
@@ -502,7 +430,7 @@ scm_handle_by_throw (void *handler_data SCM_UNUSED, SCM tag, SCM args)
 }
 
 SCM
-scm_ithrow (SCM key, SCM args, int noreturn SCM_UNUSED)
+scm_ithrow (SCM key, SCM args, int no_return SCM_UNUSED)
 {
   return scm_throw (key, args);
 }
@@ -533,7 +461,7 @@ pre_init_catch (SCM tag, SCM thunk, SCM handler, SCM pre_unwind_handler)
   if (SCM_PROMPT_SETJMP (prompt))
     {
       /* nonlocal exit */
-      SCM args = scm_i_prompt_pop_abort_args_x (prompt);
+      SCM args = scm_i_prompt_pop_abort_args_x (vm);
       /* cdr past the continuation */
       return scm_apply_0 (handler, scm_cdr (args));
     }
@@ -566,8 +494,28 @@ pre_init_throw (SCM k, SCM args)
     return scm_at_abort (sym_pre_init_catch_tag, scm_cons (k, args));
   else
     { 
-      fprintf (stderr, "Throw without catch before boot:\n");
-      scm_handle_by_message_noexit (NULL, k, args);
+      static int error_printing_error = 0;
+      static int error_printing_fallback = 0;
+      
+      if (error_printing_fallback)
+        fprintf (stderr, "\nFailed to print exception.\n");
+      else if (error_printing_error)
+        {
+          fprintf (stderr, "\nError while printing exception:\n");
+          error_printing_fallback = 1;
+          fprintf (stderr, "Key: ");
+          scm_write (k, scm_current_error_port ());
+          fprintf (stderr, ", args: ");
+          scm_write (args, scm_current_error_port ());
+          scm_newline (scm_current_error_port ());
+        }
+      else
+        {
+          fprintf (stderr, "Throw without catch before boot:\n");
+          error_printing_error = 1;
+          scm_handle_by_message_noexit (NULL, k, args);
+        }
+
       fprintf (stderr, "Aborting.\n");
       abort ();
       return SCM_BOOL_F; /* not reached */
@@ -580,8 +528,10 @@ scm_init_throw ()
   tc16_catch_closure = scm_make_smob_type ("catch-closure", 0);
   scm_set_smob_apply (tc16_catch_closure, apply_catch_closure, 0, 0, 1);
 
-  scm_c_define ("catch", scm_c_make_gsubr ("catch", 3, 1, 0, pre_init_catch));
-  scm_c_define ("throw", scm_c_make_gsubr ("throw", 1, 0, 1, pre_init_throw));
+  catch_var = scm_c_define ("catch", scm_c_make_gsubr ("catch", 3, 1, 0,
+                                                       pre_init_catch));
+  throw_var = scm_c_define ("throw", scm_c_make_gsubr ("throw", 1, 0, 1,
+                                                       pre_init_throw));
 
 #include "libguile/throw.x"
 }