Commit 4dd1c416 authored by Stefan Monnier's avatar Stefan Monnier
Browse files

Cleanup cl-macs namespace. Add macro helpers in macroexp.el.

* emacs-lisp/macroexp.el (macroexp-progn, macroexp-let*, macroexp-if)
(macroexp-let², macroexp--const-symbol-p, macroexp-const-p)
(macroexp-copyable-p): New functions and macros.
* emacs-lisp/edebug.el (edebug-unwrap):
* emacs-lisp/disass.el (disassemble-internal): Use macroexp-progn.
* emacs-lisp/pcase.el: Use macroexp-let*, macroexp-if, ...
(pcase--let*): Remove.
* emacs-lisp/bytecomp.el (byte-compile-const-symbol-p)
(byte-compile-constp): Remove.  Use macroexp--const-symbol-p and
macroexp-const-p instead.
* emacs-lisp/byte-opt.el: Use macroexp-const-p and macroexp-progn.

* emacs-lisp/cl-macs.el: Clean up the name space by using "cl--"
instead of "cl-" for internal definitions.  Use macroexp-const-p.
(cl-old-bc-file-form): Remove var.
(cl-const-exprs-p): Remove fun.
(cl-labels, cl-macrolet): Use backquote.
(cl-lexical-let): Use cl-symbol-macrolet.  Don't use cl-defun-expander.
(cl-defun-expander, cl-byte-compile-compiler-macro): Remove fun.
(cl-define-setf-expander): Rename from cl-define-setf-method.
* emacs-lisp/cl.el: Adjust alias for define-setf-method.

* international/mule-cmds.el: Don't require CL.
(view-hello-file): Don't use `letf'.
parent 7287f2f3
2012-06-07 Stefan Monnier <monnier@iro.umontreal.ca>
* emacs-lisp/macroexp.el (macroexp-progn, macroexp-let*, macroexp-if)
(macroexp-let², macroexp--const-symbol-p, macroexp-const-p)
(macroexp-copyable-p): New functions and macros.
* emacs-lisp/edebug.el (edebug-unwrap):
* emacs-lisp/disass.el (disassemble-internal): Use macroexp-progn.
* emacs-lisp/pcase.el: Use macroexp-let*, macroexp-if, ...
(pcase--let*): Remove.
* emacs-lisp/bytecomp.el (byte-compile-const-symbol-p)
(byte-compile-constp): Remove. Use macroexp--const-symbol-p and
macroexp-const-p instead.
* emacs-lisp/byte-opt.el: Use macroexp-const-p and macroexp-progn.
* emacs-lisp/cl-macs.el: Clean up the name space by using "cl--"
instead of "cl-" for internal definitions. Use macroexp-const-p.
(cl-old-bc-file-form): Remove var.
(cl-const-exprs-p): Remove fun.
(cl-labels, cl-macrolet): Use backquote.
(cl-lexical-let): Use cl-symbol-macrolet. Don't use cl-defun-expander.
(cl-defun-expander, cl-byte-compile-compiler-macro): Remove fun.
(cl-define-setf-expander): Rename from cl-define-setf-method.
* emacs-lisp/cl.el: Adjust alias for define-setf-method.
* international/mule-cmds.el: Don't require CL.
(view-hello-file): Don't use `letf'.
2012-06-07 Stefan Monnier <monnier@iro.umontreal.ca>
 
