diff lisp/lisp-mode.el @ 4677:8f1ee2d15784

Support full Common Lisp multiple values in C. lisp/ChangeLog 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * bytecomp.el : Update this file to support full C-level multiple values. This involves: -- Four new bytecodes, and special compiler functions to compile multiple-value-call, multiple-value-list-internal, values, values-list, and, since it now needs to pass back multiple values and is a special form, throw. -- There's a new compiler variable, byte-compile-checks-on-load, which is a list of forms that are evaluated at the very start of a file, with an error thrown if any of them give nil. -- The header is now inserted *after* compilation, giving a chance for the compilation process to influence what those checks are. There is still a check done before compilation for non-ASCII characters, to try to turn off dynamic docstrings if appopriate, in `byte-compile-maybe-reset-coding'. Space is reserved for checks; comments describing the version of the byte compiler generating the file are inserted if space remains for them. * bytecomp.el (byte-compile-version): Update this, we're a newer version of the byte compiler. * byte-optimize.el (byte-optimize-funcall): Correct a comment. * bytecomp.el (byte-compile-lapcode): Discard the arg with byte-multiple-value-call. * bytecomp.el (byte-compile-checks-and-comments-space): New variable, describe how many octets to reserve for checks at the start of byte-compiled files. * cl-compat.el: Remove the fake multiple-value implementation. Have the functions that use it use the real multiple-value implementation instead. * cl-macs.el (cl-block-wrapper, cl-block-throw): Revise the byte-compile properties of these symbols to work now we've made throw into a special form; keep the byte-compile properties as anonymous lambdas, since we don't have docstrings for them. * cl-macs.el (multiple-value-bind, multiple-value-setq) (multiple-value-list, nth-value): Update these functions to work with the C support for multiple values. * cl-macs.el (values): Modify the setf handler for this to call #'multiple-value-list-internal appropriately. * cl-macs.el (cl-setf-do-store): If the store form is a cons, treat it specially as wrapping the store value. * cl.el (cl-block-wrapper): Make this an alias of #'and, not #'identity, since it needs to pass back multiple values. * cl.el (multiple-value-apply): We no longer support this, mark it obsolete. * lisp-mode.el (eval-interactive-verbose): Remove a useless space in the docstring. * lisp-mode.el (eval-interactive): Update this function and its docstring. It now passes back a list, basically wrapping any eval calls with multiple-value-list. This allows multiple values to be printed by default in *scratch*. * lisp-mode.el (prin1-list-as-multiple-values): New function, printing a list as multiple values in the manner of Bruno Haible's clisp, separating each entry with " ;\n". * lisp-mode.el (eval-last-sexp): Call #'prin1-list-as-multiple-values on the return value of #'eval-interactive. * lisp-mode.el (eval-defun): Call #'prin1-list-as-multiple-values on the return value of #'eval-interactive. * mouse.el (mouse-eval-sexp): Deal with lists corresponding to multiple values from #'eval-interactive. Call #'cl-prettyprint, which is always available, instead of sometimes calling #'pprint and sometimes falling back to prin1. * obsolete.el (obsolete-throw): New function, called from eval.c when #'funcall encounters an attempt to call #'throw (now a special form) as a function. Only needed for compatibility with 21.4 byte-code. man/ChangeLog addition: 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * cl.texi (Organization): Remove references to the obsolete multiple-value emulating code. src/ChangeLog addition: 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * bytecode.c (enum Opcode /* Byte codes */): Add four new bytecodes, to deal with multiple values. (POP_WITH_MULTIPLE_VALUES): New macro. (POP): Modify this macro to ignore multiple values. (DISCARD_PRESERVING_MULTIPLE_VALUES): New macro. (DISCARD): Modify this macro to ignore multiple values. (TOP_WITH_MULTIPLE_VALUES): New macro. (TOP_ADDRESS): New macro. (TOP): Modify this macro to ignore multiple values. (TOP_LVALUE): New macro. (Bcall): Ignore multiple values where appropriate. (Breturn): Pass back multiple values. (Bdup): Preserve multiple values. Use TOP_LVALUE with most bytecodes that assign anything to anything. (Bbind_multiple_value_limits, Bmultiple_value_call, Bmultiple_value_list_internal, Bthrow): Implement the new bytecodes. (Bgotoifnilelsepop, Bgotoifnonnilelsepop, BRgotoifnilelsepop, BRgotoifnonnilelsepop): Discard any multiple values. * callint.c (Fcall_interactively): Ignore multiple values when calling #'eval, in two places. * device-x.c (x_IO_error_handler): * macros.c (pop_kbd_macro_event): * eval.c (Fsignal): * eval.c (flagged_a_squirmer): Call throw_or_bomb_out, not Fthrow, now that the latter is a special form. * eval.c: Make Qthrow, Qobsolete_throw available as symbols. Provide multiple_value_current_limit, multiple-values-limit (the latter as specified by Common Lisp. * eval.c (For): Ignore multiple values when comparing with Qnil, but pass any multiple values back for the last arg. * eval.c (Fand): Ditto. * eval.c (Fif): Ignore multiple values when examining the result of the condition. * eval.c (Fcond): Ignore multiple values when comparing what the clauses give, but pass them back if a clause gave non-nil. * eval.c (Fprog2): Never pass back multiple values. * eval.c (FletX, Flet): Ignore multiple when evaluating what exactly symbols should be bound to. * eval.c (Fwhile): Ignore multiple values when evaluating the test. * eval.c (Fsetq, Fdefvar, Fdefconst): Ignore multiple values. * eval.c (Fthrow): Declare this as a special form; ignore multiple values for TAG, preserve them for VALUE. * eval.c (throw_or_bomb_out): Make this available to other files, now Fthrow is a special form. * eval.c (Feval): Ignore multiple values when calling a compiled function, a non-special-form subr, or a lambda expression. * eval.c (Ffuncall): If we attempt to call #'throw (now a special form) as a function, don't error, call #'obsolete-throw instead. * eval.c (make_multiple_value, multiple_value_aset) (multiple_value_aref, print_multiple_value, mark_multiple_value) (size_multiple_value): Implement the multiple_value type. Add a long comment describing our implementation. * eval.c (bind_multiple_value_limits): New function, used by the bytecode and by #'multiple-value-call, #'multiple-value-list-internal. * eval.c (multiple_value_call): New function, used by the bytecode and #'multiple-value-call. * eval.c (Fmultiple_value_call): New special form. * eval.c (multiple_value_list_internal): New function, used by the byte code and #'multiple-value-list-internal. * eval.c (Fmultiple_value_list_internal, Fmultiple_value_prog1): New special forms. * eval.c (Fvalues, Fvalues_list): New Lisp functions. * eval.c (values2): New function, for C code returning multiple values. * eval.c (syms_of_eval): Make our new Lisp functions and symbols available. * eval.c (multiple-values-limit): Make this available to Lisp. * event-msw.c (dde_eval_string): * event-stream.c (execute_help_form): * glade.c (connector): * glyphs-widget.c (glyph_instantiator_to_glyph): * glyphs.c (evaluate_xpm_color_symbols): * gui-x.c (wv_set_evalable_slot, button_item_to_widget_value): * gui.c (gui_item_value, gui_item_display_flush_left): * lread.c (check_if_suppressed): * menubar-gtk.c (menu_convert, menu_descriptor_to_widget_1): * menubar-msw.c (populate_menu_add_item): * print.c (Fwith_output_to_temp_buffer): * symbols.c (Fsetq_default): Ignore multiple values when calling Feval. * symeval.h: Add the header declarations necessary for the multiple-values implementation. * inline.c: #include symeval.h, now that it has some inline functions. * lisp.h: Update Fthrow's declaration. Make throw_or_bomb_out available to all files. * lrecord.h (enum lrecord_type): Add the multiple_value type here.
author Aidan Kehoe <kehoea@parhasard.net>
date Sun, 16 Aug 2009 20:55:49 +0100
parents 830872ebe096
children 46f0df723e09
line wrap: on
line diff
--- a/lisp/lisp-mode.el	Sun Aug 16 14:58:57 2009 +0100
+++ b/lisp/lisp-mode.el	Sun Aug 16 20:55:49 2009 +0100
@@ -424,36 +424,55 @@
 been treated noninteractively.
 
 The printed messages are \"defvar treated as defconst\" and \"defcustom
