x-popup-dialog fixed, almost.
[bpt/emacs.git] / src / eval.c
index cb71669..6e964f6 100644 (file)
@@ -658,6 +658,51 @@ The return value is BASE-VARIABLE.  */)
   return base_variable;
 }
 
+static union specbinding *
+default_toplevel_binding (Lisp_Object symbol)
+{
+  union specbinding *binding = NULL;
+  union specbinding *pdl = specpdl_ptr;
+  while (pdl > specpdl)
+    {
+      switch ((--pdl)->kind)
+       {
+       case SPECPDL_LET_DEFAULT:
+       case SPECPDL_LET:
+         if (EQ (specpdl_symbol (pdl), symbol))
+           binding = pdl;
+         break;
+       }
+    }
+  return binding;
+}
+
+DEFUN ("default-toplevel-value", Fdefault_toplevel_value, Sdefault_toplevel_value, 1, 1, 0,
+       doc: /* Return SYMBOL's toplevel default value.
+"Toplevel" means outside of any let binding.  */)
+  (Lisp_Object symbol)
+{
+  union specbinding *binding = default_toplevel_binding (symbol);
+  Lisp_Object value
+    = binding ? specpdl_old_value (binding) : Fdefault_value (symbol);
+  if (!EQ (value, Qunbound))
+    return value;
+  xsignal1 (Qvoid_variable, symbol);
+}
+
+DEFUN ("set-default-toplevel-value", Fset_default_toplevel_value,
+       Sset_default_toplevel_value, 2, 2, 0,
+       doc: /* Set SYMBOL's toplevel default value to VALUE.
+"Toplevel" means outside of any let binding.  */)
+     (Lisp_Object symbol, Lisp_Object value)
+{
+  union specbinding *binding = default_toplevel_binding (symbol);
+  if (binding)
+    set_specpdl_old_value (binding, value);
+  else
+    Fset_default (symbol, value);
+  return Qnil;
+}
 
 DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0,
        doc: /* Define SYMBOL as a variable, and return SYMBOL.
@@ -706,18 +751,10 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING)  */)
       else
        { /* Check if there is really a global binding rather than just a let
             binding that shadows the global unboundness of the var.  */
-         union specbinding *pdl = specpdl_ptr;
-         while (pdl > specpdl)
+         union specbinding *binding = default_toplevel_binding (sym);
+         if (binding && EQ (specpdl_old_value (binding), Qunbound))
            {
-             if ((--pdl)->kind >= SPECPDL_LET
-                 && EQ (specpdl_symbol (pdl), sym)
-                 && EQ (specpdl_old_value (pdl), Qunbound))
-               {
-                 message_with_string
-                   ("Warning: defvar ignored because %s is let-bound",
-                    SYMBOL_NAME (sym), 1);
-                 break;
-               }
+             set_specpdl_old_value (binding, eval_sub (XCAR (tail)));
            }
        }
       tail = XCDR (tail);
@@ -1996,7 +2033,9 @@ it is defines a macro.  */)
 \f
 DEFUN ("eval", Feval, Seval, 1, 2, 0,
        doc: /* Evaluate FORM and return its value.
-If LEXICAL is t, evaluate using lexical scoping.  */)
+If LEXICAL is t, evaluate using lexical scoping.
+LEXICAL can also be an actual lexical environment, in the form of an
+alist mapping symbols to their value.  */)
   (Lisp_Object form, Lisp_Object lexical)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
@@ -2109,8 +2148,9 @@ eval_sub (Lisp_Object form)
 
   /* Optimize for no indirection.  */
   fun = original_fun;
