diff options
| author | Stefan Monnier | 2024-03-11 16:12:26 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2024-04-18 15:28:36 -0400 |
| commit | 126be02077520a943252d0d219bb7677466d0168 (patch) | |
| tree | f762237714f11b303c708f93f09a8dc72426bb2a /src/data.c | |
| parent | 7842af6095db4384898725fb4a14ebaa11379a34 (diff) | |
| download | emacs-scratch/interpreted-function.tar.gz emacs-scratch/interpreted-function.zip | |
Use a dedicated type to represent interpreted-function valuesscratch/interpreted-function
Change `function` so that when evaluating #'(lambda ...)
we return an object of type `interpreted-function` rather than
a list starting with one of `lambda` or `closure`.
The new type reuses the existing PVEC_CLOSURE (nee PVEC_COMPILED)
tag and tries to align the corresponding elements:
- the arglist, the docstring, and the interactive-form go in the
same slots as for byte-code functions.
- the body of the function goes in the slot used for the bytecode string.
- the lexical context goes in the slot used for the constants of
bytecoded functions.
The first point above means that `help-function-arglist`,
`documentation`, and `interactive-form`s don't need to
distinguish interpreted and bytecode functions any more.
Main benefits of the change:
- We can now reliably distinguish a list from a function value.
- `cl-defmethod` can dispatch on `interactive-function` and `closure`.
Dispatch on `function` also works now for interpreted functions but still
won't work for functions represented as lists or as symbols, of course.
- Function values are now self-evaluating. That was alrready the case
when byte-compiled, but not when interpreted since
(eval '(closure ...)) signals a void-function error.
That also avoids false-positive warnings about "don't quote your lambdas"
when doing things like `(mapcar ',func ...)`.
* src/eval.c (Fmake_interpreted_closure): New function.
(Ffunction): Use it and change calling convention of
`Vinternal_make_interpreted_closure_function`.
(FUNCTIONP, Fcommandp, eval_sub, funcall_general, funcall_lambda)
(Ffunc_arity, lambda_arity): Simplify.
(funcall_lambda): Adjust to new representation.
(syms_of_eval): `defsubr` the new function. Remove definition of `Qclosure`.
* lisp/emacs-lisp/cconv.el (cconv-make-interpreted-closure):
Change calling convention and use `make-interpreted-closure`.
* src/data.c (Fcl_type_of): Distinguish `byte-code-function`s from
`interpreted-function`s.
(Fclosurep, finterpreted_function_p): New functions.
(Fbyte_code_function_p): Don't be confused by `interpreted-function`s.
(Finteractive_form, Fcommand_modes): Simplify.
(syms_of_data): Define new type symbols and `defsubr` the two
new functions.
* lisp/emacs-lisp/cl-print.el (cl-print-object) <interpreted-function>:
New method.
* lisp/emacs-lisp/oclosure.el (oclosure): Refine the parent
to be `closure`.
(oclosure--fix-type, oclosure-type): Simplify.
(oclosure--copy, oclosure--get, oclosure--set): Adjust to
new representation.
* src/callint.c (Fcall_interactively): Adjust to new representation.
* src/lread.c (bytecode_from_rev_list):
* lisp/simple.el (function-documentation):
* lisp/help.el (help-function-arglist): Remove the old `closure` case
and adjust the byte-code case so it handles `interpreted-function`s.
* lisp/emacs-lisp/cl-preloaded.el (closure): New type.
(byte-code-function): Add it as a parent.
(interpreted-function): Adjust parent (the type itself was already
added earlier by accident).
* lisp/emacs-lisp/bytecomp.el (byte-compile--reify-function): Adjust to
new representation.
(byte-compile): Use `interpreted-function-p`.
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand): Adjust to
new representation.
(side-effect-free-fns): Add `interpreted-function-p` and `closurep`.
* src/profiler.c (trace_hash, ffunction_equal): Simplify.
* lisp/profiler.el (profiler-function-equal): Simplify.
* lisp/emacs-lisp/nadvice.el (advice--interactive-form-1):
Use `interpreted-function-p`; adjust to new representation; and take
advantage of the fact that function values are now self-evaluating.
* lisp/emacs-lisp/lisp-mode.el (closure):
Remove `lisp-indent-function` property.
* lisp/emacs-lisp/disass.el (disassemble-internal): Adjust to
new representation.
* lisp/emacs-lisp/edebug.el (edebug--strip-instrumentation):
Use `interpreted-function-p`.
* lisp/emacs-lisp/comp-common.el (comp-known-type-specifiers):
Add `closurep` and `interpreted-function-p`.
* test/lisp/help-fns-tests.el (help-fns-test-lisp-defun): Adjust to
more precise type info in `describe-function`.
* test/lisp/erc/resources/erc-d/erc-d-tests.el (erc-d--render-entries):
Use `interpreted-function-p`.
* test/lisp/emacs-lisp/macroexp-resources/vk.el (vk-f4, vk-f5):
Don't hardcode function values.
* doc/lispref/functions.texi (Anonymous Functions): Don't suggest that
function values are lists. Reword "self-quoting" to reflect the
fact that #' doesn't return the exact same object. Update examples
with the new shape of the return value.
* doc/lispref/variables.texi (Lexical Binding):
* doc/lispref/lists.texi (Rearrangement):
* doc/lispref/control.texi (Handling Errors): Update examples to reflect
new representation of function values.
Diffstat (limited to '')
| -rw-r--r-- | src/data.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/src/data.c b/src/data.c index 681054ff8cb..ea611ad1abf 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -248,7 +248,9 @@ a fixed set of types. */) | |||
| 248 | return XSUBR (object)->max_args == UNEVALLED ? Qspecial_form | 248 | return XSUBR (object)->max_args == UNEVALLED ? Qspecial_form |
| 249 | : SUBR_NATIVE_COMPILEDP (object) ? Qsubr_native_elisp | 249 | : SUBR_NATIVE_COMPILEDP (object) ? Qsubr_native_elisp |
| 250 | : Qprimitive_function; | 250 | : Qprimitive_function; |
| 251 | case PVEC_CLOSURE: return Qcompiled_function; | 251 | case PVEC_CLOSURE: |
| 252 | return CONSP (AREF (object, CLOSURE_CODE)) | ||
| 253 | ? Qinterpreted_function : Qbyte_code_function; | ||
| 252 | case PVEC_BUFFER: return Qbuffer; | 254 | case PVEC_BUFFER: return Qbuffer; |
| 253 | case PVEC_CHAR_TABLE: return Qchar_table; | 255 | case PVEC_CHAR_TABLE: return Qchar_table; |
| 254 | case PVEC_BOOL_VECTOR: return Qbool_vector; | 256 | case PVEC_BOOL_VECTOR: return Qbool_vector; |
| @@ -518,12 +520,32 @@ DEFUN ("subrp", Fsubrp, Ssubrp, 1, 1, 0, | |||
| 518 | return Qnil; | 520 | return Qnil; |
| 519 | } | 521 | } |
| 520 | 522 | ||
| 523 | DEFUN ("closurep", Fclosurep, Sclosurep, | ||
| 524 | 1, 1, 0, | ||
| 525 | doc: /* Return t if OBJECT is a function of type `closure'. */) | ||
| 526 | (Lisp_Object object) | ||
| 527 | { | ||
| 528 | if (CLOSUREP (object)) | ||
| 529 | return Qt; | ||
| 530 | return Qnil; | ||
| 531 | } | ||
| 532 | |||
| 521 | DEFUN ("byte-code-function-p", Fbyte_code_function_p, Sbyte_code_function_p, | 533 | DEFUN ("byte-code-function-p", Fbyte_code_function_p, Sbyte_code_function_p, |
| 522 | 1, 1, 0, | 534 | 1, 1, 0, |
| 523 | doc: /* Return t if OBJECT is a byte-compiled function object. */) | 535 | doc: /* Return t if OBJECT is a byte-compiled function object. */) |
| 524 | (Lisp_Object object) | 536 | (Lisp_Object object) |
| 525 | { | 537 | { |
| 526 | if (CLOSUREP (object)) | 538 | if (CLOSUREP (object) && STRINGP (AREF (object, CLOSURE_CODE))) |
| 539 | return Qt; | ||
| 540 | return Qnil; | ||
| 541 | } | ||
| 542 | |||
| 543 | DEFUN ("interpreted-function-p", Finterpreted_function_p, | ||
| 544 | Sinterpreted_function_p, 1, 1, 0, | ||
| 545 | doc: /* Return t if OBJECT is a function of type `interpreted-function'. */) | ||
| 546 | (Lisp_Object object) | ||
| 547 | { | ||
| 548 | if (CLOSUREP (object) && CONSP (AREF (object, CLOSURE_CODE))) | ||
| 527 | return Qt; | 549 | return Qt; |
| 528 | return Qnil; | 550 | return Qnil; |
| 529 | } | 551 | } |
| @@ -1174,17 +1196,11 @@ Value, if non-nil, is a list (interactive SPEC). */) | |||
| 1174 | else if (CONSP (fun)) | 1196 | else if (CONSP (fun)) |
| 1175 | { | 1197 | { |
| 1176 | Lisp_Object funcar = XCAR (fun); | 1198 | Lisp_Object funcar = XCAR (fun); |
| 1177 | if (EQ (funcar, Qclosure) | 1199 | if (EQ (funcar, Qlambda)) |
| 1178 | || EQ (funcar, Qlambda)) | ||
| 1179 | { | 1200 | { |
| 1180 | Lisp_Object form = Fcdr (XCDR (fun)); | 1201 | Lisp_Object form = Fcdr (XCDR (fun)); |
| 1181 | if (EQ (funcar, Qclosure)) | ||
| 1182 | form = Fcdr (form); | ||
| 1183 | Lisp_Object spec = Fassq (Qinteractive, form); | 1202 | Lisp_Object spec = Fassq (Qinteractive, form); |
| 1184 | if (NILP (spec) && VALID_DOCSTRING_P (CAR_SAFE (form))) | 1203 | if (NILP (Fcdr (Fcdr (spec)))) |
| 1185 | /* A "docstring" is a sign that we may have an OClosure. */ | ||
| 1186 | genfun = true; | ||
| 1187 | else if (NILP (Fcdr (Fcdr (spec)))) | ||
| 1188 | return spec; | 1204 | return spec; |
| 1189 | else | 1205 | else |
| 1190 | return list2 (Qinteractive, Fcar (Fcdr (spec))); | 1206 | return list2 (Qinteractive, Fcar (Fcdr (spec))); |
| @@ -1257,12 +1273,9 @@ The value, if non-nil, is a list of mode name symbols. */) | |||
| 1257 | else if (CONSP (fun)) | 1273 | else if (CONSP (fun)) |
| 1258 | { | 1274 | { |
| 1259 | Lisp_Object funcar = XCAR (fun); | 1275 | Lisp_Object funcar = XCAR (fun); |
| 1260 | if (EQ (funcar, Qclosure) | 1276 | if (EQ (funcar, Qlambda)) |
| 1261 | || EQ (funcar, Qlambda)) | ||
| 1262 | { | 1277 | { |
| 1263 | Lisp_Object form = Fcdr (XCDR (fun)); | 1278 | Lisp_Object form = Fcdr (XCDR (fun)); |
| 1264 | if (EQ (funcar, Qclosure)) | ||
| 1265 | form = Fcdr (form); | ||
| 1266 | return Fcdr (Fcdr (Fassq (Qinteractive, form))); | 1279 | return Fcdr (Fcdr (Fassq (Qinteractive, form))); |
| 1267 | } | 1280 | } |
| 1268 | } | 1281 | } |
| @@ -4224,7 +4237,8 @@ syms_of_data (void) | |||
| 4224 | DEFSYM (Qspecial_form, "special-form"); | 4237 | DEFSYM (Qspecial_form, "special-form"); |
| 4225 | DEFSYM (Qprimitive_function, "primitive-function"); | 4238 | DEFSYM (Qprimitive_function, "primitive-function"); |
| 4226 | DEFSYM (Qsubr_native_elisp, "subr-native-elisp"); | 4239 | DEFSYM (Qsubr_native_elisp, "subr-native-elisp"); |
| 4227 | DEFSYM (Qcompiled_function, "compiled-function"); | 4240 | DEFSYM (Qbyte_code_function, "byte-code-function"); |
| 4241 | DEFSYM (Qinterpreted_function, "interpreted-function"); | ||
| 4228 | DEFSYM (Qbuffer, "buffer"); | 4242 | DEFSYM (Qbuffer, "buffer"); |
| 4229 | DEFSYM (Qframe, "frame"); | 4243 | DEFSYM (Qframe, "frame"); |
| 4230 | DEFSYM (Qvector, "vector"); | 4244 | DEFSYM (Qvector, "vector"); |
| @@ -4289,6 +4303,8 @@ syms_of_data (void) | |||
| 4289 | defsubr (&Smarkerp); | 4303 | defsubr (&Smarkerp); |
| 4290 | defsubr (&Ssubrp); | 4304 | defsubr (&Ssubrp); |
| 4291 | defsubr (&Sbyte_code_function_p); | 4305 | defsubr (&Sbyte_code_function_p); |
| 4306 | defsubr (&Sinterpreted_function_p); | ||
| 4307 | defsubr (&Sclosurep); | ||
| 4292 | defsubr (&Smodule_function_p); | 4308 | defsubr (&Smodule_function_p); |
| 4293 | defsubr (&Schar_or_string_p); | 4309 | defsubr (&Schar_or_string_p); |
| 4294 | defsubr (&Sthreadp); | 4310 | defsubr (&Sthreadp); |