- evaluation forced\".  See `eval-interactive' for more details."
+evaluation forced\".  See `eval-interactive' for more details."
   :type 'boolean
   :group 'lisp)
 
 (defun eval-interactive (expr)
-  "Like `eval' except that it transforms defvars to defconsts.
-The evaluation of defcustom forms is forced."
+  "Evaluate EXPR; pass back multiple values, transform defvars to defconsts. 
+
+Always returns a list.  The length of this list will be something other than
+one if the form returned multiple values.  It will be zero if the form
+returned a single zero-length multiple value."
   (cond ((and (eq (car-safe expr) 'defvar)
 	      (> (length expr) 2))
-	 (eval (cons 'defconst (cdr expr)))
+	 (setq expr (multiple-value-list (eval (cons 'defconst (cdr expr)))))
 	 (when eval-interactive-verbose
 	   (message "defvar treated as defconst")
 	   (sit-for 1)
 	   (message ""))
-	 (nth 1 expr))
+         expr)
 	((and (eq (car-safe expr) 'defcustom)
 	      (> (length expr) 2)
 	      (default-boundp (nth 1 expr)))
 	 ;; Force variable to be bound
-	 ;; #### defcustom might specify a different :set method.
-	 (set-default (nth 1 expr) (eval (nth 2 expr)))
+         (funcall 
+          (or (plist-get expr :set) #'custom-set-default)
+          (nth 1 expr) (eval (nth 2 expr)))
 	 ;; And evaluate the defcustom
-	 (eval expr)
+	 (setq expr (multiple-value-list (eval expr)))
 	 (when eval-interactive-verbose
 	   (message "defcustom evaluation forced")
 	   (sit-for 1)
 	   (message ""))
-	 (nth 1 expr))
+         expr)
 	(t
-	 (eval expr))))
+	 (multiple-value-list (eval expr)))))
+
+(defun prin1-list-as-multiple-values (multiple-value-list &optional stream)
+  "Call `prin1' on each element of MULTIPLE-VALUE-LIST, separated by \" ;\\n\"
+
+If MULTIPLE-VALUE-LIST is zero-length, print the text
+\"#<zero length multiple value> ;\\n\".  Always returns nil."
+  (loop for value in multiple-value-list
+    with seen-first = nil
+    do
+    (if seen-first
+        (princ " ;\n" stream)
+      (setq seen-first t))
+    (prin1 value stream)
+    finally (unless seen-first
+	      (princ "#<zero length multiple value> ;" stream))))
 
 ;; XEmacs change, based on Bob Weiner suggestion
 (defun eval-last-sexp (eval-last-sexp-arg-internal) ;dynamic scoping wonderment
@@ -463,31 +482,32 @@
   (let ((standard-output (if eval-last-sexp-arg-internal (current-buffer) t))
 	(opoint (point))
 	ignore-quotes)
-    (prin1 (eval-interactive
-	    (letf (((syntax-table) emacs-lisp-mode-syntax-table))
-	      (save-excursion
-		;; If this sexp appears to be enclosed in `...' then
-		;; ignore the surrounding quotes.
-		(setq ignore-quotes (or (eq (char-after) ?\')
-					(eq (char-before) ?\')))
-		(forward-sexp -1)
-		;; vladimir@cs.ualberta.ca 30-Jul-1997: skip ` in
-		;; `variable' so that the value is returned, not the
-		;; name.
-		(if (and ignore-quotes
-			 (eq (char-after) ?\`))
-		    (forward-char))
-		(save-restriction
-		  (narrow-to-region (point-min) opoint)
-		  (let ((expr (read (current-buffer))))
-		    (if (eq (car-safe expr) 'interactive)
-			;; If it's an (interactive ...) form, it's
-			;; more useful to show how an interactive call
-			;; would use it.
-			`(call-interactively
-			  (lambda (&rest args)
-			    ,expr args))
-		      expr)))))))))
+    (prin1-list-as-multiple-values
+     (eval-interactive
+      (letf (((syntax-table) emacs-lisp-mode-syntax-table))
+        (save-excursion
+          ;; If this sexp appears to be enclosed in `...' then
+          ;; ignore the surrounding quotes.
+          (setq ignore-quotes (or (eq (char-after) ?\')
+                                  (eq (char-before) ?\')))
+          (forward-sexp -1)
+          ;; vladimir@cs.ualberta.ca 30-Jul-1997: skip ` in
+          ;; `variable' so that the value is returned, not the
+          ;; name.
+          (if (and ignore-quotes
+                   (eq (char-after) ?\`))
+              (forward-char))
+          (save-restriction
+            (narrow-to-region (point-min) opoint)
+            (let ((expr (read (current-buffer))))
+              (if (eq (car-safe expr) 'interactive)
+                  ;; If it's an (interactive ...) form, it's
+                  ;; more useful to show how an interactive call
+                  ;; would use it.
+                  `(call-interactively
+                    (lambda (&rest args)
+                      ,expr args))
+                expr)))))))))
 
 (defun eval-defun (eval-defun-arg-internal)
   "Evaluate defun that point is in or before.
@@ -495,11 +515,12 @@
 With argument, insert value in current buffer after the defun."
   (interactive "P")
   (let ((standard-output (if eval-defun-arg-internal (current-buffer) t)))
-    (prin1 (eval-interactive (save-excursion
-			       (end-of-defun)
-			       (beginning-of-defun)
-			       (read (current-buffer)))))))
-
+    (prin1-list-as-multiple-values
+     (eval-interactive
+      (save-excursion
+        (end-of-defun)
+        (beginning-of-defun)
+        (read (current-buffer)))))))
 
 (defun lisp-comment-indent ()
   (if (looking-at "\\s<\\s<\\s<")