-  if (SYMBOLP (fun) && !NILP (fun)
-      && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
+  if (!SYMBOLP (fun))
+    fun = Ffunction (Fcons (fun, Qnil));
+  else if (!NILP (fun) && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
     fun = indirect_function (fun);
 
   if (SUBRP (fun))
@@ -3114,20 +3154,17 @@ let_shadows_global_binding_p (Lisp_Object symbol)
   return 0;
 }
 
-/* `specpdl_ptr->symbol' is a field which describes which variable is
+/* `specpdl_ptr' describes which variable is
    let-bound, so it can be properly undone when we unbind_to.
-   It can have the following two shapes:
-   - SYMBOL : if it's a plain symbol, it means that we have let-bound
-     a symbol that is not buffer-local (at least at the time
-     the let binding started).  Note also that it should not be
+   It can be either a plain SPECPDL_LET or a SPECPDL_LET_LOCAL/DEFAULT.
+   - SYMBOL is the variable being bound.  Note that it should not be
      aliased (i.e. when let-binding V1 that's aliased to V2, we want
      to record V2 here).
-   - (SYMBOL WHERE . BUFFER) : this means that it is a let-binding for
-     variable SYMBOL which can be buffer-local.  WHERE tells us
-     which buffer is affected (or nil if the let-binding affects the
-     global value of the variable) and BUFFER tells us which buffer was
-     current (i.e. if WHERE is non-nil, then BUFFER==WHERE, otherwise
-     BUFFER did not yet have a buffer-local value).  */
+   - WHERE tells us in which buffer the binding took place.
+     This is used for SPECPDL_LET_LOCAL bindings (i.e. bindings to a
+     buffer-local variable) as well as for SPECPDL_LET_DEFAULT bindings,
+     i.e. bindings to the default value of a variable which can be
+     buffer-local.  */
 
 void
 specbind (Lisp_Object symbol, Lisp_Object value)
@@ -3264,6 +3301,16 @@ clear_unwind_protect (ptrdiff_t count)
    It need not be at the top of the stack.  Discard the entry's
    previous value without invoking it.  */
 
+void
+set_unwind_protect (ptrdiff_t count, void (*func) (Lisp_Object),
+                   Lisp_Object arg)
+{
+  union specbinding *p = specpdl + count;
+  p->unwind.kind = SPECPDL_UNWIND;
+  p->unwind.func = func;
+  p->unwind.arg = arg;
+}
+
 void
 set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg)
 {
@@ -3311,19 +3358,21 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
        case SPECPDL_BACKTRACE:
          break;
        case SPECPDL_LET:
-         /* If variable has a trivial value (no forwarding), we can
-            just set it.  No need to check for constant symbols here,
-            since that was already done by specbind.  */
-         if (XSYMBOL (specpdl_symbol (specpdl_ptr))->redirect
-             == SYMBOL_PLAINVAL)
-           SET_SYMBOL_VAL (XSYMBOL (specpdl_symbol (specpdl_ptr)),
-                           specpdl_old_value (specpdl_ptr));
-         else
-           /* NOTE: we only ever come here if make_local_foo was used for
-              the first time on this var within this let.  */
-           Fset_default (specpdl_symbol (specpdl_ptr),
-                         specpdl_old_value (specpdl_ptr));
-         break;
+         { /* If variable has a trivial value (no forwarding), we can
+              just set it.  No need to check for constant symbols here,
+              since that was already done by specbind.  */
+           struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (specpdl_ptr));
+           if (sym->redirect == SYMBOL_PLAINVAL)
+             {
+               SET_SYMBOL_VAL (sym, specpdl_old_value (specpdl_ptr));
+               break;
+             }
+           else
+             { /* FALLTHROUGH!!
+                  NOTE: we only ever come here if make_local_foo was used for
+                  the first time on this var within this let.  */
+             }
+         }
        case SPECPDL_LET_DEFAULT:
          Fset_default (specpdl_symbol (specpdl_ptr),
                        specpdl_old_value (specpdl_ptr));
@@ -3511,24 +3560,23 @@ backtrace_eval_unrewind (int distance)
        case SPECPDL_BACKTRACE:
          break;
        case SPECPDL_LET:
-         /* If variable has a trivial value (no forwarding), we can
-            just set it.  No need to check for constant symbols here,
-            since that was already done by specbind.  */
-         if (XSYMBOL (specpdl_symbol (tmp))->redirect
-             == SYMBOL_PLAINVAL)
-           {
-             struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (tmp));
-             Lisp_Object old_value = specpdl_old_value (tmp);
-             set_specpdl_old_value (tmp, SYMBOL_VAL (sym));
-             SET_SYMBOL_VAL (sym, old_value);
-             break;
-           }
-         else
-           {
-             /* FALLTHROUGH!
-                NOTE: we only ever come here if make_local_foo was used for
-                the first time on this var within this let.  */
-           }
+         { /* If variable has a trivial value (no forwarding), we can
+              just set it.  No need to check for constant symbols here,
+              since that was already done by specbind.  */
+           struct Lisp_Symbol *sym = XSYMBOL (specpdl_symbol (tmp));
+           if (sym->redirect == SYMBOL_PLAINVAL)
+             {
+               Lisp_Object old_value = specpdl_old_value (tmp);
+               set_specpdl_old_value (tmp, SYMBOL_VAL (sym));
+               SET_SYMBOL_VAL (sym, old_value);
+               break;
+             }
+           else
+             { /* FALLTHROUGH!!
+                  NOTE: we only ever come here if make_local_foo was used for
+                  the first time on this var within this let.  */
+             }
+         }
        case SPECPDL_LET_DEFAULT:
          {
            Lisp_Object sym = specpdl_symbol (tmp);
@@ -3796,6 +3844,8 @@ alist of active lexical bindings.  */);
   defsubr (&Ssetq);
   defsubr (&Squote);
   defsubr (&Sfunction);
+  defsubr (&Sdefault_toplevel_value);
+  defsubr (&Sset_default_toplevel_value);
   defsubr (&Sdefvar);
   defsubr (&Sdefvaralias);
   defsubr (&Sdefconst);