From: Paul Pogonyshev <pogonyshev@gmail.com>
To: Philipp Stephani <p.stephani2@gmail.com>
Cc: emacs-devel@gnu.org
Subject: Re: Arbitrary function: find the number(s) of expected arguments
Date: Sat, 19 Mar 2016 17:51:39 +0100 [thread overview]
Message-ID: <CAG7BpaqRFpD=bup9uTf4ZX_BquX7K92GOVyWu60PzTEuDaOxaw@mail.gmail.com> (raw)
In-Reply-To: <CAArVCkQYEYvhPx2UM6-8o380itOTo88tjyD2V1saqDpnWP9E3A@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 598 bytes --]
Approximate patch, without documentation. If this is accepted, I can write
documentation too. I submitted legal papers for FSF years ago.
(func-arity 'car) (1 . 1)
(func-arity 'caar) (1 . 1)
(func-arity 'magit-log-all) (0 . 2)
(func-arity 'format) (1 . many)
(func-arity (lambda (&rest x))) (0 . many)
Return value is the same as with `subr-arity' except here any callable is
accepted and you don't need `symbol-function' or `indirect-function'.
Autoloading is also supported transparently.
Paul
[-- Attachment #1.2: Type: text/html, Size: 1044 bytes --]
[-- Attachment #2: func-arity.diff --]
[-- Type: text/plain, Size: 5316 bytes --]
diff --git a/src/bytecode.c b/src/bytecode.c
index 9ae2e82..ca04c28 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -1987,6 +1987,22 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
return result;
}
+Lisp_Object
+get_byte_code_arity (Lisp_Object args_template)
+{
+ if (INTEGERP (args_template))
+ {
+ ptrdiff_t at = XINT (args_template);
+ bool rest = (at & 128) != 0;
+ int mandatory = at & 127;
+ ptrdiff_t nonrest = at >> 8;
+
+ return Fcons (make_number (mandatory), rest ? Qmany : make_number (nonrest));
+ }
+ else
+ error ("Unknown args template!");
+}
+
void
syms_of_bytecode (void)
{
diff --git a/src/eval.c b/src/eval.c
index 74b30e6..40ed24c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -90,6 +90,7 @@ union specbinding *backtrace_top (void) EXTERNALLY_VISIBLE;
static Lisp_Object funcall_lambda (Lisp_Object, ptrdiff_t, Lisp_Object *);
static Lisp_Object apply_lambda (Lisp_Object, Lisp_Object, ptrdiff_t);
+static Lisp_Object lambda_arity (Lisp_Object);
static Lisp_Object
specpdl_symbol (union specbinding *pdl)
@@ -2934,6 +2935,122 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
return unbind_to (count, val);
}
+DEFUN ("func-arity", Ffunc_arity, Sfunc_arity, 1, 1, 0,
+ doc: /* Return minimum and maximum number of args allowed for FUNCTION.
+FUNCTION must be a function of some kind.
+The returned value is a pair (MIN . MAX). MIN is the minimum number
+of args. MAX is the maximum number or the symbol `many', for a
+function with `&rest' args, or `unevalled' for a special form. */)
+ (Lisp_Object function)
+{
+ Lisp_Object original;
+ Lisp_Object funcar;
+ Lisp_Object result;
+ short minargs, maxargs;
+
+ original = function;
+
+ retry:
+
+ /* Optimize for no indirection. */
+ function = original;
+ if (SYMBOLP (function) && !NILP (function)
+ && (function = XSYMBOL (function)->function, SYMBOLP (function)))
+ function = indirect_function (function);
+
+ if (SUBRP (function))
+ {
+ minargs = XSUBR (function)->min_args;
+ maxargs = XSUBR (function)->max_args;
+ result = Fcons (make_number (minargs),
+ maxargs == MANY ? Qmany
+ : maxargs == UNEVALLED ? Qunevalled
+ : make_number (maxargs));
+ }
+ else if (COMPILEDP (function))
+ result = lambda_arity (function);
+ else
+ {
+ if (NILP (function))
+ xsignal1 (Qvoid_function, original);
+ if (!CONSP (function))
+ xsignal1 (Qinvalid_function, original);
+ funcar = XCAR (function);
+ if (!SYMBOLP (funcar))
+ xsignal1 (Qinvalid_function, original);
+ if (EQ (funcar, Qlambda)
+ || EQ (funcar, Qclosure))
+ result = lambda_arity (function);
+ else if (EQ (funcar, Qautoload))
+ {
+ Fautoload_do_load (function, original, Qnil);
+ goto retry;
+ }
+ else
+ xsignal1 (Qinvalid_function, original);
+ }
+ return result;
+}
+
+/* FUN must be either a lambda-expression or a compiled-code object. */
+static Lisp_Object
+lambda_arity (Lisp_Object fun)
+{
+ Lisp_Object val, syms_left, next;
+ ptrdiff_t minargs, maxargs;
+ bool optional;
+
+ if (CONSP (fun))
+ {
+ if (EQ (XCAR (fun), Qclosure))
+ {
+ fun = XCDR (fun); /* Drop `closure'. */
+ CHECK_LIST_CONS (fun, fun);
+ }
+ syms_left = XCDR (fun);
+ if (CONSP (syms_left))
+ syms_left = XCAR (syms_left);
+ else
+ xsignal1 (Qinvalid_function, fun);
+ }
+ else if (COMPILEDP (fun))
+ {
+ ptrdiff_t size = ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK;
+ if (size <= COMPILED_STACK_DEPTH)
+ xsignal1 (Qinvalid_function, fun);
+ syms_left = AREF (fun, COMPILED_ARGLIST);
+ if (INTEGERP (syms_left))
+ return get_byte_code_arity (syms_left);
+ }
+ else
+ emacs_abort ();
+
+ minargs = maxargs = optional = 0;
+ for (; CONSP (syms_left); syms_left = XCDR (syms_left))
+ {
+ next = XCAR (syms_left);
+ if (!SYMBOLP (next))
+ xsignal1 (Qinvalid_function, fun);
+
+ if (EQ (next, Qand_rest))
+ return Fcons (make_number (minargs), Qmany);
+ else if (EQ (next, Qand_optional))
+ optional = 1;
+ else
+ {
+ if (!optional)
+ minargs++;
+ maxargs++;
+ }
+ }
+
+ if (!NILP (syms_left))
+ xsignal1 (Qinvalid_function, fun);
+
+ return Fcons (make_number (minargs), make_number (maxargs));
+}
+
+
DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
1, 1, 0,
doc: /* If byte-compiled OBJECT is lazy-loaded, fetch it now. */)
@@ -3808,6 +3925,7 @@ alist of active lexical bindings. */);
defsubr (&Seval);
defsubr (&Sapply);
defsubr (&Sfuncall);
+ defsubr (&Sfunc_arity);
defsubr (&Srun_hooks);
defsubr (&Srun_hook_with_args);
defsubr (&Srun_hook_with_args_until_success);
diff --git a/src/lisp.h b/src/lisp.h
index d0abb24..cd0c0fc 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4214,6 +4214,7 @@ extern struct byte_stack *byte_stack_list;
extern void relocate_byte_stack (void);
extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, ptrdiff_t, Lisp_Object *);
+extern Lisp_Object get_byte_code_arity (Lisp_Object);
/* Defined in macros.c. */
extern void init_macros (void);
next prev parent reply other threads:[~2016-03-19 16:51 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-15 18:48 Arbitrary function: find the number(s) of expected arguments Paul Pogonyshev
2016-03-15 22:45 ` Davis Herring
2016-03-16 7:41 ` Paul Pogonyshev
2016-03-19 12:26 ` Paul Pogonyshev
2016-03-19 13:10 ` Eli Zaretskii
2016-03-19 13:42 ` Paul Pogonyshev
2016-03-19 13:54 ` Michael Heerdegen
2016-03-19 14:08 ` Eli Zaretskii
2016-03-19 15:20 ` Michael Heerdegen
2016-03-19 15:43 ` Eli Zaretskii
2016-03-19 15:57 ` Michael Heerdegen
2016-03-19 16:24 ` Eli Zaretskii
2016-03-19 17:43 ` Michael Heerdegen
2016-03-19 17:50 ` Eli Zaretskii
2016-03-19 17:59 ` Michael Heerdegen
2016-03-19 18:14 ` Eli Zaretskii
2016-03-19 16:14 ` Philipp Stephani
2016-03-19 16:27 ` Michael Heerdegen
2016-03-19 16:27 ` Eli Zaretskii
2016-03-19 16:30 ` Philipp Stephani
2016-03-19 16:32 ` Eli Zaretskii
2016-03-19 16:34 ` Philipp Stephani
2016-03-19 16:46 ` Philipp Stephani
2016-03-19 16:47 ` Eli Zaretskii
2016-03-19 17:16 ` Philipp Stephani
2016-03-19 17:48 ` Eli Zaretskii
2016-03-19 17:49 ` Philipp Stephani
2016-03-19 18:11 ` Eli Zaretskii
2016-03-19 18:35 ` Michael Heerdegen
2016-04-18 23:02 ` Davis Herring
2016-03-19 19:52 ` Stefan Monnier
2016-03-19 20:33 ` Eli Zaretskii
2016-03-19 22:43 ` Stefan Monnier
2016-03-26 15:55 ` Elias Mårtenson
2016-03-26 17:20 ` Stefan Monnier
2016-03-19 14:26 ` Philipp Stephani
2016-03-19 16:51 ` Paul Pogonyshev [this message]
2016-03-19 18:09 ` Eli Zaretskii
2016-03-19 19:32 ` Michael Heerdegen
2016-03-19 19:39 ` Eli Zaretskii
2016-03-19 20:59 ` Michael Heerdegen
2016-03-21 18:36 ` Paul Pogonyshev
2016-03-25 8:44 ` Eli Zaretskii
2016-03-25 16:16 ` Paul Pogonyshev
2016-03-25 16:35 ` Drew Adams
2016-03-25 17:16 ` Paul Pogonyshev
2016-03-25 18:19 ` Drew Adams
2016-03-25 18:28 ` Clément Pit--Claudel
2016-03-25 18:51 ` Use plain-text for mail [was: Arbitrary function: find the number(s) of expected arguments] Drew Adams
2016-03-25 18:57 ` Use plain-text for mail [ Lars Magne Ingebrigtsen
2016-03-25 19:49 ` Andreas Schwab
2016-03-26 1:12 ` Use plain-text for mail [was: Arbitrary function: find the number(s) of expected arguments] Yuri Khan
2016-03-25 17:39 ` Arbitrary function: find the number(s) of expected arguments Eli Zaretskii
2016-03-25 18:31 ` Drew Adams
2016-03-26 8:27 ` Eli Zaretskii
2016-03-26 11:42 ` Paul Pogonyshev
2016-04-02 9:48 ` Eli Zaretskii
[not found] ` <<83y49e731p.fsf@gnu.org>
2016-03-19 19:21 ` Drew Adams
2016-04-18 18:43 ` Davis Herring
2016-03-16 3:47 ` Stefan Monnier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAG7BpaqRFpD=bup9uTf4ZX_BquX7K92GOVyWu60PzTEuDaOxaw@mail.gmail.com' \
--to=pogonyshev@gmail.com \
--cc=emacs-devel@gnu.org \
--cc=p.stephani2@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.