-;;; pym.el --- Macros for Your Poe.
+;;; pym.el --- Macros for Your Poe
-;; Copyright (C) 1995,1996,1997,1998,1999 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002
+;; Free Software Foundation, Inc.
;; Author: MORIOKA Tomohiko <tomo@m17n.org>
;; Shuhei KOBAYASHI <shuhei@aqua.ocn.ne.jp>
+;; Katsumi Yamaoka <yamaoka@jpl.org>
;; Keywords: byte-compile, evaluation, edebug, internal
;; This file is part of APEL (A Portable Emacs Library).
;;; Code:
-;; for `load-history'.
-(or (boundp 'current-load-list) (setq current-load-list nil))
-
(require 'static)
;;; Conditional define.
+(defvar def*-maybe-enable-compile-time-hack nil
+ "If non-nil, `def*-maybe' macros will do compile-time check.
+`def*-maybe' macro normally checks existence of its target function or
+variable at load-time. But if this variable is non-nil at compile-time,
+existence of its target is first checked at compile-time, and if exists,
+it will emit no compiled code at all!
+You should set this variable to non-nil only when you really know what
+you are doing.")
+
(put 'defun-maybe 'lisp-indent-function 'defun)
(defmacro defun-maybe (name &rest everything-else)
"Define NAME as a function if NAME is not defined.
-See also the function `defun'."
- (or (and (fboundp name)
- (not (get name 'defun-maybe)))
- (` (or (fboundp (quote (, name)))
- (prog1
- (defun (, name) (,@ everything-else))
- ;; This `defun' will be compiled to `fset',
- ;; which does not update `load-history'.
- ;; We must update `current-load-list' explicitly.
- (setq current-load-list
- (cons (quote (, name)) current-load-list))
- (put (quote (, name)) 'defun-maybe t))))))
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil. In order to always
+check for the existence of NAME, use `defun-when-void' instead. See
+also the function `defun'."
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp name))
+ (get name 'defun-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (prog1
+ (, qname)
+ (if (not (fboundp (, qname)))
+ (progn
+ ;; Use `defalias' to update `load-history'.
+ (defalias (, qname)
+ (function (lambda (,@ everything-else))))
+ (put (, qname) 'defun-maybe t))))))))
(put 'defmacro-maybe 'lisp-indent-function 'defun)
(defmacro defmacro-maybe (name &rest everything-else)
"Define NAME as a macro if NAME is not defined.
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil. In order to always
+check for the existence of NAME, use `defmacro-when-void' instead.
See also the function `defmacro'."
- (or (and (fboundp name)
- (not (get name 'defmacro-maybe)))
- (` (or (fboundp (quote (, name)))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp name))
+ (get name 'defmacro-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (if (fboundp (, qname))
+ (, qname)
(prog1
(defmacro (, name) (,@ everything-else))
- ;; This `defmacro' will be compiled to `fset',
- ;; which does not update `load-history'.
- ;; We must update `current-load-list' explicitly.
- (setq current-load-list
- (cons (quote (, name)) current-load-list))
- (put (quote (, name)) 'defmacro-maybe t))))))
+ ;; Use `defalias' to update `load-history'.
+ (defalias (, qname) (symbol-function (, qname)))
+ (put (, qname) 'defmacro-maybe t)))))))
(put 'defsubst-maybe 'lisp-indent-function 'defun)
(defmacro defsubst-maybe (name &rest everything-else)
"Define NAME as an inline function if NAME is not defined.
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil. In order to always
+check for the existence of NAME, use `defsubst-when-void' instead.
See also the macro `defsubst'."
- (or (and (fboundp name)
- (not (get name 'defsubst-maybe)))
- (` (or (fboundp (quote (, name)))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp name))
+ (get name 'defsubst-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (if (fboundp (, qname))
+ (, qname)
(prog1
(defsubst (, name) (,@ everything-else))
- ;; This `defsubst' will be compiled to `fset',
- ;; which does not update `load-history'.
- ;; We must update `current-load-list' explicitly.
- (setq current-load-list
- (cons (quote (, name)) current-load-list))
- (put (quote (, name)) 'defsubst-maybe t))))))
+ ;; Use `defalias' to update `load-history'.
+ (defalias (, qname) (symbol-function (, qname)))
+ (put (, qname) 'defsubst-maybe t)))))))
(defmacro defalias-maybe (symbol definition)
"Define SYMBOL as an alias for DEFINITION if SYMBOL is not defined.
+Note that it will never produce a byte-compiled code when SYMBOL has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil. In order to always
+check for the existence of SYMBOL, use `defalias-when-void' instead.
See also the function `defalias'."
(setq symbol (eval symbol))
- (or (and (fboundp symbol)
- (not (get symbol 'defalias-maybe)))
- (` (or (fboundp (quote (, symbol)))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp symbol))
+ (get symbol 'defalias-maybe))
+ (let ((qsymbol (` (quote (, symbol)))))
+ (` (if (fboundp (, qsymbol))
+ (symbol-function (, qsymbol))
(prog1
- (defalias (quote (, symbol)) (, definition))
- ;; `defalias' updates `load-history' internally.
- (put (quote (, symbol)) 'defalias-maybe t))))))
+ ;; `defalias' updates `load-history' internally.
+ (defalias (, qsymbol) (, definition))
+ (put (, qsymbol) 'defalias-maybe t)))))))
(defmacro defvar-maybe (name &rest everything-else)
"Define NAME as a variable if NAME is not defined.
-See also the function `defvar'."
- (or (and (boundp name)
- (not (get name 'defvar-maybe)))
- (` (or (boundp (quote (, name)))
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil. In order to always
+check for the existence of NAME, use `defvar-when-void' instead. See
+also the function `defvar'."
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (boundp name))
+ (get name 'defvar-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (if (boundp (, qname))
+ (, qname)
(prog1
+ ;; byte-compiler will generate code to update
+ ;; `load-history'.
(defvar (, name) (,@ everything-else))
- ;; byte-compiler will generate code to update
- ;; `load-history'.
- (put (quote (, name)) 'defvar-maybe t))))))
+ (put (, qname) 'defvar-maybe t)))))))
(defmacro defconst-maybe (name &rest everything-else)
"Define NAME as a constant variable if NAME is not defined.
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil. In order to always
+check for the existence of NAME, use `defconst-when-void' instead.
See also the function `defconst'."
- (or (and (boundp name)
- (not (get name 'defconst-maybe)))
- (` (or (boundp (quote (, name)))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (boundp name))
+ (get name 'defconst-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (if (boundp (, qname))
+ (, qname)
(prog1
+ ;; byte-compiler will generate code to update
+ ;; `load-history'.
(defconst (, name) (,@ everything-else))
- ;; byte-compiler will generate code to update
- ;; `load-history'.
- (put (quote (, name)) 'defconst-maybe t))))))
+ (put (, qname) 'defconst-maybe t)))))))
(defmacro defun-maybe-cond (name args &optional doc &rest clauses)
"Define NAME as a function if NAME is not defined.
-CLAUSES are like those of `cond' expression, but each condition is evaluated
-at compile-time and, if the value is non-nil, the body of the clause is used
-for function definition of NAME.
-See also the function `defun'."
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil.
+CLAUSES are like those of `cond' expression, but each condition is
+evaluated at compile-time and, if the value is non-nil, the body of
+the clause is used for function definition of NAME. See also the
+function `defun'."
(or (stringp doc)
(setq clauses (cons doc clauses)
doc nil))
- (or (and (fboundp name)
- (not (get name 'defun-maybe)))
- (` (or (fboundp (quote (, name)))
- (prog1
- (static-cond
- (,@ (mapcar
- (function
- (lambda (case)
- (list (car case)
- (if doc
- (` (defun (, name) (, args)
- (, doc)
- (,@ (cdr case))))
- (` (defun (, name) (, args)
- (,@ (cdr case))))))))
- clauses)))
- ;; This `defun' will be compiled to `fset',
- ;; which does not update `load-history'.
- ;; We must update `current-load-list' explicitly.
- (setq current-load-list
- (cons (quote (, name)) current-load-list))
- (put (quote (, name)) 'defun-maybe t))))))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp name))
+ (get name 'defun-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (prog1
+ (, qname)
+ (if (not (fboundp (, qname)))
+ (progn
+ (static-cond
+ (,@ (mapcar
+ (function
+ (lambda (case)
+ (list (car case)
+ (if doc
+ (` (defalias (, qname)
+ (function
+ (lambda (, args)
+ (, doc)
+ (,@ (cdr case))))))
+ (` (defalias (, qname)
+ (function
+ (lambda (, args)
+ (,@ (cdr case))))))))))
+ clauses)))
+ (put (, qname) 'defun-maybe t))))))))
(defmacro defmacro-maybe-cond (name args &optional doc &rest clauses)
"Define NAME as a macro if NAME is not defined.
-CLAUSES are like those of `cond' expression, but each condition is evaluated
-at compile-time and, if the value is non-nil, the body of the clause is used
-for macro definition of NAME.
-See also the function `defmacro'."
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil.
+CLAUSES are like those of `cond' expression, but each condition is
+evaluated at compile-time and, if the value is non-nil, the body of
+the clause is used for macro definition of NAME. See also the
+function `defmacro'."
(or (stringp doc)
(setq clauses (cons doc clauses)
doc nil))
- (or (and (fboundp name)
- (not (get name 'defmacro-maybe)))
- (` (or (fboundp (quote (, name)))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp name))
+ (get name 'defmacro-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (if (fboundp (, qname))
+ (, qname)
(prog1
(static-cond
(,@ (mapcar
(lambda (case)
(list (car case)
(if doc
- (` (defmacro (, name) (, args)
- (, doc)
- (,@ (cdr case))))
- (` (defmacro (, name) (, args)
- (,@ (cdr case))))))))
+ (` (prog1
+ (defmacro (, name) (, args)
+ (, doc)
+ (,@ (cdr case)))
+ (defalias (, qname)
+ (symbol-function (, qname)))))
+ (` (prog1
+ (defmacro (, name) (, args)
+ (,@ (cdr case)))
+ (defalias (, qname)
+ (symbol-function (, qname)))))))))
clauses)))
- ;; This `defmacro' will be compiled to `fset',
- ;; which does not update `load-history'.
- ;; We must update `current-load-list' explicitly.
- (setq current-load-list
- (cons (quote (, name)) current-load-list))
- (put (quote (, name)) 'defmacro-maybe t))))))
+ (put (, qname) 'defmacro-maybe t)))))))
(defmacro defsubst-maybe-cond (name args &optional doc &rest clauses)
"Define NAME as an inline function if NAME is not defined.
-CLAUSES are like those of `cond' expression, but each condition is evaluated
-at compile-time and, if the value is non-nil, the body of the clause is used
-for function definition of NAME.
-See also the macro `defsubst'."
+Note that it will never produce a byte-compiled code when NAME has
+already been defined at the compile-time and the value for
+`def*-maybe-enable-compile-time-hack' is non-nil.
+CLAUSES are like those of `cond' expression, but each condition is
+evaluated at compile-time and, if the value is non-nil, the body of
+the clause is used for function definition of NAME. See also the
+macro `defsubst'."
(or (stringp doc)
(setq clauses (cons doc clauses)
doc nil))
- (or (and (fboundp name)
- (not (get name 'defsubst-maybe)))
- (` (or (fboundp (quote (, name)))
+ (if (or (null def*-maybe-enable-compile-time-hack)
+ (not (fboundp name))
+ (get name 'defsubst-maybe))
+ (let ((qname (` (quote (, name)))))
+ (` (if (fboundp (, qname))
+ (, qname)
(prog1
(static-cond
(,@ (mapcar
(lambda (case)
(list (car case)
(if doc
- (` (defsubst (, name) (, args)
- (, doc)
- (,@ (cdr case))))
- (` (defsubst (, name) (, args)
- (,@ (cdr case))))))))
+ (` (prog1
+ (defsubst (, name) (, args)
+ (, doc)
+ (,@ (cdr case)))
+ (defalias (, qname)
+ (symbol-function (, qname)))))
+ (` (prog1
+ (defsubst (, name) (, args)
+ (,@ (cdr case)))
+ (defalias (, qname)
+ (symbol-function (, qname)))))))))
clauses)))
- ;; This `defsubst' will be compiled to `fset',
- ;; which does not update `load-history'.
- ;; We must update `current-load-list' explicitly.
- (setq current-load-list
- (cons (quote (, name)) current-load-list))
- (put (quote (, name)) 'defsubst-maybe t))))))
+ (put (, qname) 'defsubst-maybe t)))))))
+
+
+;;; Conditional define (always do load-time check).
+
+(put 'defun-when-void 'lisp-indent-function 'defun)
+(defmacro defun-when-void (name &rest everything-else)
+ "Define NAME as a function if NAME is not defined at the load-time.
+See also the function `defun' and the macro `defun-maybe'. Note that
+the macro with the same name in XEmacs will be replaced with it."
+ (let ((qname (` (quote (, name)))))
+ (` (prog1
+ (, qname)
+ (if (not (fboundp (, qname)))
+ ;; Use `defalias' to update `load-history'.
+ (defalias (, qname)
+ (function (lambda (,@ everything-else)))))))))
+
+(put 'defmacro-when-void 'lisp-indent-function 'defun)
+(defmacro defmacro-when-void (name &rest everything-else)
+ "Define NAME as a macro if NAME is not defined at the load-time.
+See also the function `defmacro' and the macro `defmacro-maybe'."
+ (let ((qname (` (quote (, name)))))
+ (` (if (fboundp (, qname))
+ (, qname)
+ (prog1
+ (defmacro (, name) (,@ everything-else))
+ ;; Use `defalias' to update `load-history'.
+ (defalias (, qname) (symbol-function (, qname))))))))
+
+(put 'defsubst-when-void 'lisp-indent-function 'defun)
+(defmacro defsubst-when-void (name &rest everything-else)
+ "Define NAME as an inline function if NAME is not defined at the
+load-time. See also the macros `defsubst' and `defsubst-maybe'."
+ (let ((qname (` (quote (, name)))))
+ (` (if (fboundp (, qname))
+ (, qname)
+ (prog1
+ (defsubst (, name) (,@ everything-else))
+ ;; Use `defalias' to update `load-history'.
+ (defalias (, qname) (symbol-function (, qname))))))))
+
+(defmacro defalias-when-void (symbol definition)
+ "Define SYMBOL as an alias for DEFINITION if SYMBOL is not defined at
+the load-time. See also the function `defalias' and the macro
+`defalias-maybe'."
+ (let* ((symbol (eval symbol))
+ (qsymbol (` (quote (, symbol)))))
+ (` (if (fboundp (, qsymbol))
+ (symbol-function (, qsymbol))
+ ;; `defalias' updates `load-history' internally.
+ (defalias (, qsymbol) (, definition))))))
+
+(defmacro defvar-when-void (name &rest everything-else)
+ "Define NAME as a variable if NAME is not defined at the load-time.
+See also the function `defvar' and the macro `defvar-maybe'."
+ (let ((qname (` (quote (, name)))))
+ (` (if (boundp (, qname))
+ (, qname)
+ ;; byte-compiler will generate code to update
+ ;; `load-history'.
+ (defvar (, name) (,@ everything-else))))))
+
+(defmacro defconst-when-void (name &rest everything-else)
+ "Define NAME as a constant variable if NAME is not defined at the
+load-time. See also the function `defconst' and the macro
+`defconst-maybe'."
+ (let ((qname (` (quote (, name)))))
+ (` (if (boundp (, qname))
+ (, qname)
+ ;; byte-compiler will generate code to update
+ ;; `load-history'.
+ (defconst (, name) (,@ everything-else))))))
;;; Edebug spec.