* tmm.el (tmm-prompt): Use string-prefix-p.
......
......@@ -184,6 +184,7 @@
(require 'bytecomp)
(eval-when-compile (require 'cl))
(require 'macroexp)
(defun byte-compile-log-lap-1 (format &rest args)
;; Newer byte codes for stack-ref make the slot 0 non-nil again.
......@@ -434,11 +435,9 @@
clause))
(cdr form))))
((eq fn 'progn)
;; as an extra added bonus, this simplifies (progn <x>) --> <x>
;; As an extra added bonus, this simplifies (progn <x>) --> <x>.
(if (cdr (cdr form))
(progn
(setq tmp (byte-optimize-body (cdr form) for-effect))
(if (cdr tmp) (cons 'progn tmp) (car tmp)))
(macroexp-progn (byte-optimize-body (cdr form) for-effect))
(byte-optimize-form (nth 1 form) for-effect)))
((eq fn 'prog1)
(if (cdr (cdr form))
......@@ -577,10 +576,10 @@
(cons fn args)))))))
(defun byte-optimize-all-constp (list)
"Non-nil if all elements of LIST satisfy `byte-compile-constp'."
"Non-nil if all elements of LIST satisfy `macroexp-const-p"
(let ((constant t))
(while (and list constant)
(unless (byte-compile-constp (car list))
(unless (macroexp-const-p (car list))
(setq constant nil))
(setq list (cdr list)))
constant))
......@@ -870,8 +869,8 @@
(defun byte-optimize-binary-predicate (form)
(if (byte-compile-constp (nth 1 form))
(if (byte-compile-constp (nth 2 form))
(if (macroexp-const-p (nth 1 form))
(if (macroexp-const-p (nth 2 form))
(condition-case ()
(list 'quote (eval form))
(error form))
......@@ -883,7 +882,7 @@
(let ((ok t)
(rest (cdr form)))
(while (and rest ok)
(setq ok (byte-compile-constp (car rest))
(setq ok (macroexp-const-p (car rest))
rest (cdr rest)))
(if ok
(condition-case ()
......@@ -949,7 +948,7 @@
(defun byte-optimize-quote (form)
(if (or (consp (nth 1 form))
(and (symbolp (nth 1 form))
(not (byte-compile-const-symbol-p form))))
(not (macroexp--const-symbol-p form))))
form
(nth 1 form)))
......@@ -1586,13 +1585,13 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(not (eq (car lap0) 'byte-constant)))
nil
(setq keep-going t)
(if (memq (car lap0) '(byte-constant byte-dup))
(progn
(setq tmp (if (or (not tmp)
(byte-compile-const-symbol-p
(car (cdr lap0))))
(cdr lap0)
(byte-compile-get-constant t)))
(if (memq (car lap0) '(byte-constant byte-dup))
(progn
(setq tmp (if (or (not tmp)
(macroexp--const-symbol-p
(car (cdr lap0))))
(cdr lap0)
(byte-compile-get-constant t)))
(byte-compile-log-lap " %s %s %s\t-->\t%s %s %s"
lap0 lap1 lap2 lap0 lap1
(cons (car lap0) tmp))
......
......@@ -1464,29 +1464,6 @@ extra args."
nil)
(defsubst byte-compile-const-symbol-p (symbol &optional any-value)
"Non-nil if SYMBOL is constant.
If ANY-VALUE is nil, only return non-nil if the value of the symbol is the
symbol itself."
(or (memq symbol '(nil t))
(keywordp symbol)
(if any-value
(or (memq symbol byte-compile-const-variables)
;; FIXME: We should provide a less intrusive way to find out
;; if a variable is "constant".
(and (boundp symbol)
(condition-case nil
(progn (set symbol (symbol-value symbol)) nil)
(setting-constant t)))))))
(defmacro byte-compile-constp (form)
"Return non-nil if FORM is a constant."
`(cond ((consp ,form) (or (eq (car ,form) 'quote)
(and (eq (car ,form) 'function)
(symbolp (cadr ,form)))))
((not (symbolp ,form)))
((byte-compile-const-symbol-p ,form))))
;; Dynamically bound in byte-compile-from-buffer.
;; NB also used in cl.el and cl-macs.el.
(defvar byte-compile--outbuffer)
......@@ -2204,7 +2181,7 @@ list that represents a doc string reference.
(put 'autoload 'byte-hunk-handler 'byte-compile-file-form-autoload)
(defun byte-compile-file-form-autoload (form)
(and (let ((form form))
(while (if (setq form (cdr form)) (byte-compile-constp (car form))))
(while (if (setq form (cdr form)) (macroexp-const-p (car form))))
(null form)) ;Constants only
(eval (nth 5 form)) ;Macro
(eval form)) ;Define the autoload.
......@@ -2510,7 +2487,7 @@ If FORM is a lambda or a macro, byte-compile it as a function."
(when (symbolp arg)
(byte-compile-set-symbol-position arg))
(cond ((or (not (symbolp arg))
(byte-compile-const-symbol-p arg t))
(macroexp--const-symbol-p arg t))
(error "Invalid lambda variable %s" arg))
((eq arg '&rest)
(unless (cdr list)
......@@ -2779,7 +2756,7 @@ for symbols generated by the byte compiler itself."
(if (if (eq (car (car rest)) 'byte-constant)
(or (consp tmp)
(and (symbolp tmp)
(not (byte-compile-const-symbol-p tmp)))))
(not (macroexp--const-symbol-p tmp)))))
(if maycall
(setq body (cons (list 'quote tmp) body)))
(setq body (cons tmp body))))
......@@ -2850,7 +2827,7 @@ for symbols generated by the byte compiler itself."
(let ((byte-compile--for-effect for-effect))
(cond
((not (consp form))
(cond ((or (not (symbolp form)) (byte-compile-const-symbol-p form))
(cond ((or (not (symbolp form)) (macroexp--const-symbol-p form))
(when (symbolp form)
(byte-compile-set-symbol-position form))
(byte-compile-constant form))
......@@ -2863,7 +2840,7 @@ for symbols generated by the byte compiler itself."
((symbolp (car form))
(let* ((fn (car form))
(handler (get fn 'byte-compile)))
(when (byte-compile-const-symbol-p fn)
(when (macroexp--const-symbol-p fn)
(byte-compile-warn "`%s' called as a function" fn))
(and (byte-compile-warning-enabled-p 'interactive-only)
(memq fn byte-compile-interactive-only-functions)
......@@ -2997,7 +2974,7 @@ That command is designed for interactive use only" fn))
"Do various error checks before a use of the variable VAR."
(when (symbolp var)
(byte-compile-set-symbol-position var))
(cond ((or (not (symbolp var)) (byte-compile-const-symbol-p var))
(cond ((or (not (symbolp var)) (macroexp--const-symbol-p var))
(when (byte-compile-warning-enabled-p 'constants)
(byte-compile-warn (if (eq access-type 'let-bind)
"attempt to let-bind %s `%s`"
......@@ -3568,7 +3545,7 @@ discarding."
(byte-compile-form (cons 'progn (nreverse setters))))
(let ((var (car form)))
(and (or (not (symbolp var))
(byte-compile-const-symbol-p var t))
(macroexp--const-symbol-p var t))
(byte-compile-warning-enabled-p 'constants)
(byte-compile-warn
"variable assignment to %s `%s'"
......@@ -4117,8 +4094,8 @@ binding slots have been popped."
(defun byte-compile-autoload (form)
(byte-compile-set-symbol-position 'autoload)
(and (byte-compile-constp (nth 1 form))
(byte-compile-constp (nth 5 form))
(and (macroexp-const-p (nth 1 form))
(macroexp-const-p (nth 5 form))
(eval (nth 5 form)) ; macro-p
(not (fboundp (eval (nth 1 form))))
(byte-compile-warn
......
......@@ -281,7 +281,7 @@ This also does some trivial optimizations to make the form prettier.
;;;;;; cl-assert cl-check-type cl-typep cl-deftype cl-struct-setf-expander
;;;;;; cl-defstruct cl-define-modify-macro cl-callf2 cl-callf cl-letf*
;;;;;; cl-letf cl-rotatef cl-shiftf cl-remf cl-do-pop cl-psetf cl-setf
;;;;;; cl-get-setf-method cl-defsetf cl-define-setf-method cl-declare
;;;;;; cl-get-setf-method cl-defsetf cl-define-setf-expander cl-declare
;;;;;; cl-the cl-locally cl-multiple-value-setq cl-multiple-value-bind
;;;;;; cl-lexical-let* cl-lexical-let cl-symbol-macrolet cl-macrolet
;;;;;; cl-labels cl-flet cl-progv cl-psetq cl-do-all-symbols cl-do-symbols
......@@ -289,7 +289,7 @@ This also does some trivial optimizations to make the form prettier.
;;;;;; cl-return cl-block cl-etypecase cl-typecase cl-ecase cl-case
;;;;;; cl-load-time-value cl-eval-when cl-destructuring-bind cl-function
;;;;;; cl-defmacro cl-defun cl-gentemp cl-gensym) "cl-macs" "cl-macs.el"
;;;;;; "f3973150add70d26cadb8530147dfc99")
;;;;;; "25086e27342ec0990f35f1748a5b7b4e")
;;; Generated autoloads from cl-macs.el
(autoload 'cl-gensym "cl-macs" "\
......@@ -611,7 +611,7 @@ See Info node `(cl)Declarations' for details.
\(fn &rest SPECS)" nil t)
(autoload 'cl-define-setf-method "cl-macs" "\
(autoload 'cl-define-setf-expander "cl-macs" "\
Define a `cl-setf' method.
This method shows how to handle `cl-setf's to places of the form (NAME ARGS...).
The argument forms ARGS are bound according to ARGLIST, as if NAME were
......@@ -624,7 +624,7 @@ form. See `cl-defsetf' for a simpler way to define most setf-methods.
(autoload 'cl-defsetf "cl-macs" "\
Define a `cl-setf' method.
This macro is an easy-to-use substitute for `cl-define-setf-method' that works
This macro is an easy-to-use substitute for `cl-define-setf-expander' that works
well for simple place forms. In the simple `cl-defsetf' form, `cl-setf's of
the form (cl-setf (NAME ARGS...) VAL) are transformed to function or macro
calls of the form (FUNC ARGS... VAL). Example:
......
This diff is collapsed.
......@@ -219,8 +219,8 @@
setf
get-setf-method
defsetf
(define-setf-method . cl-define-setf-expander)
define-setf-expander
define-setf-method
declare
the
locally
......
......@@ -35,6 +35,8 @@
;;; Code:
(require 'macroexp)
;;; The variable byte-code-vector is defined by the new bytecomp.el.
;;; The function byte-decompile-lapcode is defined in byte-opt.el.
;;; Since we don't use byte-decompile-lapcode, let's try not loading byte-opt.
......@@ -155,7 +157,7 @@ redefine OBJECT if it is a symbol."
(t
(insert "Uncompiled body: ")
(let ((print-escape-newlines t))
(prin1 (if (cdr obj) (cons 'progn obj) (car obj))
(prin1 (macroexp-progn obj)
(current-buffer))))))
(if interactive-p
(message "")))
......
......@@ -51,6 +51,8 @@
;;; Code:
(require 'macroexp)
;;; Bug reporting
(defalias 'edebug-submit-bug-report 'report-emacs-bug)
......@@ -1251,10 +1253,7 @@ expressions; a `progn' form will be returned enclosing these forms."
((eq 'edebug-after (car sexp))
(nth 3 sexp))
((eq 'edebug-enter (car sexp))
(let ((forms (nthcdr 2 (nth 1 (nth 3 sexp)))))
(if (> (length forms) 1)
(cons 'progn forms) ;; could return (values forms) instead.
(car forms))))
(macroexp-progn (nthcdr 2 (nth 1 (nth 3 sexp)))))
(t sexp);; otherwise it is not wrapped, so just return it.
)
sexp))
......
......@@ -225,6 +225,84 @@ definitions to shadow the loaded ones for use in file byte-compilation."
(let ((macroexpand-all-environment environment))
(macroexp--expand-all form)))
;;; Handy functions to use in macros.
(defun macroexp-progn (exps)
"Return an expression equivalent to `(progn ,@EXPS)."
(if (cdr exps) `(progn ,@exps) (car exps)))
(defun macroexp-let* (bindings exp)
"Return an expression equivalent to `(let* ,bindings ,exp)."
(cond
((null bindings) exp)
((eq 'let* (car-safe exp)) `(let* (,@bindings ,@(cadr exp)) ,@(cddr exp)))
(t `(let* ,bindings ,exp))))
(defun macroexp-if (test then else)
"Return an expression equivalent to `(if ,test ,then ,else)."
(cond
((eq (car-safe else) 'if)
(if (equal test (nth 1 else))
;; Doing a test a second time: get rid of the redundancy.
`(if ,test ,then ,@(nthcdr 3 else))
`(cond (,test ,then)
(,(nth 1 else) ,(nth 2 else))
(t ,@(nthcdr 3 else)))))
((eq (car-safe else) 'cond)
`(cond (,test ,then)
;; Doing a test a second time: get rid of the redundancy, as above.
,@(remove (assoc test else) (cdr else))))
;; Invert the test if that lets us reduce the depth of the tree.
((memq (car-safe then) '(if cond)) (macroexp-if `(not ,test) else then))
(t `(if ,test ,then ,else))))
(defmacro macroexp-let² (test var exp &rest exps)
"Bind VAR to a copyable expression that returns the value of EXP.
This is like `(let ((v ,EXP)) ,EXPS) except that `v' is a new generated
symbol which EXPS can find in VAR.
TEST should be the name of a predicate on EXP checking whether the `let' can
be skipped; if nil, as is usual, `macroexp-const-p' is used."
(declare (indent 3) (debug (sexp form sexp body)))
(let ((bodysym (make-symbol "body"))
(expsym (make-symbol "exp")))
`(let* ((,expsym ,exp)
(,var (if (,(or test #'macroexp-const-p) ,expsym)
,expsym (make-symbol "x")))
(,bodysym ,(macroexp-progn exps)))
(if (eq ,var ,expsym) ,bodysym
(macroexp-let* (list (list ,var ,expsym))
,bodysym)))))
(defsubst macroexp--const-symbol-p (symbol &optional any-value)
"Non-nil if SYMBOL is constant.
If ANY-VALUE is nil, only return non-nil if the value of the symbol is the
symbol itself."
(or (memq symbol '(nil t))
(keywordp symbol)
(if any-value
(or (memq symbol byte-compile-const-variables)
;; FIXME: We should provide a less intrusive way to find out
;; if a variable is "constant".
(and (boundp symbol)
(condition-case nil
(progn (set symbol (symbol-value symbol)) nil)
(setting-constant t)))))))
(defun macroexp-const-p (exp)
"Return non-nil if EXP will always evaluate to the same value."
(cond ((consp exp) (or (eq (car exp) 'quote)
(and (eq (car exp) 'function)
(symbolp (cadr exp)))))
;; It would sometimes make sense to pass `any-value', but it's not
;; always safe since a "constant" variable may not actually always have
;; the same value.
((symbolp exp) (macroexp--const-symbol-p exp))
(t t)))
(defun macroexp-copyable-p (exp)
"Return non-nil if EXP can be copied without extra cost."
(or (symbolp exp) (macroexp-const-p exp)))
(provide 'macroexp)
;;; macroexp.el ends here
......@@ -53,6 +53,8 @@
;;; Code:
(require 'macroexp)
;; Macro-expansion of pcase is reasonably fast, so it's not a problem
;; when byte-compiling a file, but when interpreting the code, if the pcase
;; is in a loop, the repeated macro-expansion becomes terribly costly, so we
......@@ -94,7 +96,7 @@ PRED patterns can refer to variables bound earlier in the pattern.
E.g. you can match pairs where the cdr is larger than the car with a pattern
like `(,a . ,(pred (< a))) or, with more checks:
`(,(and a (pred numberp)) . ,(and (pred numberp) (pred (< a))))"
(declare (indent 1) (debug case)) ;FIXME: edebug `guard' and vars.
(declare (indent 1) (debug cl-case)) ;FIXME: edebug `guard' and vars.
;; We want to use a weak hash table as a cache, but the key will unavoidably
;; be based on `exp' and `cases', yet `cases' is a fresh new list each time
;; we're called so it'll be immediately GC'd. So we use (car cases) as key
......@@ -225,10 +227,10 @@ of the form (UPAT EXP)."
(cdr case))))
cases))))
(if (null defs) main
(pcase--let* defs main))))
(macroexp-let* defs main))))
(defun pcase-codegen (code vars)
;; Don't use let*, otherwise pcase--let* may merge it with some surrounding
;; Don't use let*, otherwise macroexp-let* may merge it with some surrounding
;; let* which might prevent the setcar/setcdr in pcase--expand's fancy
;; codegen from later metamorphosing this let into a funcall.
`(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars)
......@@ -248,30 +250,7 @@ of the form (UPAT EXP)."
(cond
((eq else :pcase--dontcare) then)
((eq then :pcase--dontcare) (debug) else) ;Can/should this ever happen?
((eq (car-safe else) 'if)
(if (equal test (nth 1 else))
;; Doing a test a second time: get rid of the redundancy.
;; FIXME: ideally, this should never happen because the pcase--split-*
;; funs should have eliminated such things, but pcase--split-member
;; is imprecise, so in practice it can happen occasionally.
`(if ,test ,then ,@(nthcdr 3 else))
`(cond (,test ,then)
(,(nth 1 else) ,(nth 2 else))
(t ,@(nthcdr 3 else)))))
((eq (car-safe else) 'cond)
`(cond (,test ,then)
;; Doing a test a second time: get rid of the redundancy, as above.
,@(remove (assoc test else) (cdr else))))
;; Invert the test if that lets us reduce the depth of the tree.
((memq (car-safe then) '(if cond)) (pcase--if `(not ,test) else then))
(t `(if ,test ,then ,else))))
;; Again, try and reduce nesting.
(defun pcase--let* (binders body)
(if (eq (car-safe body) 'let*)
`(let* ,(append binders (nth 1 body))
,@(nthcdr 2 body))
`(let* ,binders ,body)))
(t (macroexp-if test then else))))
(defun pcase--upat (qpattern)
(cond
......@@ -589,21 +568,17 @@ Otherwise, it defers to REST which is a list of branches of the form
;; A upat of the form (let VAR EXP).
;; (pcase--u1 matches code
;; (cons (cons (nth 1 upat) (nth 2 upat)) vars) rest)
(let* ((exp
(let* ((exp (nth 2 upat))
(found (assq exp vars)))
(if found (cdr found)
(let* ((vs (pcase--fgrep (mapcar #'car vars) exp))
(env (mapcar (lambda (v) (list v (cdr (assq v vars))))
vs)))
(if env `(let* ,env ,exp) exp)))))
(sym (if (symbolp exp) exp (make-symbol "x")))
(body
(pcase--u1 (cons `(match ,sym . ,(nth 1 upat)) matches)
code vars rest)))
(if (eq sym exp)
body
`(let* ((,sym ,exp)) ,body))))
(macroexp-let²
macroexp-copyable-p sym
(let* ((exp (nth 2 upat))
(found (assq exp vars)))
(if found (cdr found)
(let* ((vs (pcase--fgrep (mapcar #'car vars) exp))
(env (mapcar (lambda (v) (list v (cdr (assq v vars))))
vs)))
(if env (macroexp-let* env exp) exp))))
(pcase--u1 (cons `(match ,sym . ,(nth 1 upat)) matches)
code vars rest)))
((eq (car-safe upat) '\`)
(put sym 'pcase-used t)
(pcase--q1 sym (cadr upat) matches code vars rest))
......@@ -695,7 +670,7 @@ Otherwise, it defers to REST which is a list of branches of the form
;; can't signal errors and our byte-compiler is not that clever.
;; FIXME: Some of those let bindings occur too early (they are used in
;; `then-body', but only within some sub-branch).
(pcase--let*
(macroexp-let*
`(,@(if (get syma 'pcase-used) `((,syma (car ,sym))))
,@(if (get symd 'pcase-used) `((,symd (cdr ,sym)))))
then-body)
......
......@@ -30,8 +30,6 @@
;;; Code:
(eval-when-compile (require 'cl)) ; letf
(defvar dos-codepage)
(autoload 'widget-value "wid-edit")
......@@ -285,7 +283,7 @@ wrong, use this command again to toggle back to the right mode."
"Display the HELLO file, which lists many languages and characters."
(interactive)
;; We have to decode the file in any environment.
(letf ((coding-system-for-read 'iso-2022-7bit))
(let ((coding-system-for-read 'iso-2022-7bit))
(view-file (expand-file-name "HELLO" data-directory))))
(defun universal-coding-system-argument (coding-system)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment