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/eval.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 'src/eval.c')
| -rw-r--r-- | src/eval.c | 148 |
1 files changed, 93 insertions, 55 deletions
diff --git a/src/eval.c b/src/eval.c index a7d860114cf..fd388706108 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -510,6 +510,33 @@ usage: (quote ARG) */) | |||
| 510 | return XCAR (args); | 510 | return XCAR (args); |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | DEFUN ("make-interpreted-closure", Fmake_interpreted_closure, | ||
| 514 | Smake_interpreted_closure, 3, 5, 0, | ||
| 515 | doc: /* Make an interpreted closure. | ||
| 516 | ARGS should be the list of formal arguments. | ||
| 517 | BODY should be a non-empty list of forms. | ||
| 518 | ENV should be a lexical environment, like the second argument of `eval'. | ||
| 519 | IFORM if non-nil should be of the form (interactive ...). */) | ||
| 520 | (Lisp_Object args, Lisp_Object body, Lisp_Object env, | ||
| 521 | Lisp_Object docstring, Lisp_Object iform) | ||
| 522 | { | ||
| 523 | CHECK_CONS (body); /* Make sure it's not confused with byte-code! */ | ||
| 524 | CHECK_LIST (args); | ||
| 525 | CHECK_LIST (iform); | ||
| 526 | Lisp_Object ifcdr = Fcdr (iform); | ||
| 527 | Lisp_Object slots[] = { args, body, env, Qnil, docstring, | ||
| 528 | NILP (Fcdr (ifcdr)) | ||
| 529 | ? Fcar (ifcdr) | ||
| 530 | : CALLN (Fvector, XCAR (ifcdr), XCDR (ifcdr)) }; | ||
| 531 | /* Adjusting the size is indispensable since, as for byte-code objects, | ||
| 532 | we distinguish interactive functions by the presence or absence of the | ||
| 533 | iform slot. */ | ||
| 534 | Lisp_Object val | ||
| 535 | = Fvector (!NILP (iform) ? 6 : !NILP (docstring) ? 5 : 3, slots); | ||
| 536 | XSETPVECTYPE (XVECTOR (val), PVEC_CLOSURE); | ||
| 537 | return val; | ||
| 538 | } | ||
| 539 | |||
| 513 | DEFUN ("function", Ffunction, Sfunction, 1, UNEVALLED, 0, | 540 | DEFUN ("function", Ffunction, Sfunction, 1, UNEVALLED, 0, |
| 514 | doc: /* Like `quote', but preferred for objects which are functions. | 541 | doc: /* Like `quote', but preferred for objects which are functions. |
| 515 | In byte compilation, `function' causes its argument to be handled by | 542 | In byte compilation, `function' causes its argument to be handled by |
| @@ -525,33 +552,55 @@ usage: (function ARG) */) | |||
| 525 | if (!NILP (XCDR (args))) | 552 | if (!NILP (XCDR (args))) |
| 526 | xsignal2 (Qwrong_number_of_arguments, Qfunction, Flength (args)); | 553 | xsignal2 (Qwrong_number_of_arguments, Qfunction, Flength (args)); |
| 527 | 554 | ||
| 528 | if (!NILP (Vinternal_interpreter_environment) | 555 | if (CONSP (quoted) |
| 529 | && CONSP (quoted) | ||
| 530 | && EQ (XCAR (quoted), Qlambda)) | 556 | && EQ (XCAR (quoted), Qlambda)) |
| 531 | { /* This is a lambda expression within a lexical environment; | 557 | { /* This is a lambda expression within a lexical environment; |
| 532 | return an interpreted closure instead of a simple lambda. */ | 558 | return an interpreted closure instead of a simple lambda. */ |
| 533 | Lisp_Object cdr = XCDR (quoted); | 559 | Lisp_Object cdr = XCDR (quoted); |
| 534 | Lisp_Object tmp = cdr; | 560 | Lisp_Object args = Fcar (cdr); |
| 535 | if (CONSP (tmp) | 561 | cdr = Fcdr (cdr); |
| 536 | && (tmp = XCDR (tmp), CONSP (tmp)) | 562 | Lisp_Object docstring = Qnil, iform = Qnil; |
| 537 | && (tmp = XCAR (tmp), CONSP (tmp)) | 563 | if (CONSP (cdr)) |
| 538 | && (EQ (QCdocumentation, XCAR (tmp)))) | 564 | { |
| 539 | { /* Handle the special (:documentation <form>) to build the docstring | 565 | docstring = XCAR (cdr); |
| 566 | if (STRINGP (docstring)) | ||
| 567 | { | ||
| 568 | Lisp_Object tmp = XCDR (cdr); | ||
| 569 | if (!NILP (tmp)) | ||
| 570 | cdr = tmp; | ||
| 571 | else /* It's not a docstring, it's a return value. */ | ||
| 572 | docstring = Qnil; | ||
| 573 | } | ||
| 574 | /* Handle the special (:documentation <form>) to build the docstring | ||
| 540 | dynamically. */ | 575 | dynamically. */ |
| 541 | Lisp_Object docstring = eval_sub (Fcar (XCDR (tmp))); | 576 | else if (CONSP (docstring) |
| 542 | if (SYMBOLP (docstring) && !NILP (docstring)) | 577 | && EQ (QCdocumentation, XCAR (docstring)) |
| 543 | /* Hack for OClosures: Allow the docstring to be a symbol | 578 | && (docstring = eval_sub (Fcar (XCDR (docstring))), |
| 544 | * (the OClosure's type). */ | 579 | true)) |
| 545 | docstring = Fsymbol_name (docstring); | 580 | cdr = XCDR (cdr); |
| 546 | CHECK_STRING (docstring); | 581 | else |
| 547 | cdr = Fcons (XCAR (cdr), Fcons (docstring, XCDR (XCDR (cdr)))); | 582 | docstring = Qnil; /* Not a docstring after all. */ |
| 548 | } | 583 | } |
| 549 | if (NILP (Vinternal_make_interpreted_closure_function)) | 584 | if (CONSP (cdr)) |
| 550 | return Fcons (Qclosure, Fcons (Vinternal_interpreter_environment, cdr)); | 585 | { |
| 586 | iform = XCAR (cdr); | ||
| 587 | if (CONSP (iform) | ||
| 588 | && EQ (Qinteractive, XCAR (iform))) | ||
| 589 | cdr = XCDR (cdr); | ||
| 590 | else | ||
| 591 | iform = Qnil; /* Not an interactive-form after all. */ | ||
| 592 | } | ||
| 593 | if (NILP (cdr)) | ||
| 594 | cdr = Fcons (Qnil, Qnil); /* Make sure the body is never empty! */ | ||
| 595 | |||
| 596 | if (NILP (Vinternal_interpreter_environment) | ||
| 597 | || NILP (Vinternal_make_interpreted_closure_function)) | ||
| 598 | return Fmake_interpreted_closure | ||
| 599 | (args, cdr, Vinternal_interpreter_environment, docstring, iform); | ||
| 551 | else | 600 | else |
| 552 | return call2 (Vinternal_make_interpreted_closure_function, | 601 | return call5 (Vinternal_make_interpreted_closure_function, |
| 553 | Fcons (Qlambda, cdr), | 602 | args, cdr, Vinternal_interpreter_environment, |
| 554 | Vinternal_interpreter_environment); | 603 | docstring, iform); |
| 555 | } | 604 | } |
| 556 | else | 605 | else |
| 557 | /* Simply quote the argument. */ | 606 | /* Simply quote the argument. */ |
| @@ -2193,15 +2242,12 @@ then strings and vectors are not accepted. */) | |||
| 2193 | else | 2242 | else |
| 2194 | { | 2243 | { |
| 2195 | Lisp_Object body = CDR_SAFE (XCDR (fun)); | 2244 | Lisp_Object body = CDR_SAFE (XCDR (fun)); |
| 2196 | if (EQ (funcar, Qclosure)) | 2245 | if (!EQ (funcar, Qlambda)) |
| 2197 | body = CDR_SAFE (body); | ||
| 2198 | else if (!EQ (funcar, Qlambda)) | ||
| 2199 | return Qnil; | 2246 | return Qnil; |
| 2200 | if (!NILP (Fassq (Qinteractive, body))) | 2247 | if (!NILP (Fassq (Qinteractive, body))) |
| 2201 | return Qt; | 2248 | return Qt; |
| 2202 | else if (VALID_DOCSTRING_P (CAR_SAFE (body))) | 2249 | else |
| 2203 | /* A "docstring" is a sign that we may have an OClosure. */ | 2250 | return Qnil; |
| 2204 | genfun = true; | ||
| 2205 | } | 2251 | } |
| 2206 | } | 2252 | } |
| 2207 | 2253 | ||
| @@ -2611,8 +2657,7 @@ eval_sub (Lisp_Object form) | |||
| 2611 | exp = unbind_to (count1, exp); | 2657 | exp = unbind_to (count1, exp); |
| 2612 | val = eval_sub (exp); | 2658 | val = eval_sub (exp); |
| 2613 | } | 2659 | } |
| 2614 | else if (EQ (funcar, Qlambda) | 2660 | else if (EQ (funcar, Qlambda)) |
| 2615 | || EQ (funcar, Qclosure)) | ||
| 2616 | return apply_lambda (fun, original_args, count); | 2661 | return apply_lambda (fun, original_args, count); |
| 2617 | else | 2662 | else |
| 2618 | xsignal1 (Qinvalid_function, original_fun); | 2663 | xsignal1 (Qinvalid_function, original_fun); |
| @@ -2950,7 +2995,7 @@ FUNCTIONP (Lisp_Object object) | |||
| 2950 | else if (CONSP (object)) | 2995 | else if (CONSP (object)) |
| 2951 | { | 2996 | { |
| 2952 | Lisp_Object car = XCAR (object); | 2997 | Lisp_Object car = XCAR (object); |
| 2953 | return EQ (car, Qlambda) || EQ (car, Qclosure); | 2998 | return EQ (car, Qlambda); |
| 2954 | } | 2999 | } |
| 2955 | else | 3000 | else |
| 2956 | return false; | 3001 | return false; |
| @@ -2980,8 +3025,7 @@ funcall_general (Lisp_Object fun, ptrdiff_t numargs, Lisp_Object *args) | |||
| 2980 | Lisp_Object funcar = XCAR (fun); | 3025 | Lisp_Object funcar = XCAR (fun); |
| 2981 | if (!SYMBOLP (funcar)) | 3026 | if (!SYMBOLP (funcar)) |
| 2982 | xsignal1 (Qinvalid_function, original_fun); | 3027 | xsignal1 (Qinvalid_function, original_fun); |
| 2983 | if (EQ (funcar, Qlambda) | 3028 | if (EQ (funcar, Qlambda)) |
| 2984 | || EQ (funcar, Qclosure)) | ||
| 2985 | return funcall_lambda (fun, numargs, args); | 3029 | return funcall_lambda (fun, numargs, args); |
| 2986 | else if (EQ (funcar, Qautoload)) | 3030 | else if (EQ (funcar, Qautoload)) |
| 2987 | { | 3031 | { |
| @@ -3165,16 +3209,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, Lisp_Object *arg_vector) | |||
| 3165 | 3209 | ||
| 3166 | if (CONSP (fun)) | 3210 | if (CONSP (fun)) |
| 3167 | { | 3211 | { |
| 3168 | if (EQ (XCAR (fun), Qclosure)) | 3212 | lexenv = Qnil; |
| 3169 | { | ||
| 3170 | Lisp_Object cdr = XCDR (fun); /* Drop `closure'. */ | ||
| 3171 | if (! CONSP (cdr)) | ||
| 3172 | xsignal1 (Qinvalid_function, fun); | ||
| 3173 | fun = cdr; | ||
| 3174 | lexenv = XCAR (fun); | ||
| 3175 | } | ||
| 3176 | else | ||
| 3177 | lexenv = Qnil; | ||
| 3178 | syms_left = XCDR (fun); | 3213 | syms_left = XCDR (fun); |
| 3179 | if (CONSP (syms_left)) | 3214 | if (CONSP (syms_left)) |
| 3180 | syms_left = XCAR (syms_left); | 3215 | syms_left = XCAR (syms_left); |
| @@ -3189,10 +3224,12 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, Lisp_Object *arg_vector) | |||
| 3189 | engine directly. */ | 3224 | engine directly. */ |
| 3190 | if (FIXNUMP (syms_left)) | 3225 | if (FIXNUMP (syms_left)) |
| 3191 | return exec_byte_code (fun, XFIXNUM (syms_left), nargs, arg_vector); | 3226 | return exec_byte_code (fun, XFIXNUM (syms_left), nargs, arg_vector); |
| 3192 | /* Otherwise the bytecode object uses dynamic binding and the | 3227 | /* Otherwise the closure either is interpreted |
| 3193 | ARGLIST slot contains a standard formal argument list whose | 3228 | or uses dynamic binding and the ARGLIST slot contains a standard |
| 3194 | variables are bound dynamically below. */ | 3229 | formal argument list whose variables are bound dynamically below. */ |
| 3195 | lexenv = Qnil; | 3230 | lexenv = CONSP (AREF (fun, CLOSURE_CODE)) |
| 3231 | ? AREF (fun, CLOSURE_CONSTANTS) | ||
| 3232 | : Qnil; | ||
| 3196 | } | 3233 | } |
| 3197 | #ifdef HAVE_MODULES | 3234 | #ifdef HAVE_MODULES |
| 3198 | else if (MODULE_FUNCTIONP (fun)) | 3235 | else if (MODULE_FUNCTIONP (fun)) |
| @@ -3280,7 +3317,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, Lisp_Object *arg_vector) | |||
| 3280 | val = XSUBR (fun)->function.a0 (); | 3317 | val = XSUBR (fun)->function.a0 (); |
| 3281 | } | 3318 | } |
| 3282 | else | 3319 | else |
| 3283 | val = exec_byte_code (fun, 0, 0, NULL); | 3320 | { |
| 3321 | eassert (CLOSUREP (fun)); | ||
| 3322 | val = CONSP (AREF (fun, CLOSURE_CODE)) | ||
| 3323 | /* Interpreted function. */ | ||
| 3324 | ? Fprogn (AREF (fun, CLOSURE_CODE)) | ||
| 3325 | /* Dynbound bytecode. */ | ||
| 3326 | : exec_byte_code (fun, 0, 0, NULL); | ||
| 3327 | } | ||
| 3284 | 3328 | ||
| 3285 | return unbind_to (count, val); | 3329 | return unbind_to (count, val); |
| 3286 | } | 3330 | } |
| @@ -3330,8 +3374,7 @@ function with `&rest' args, or `unevalled' for a special form. */) | |||
| 3330 | funcar = XCAR (function); | 3374 | funcar = XCAR (function); |
| 3331 | if (!SYMBOLP (funcar)) | 3375 | if (!SYMBOLP (funcar)) |
| 3332 | xsignal1 (Qinvalid_function, original); | 3376 | xsignal1 (Qinvalid_function, original); |
| 3333 | if (EQ (funcar, Qlambda) | 3377 | if (EQ (funcar, Qlambda)) |
| 3334 | || EQ (funcar, Qclosure)) | ||
| 3335 | result = lambda_arity (function); | 3378 | result = lambda_arity (function); |
| 3336 | else if (EQ (funcar, Qautoload)) | 3379 | else if (EQ (funcar, Qautoload)) |
| 3337 | { | 3380 | { |
| @@ -3352,11 +3395,6 @@ lambda_arity (Lisp_Object fun) | |||
| 3352 | 3395 | ||
| 3353 | if (CONSP (fun)) | 3396 | if (CONSP (fun)) |
| 3354 | { | 3397 | { |
| 3355 | if (EQ (XCAR (fun), Qclosure)) | ||
| 3356 | { | ||
| 3357 | fun = XCDR (fun); /* Drop `closure'. */ | ||
| 3358 | CHECK_CONS (fun); | ||
| 3359 | } | ||
| 3360 | syms_left = XCDR (fun); | 3398 | syms_left = XCDR (fun); |
| 3361 | if (CONSP (syms_left)) | 3399 | if (CONSP (syms_left)) |
| 3362 | syms_left = XCAR (syms_left); | 3400 | syms_left = XCAR (syms_left); |
| @@ -4265,7 +4303,6 @@ before making `inhibit-quit' nil. */); | |||
| 4265 | DEFSYM (Qcommandp, "commandp"); | 4303 | DEFSYM (Qcommandp, "commandp"); |
| 4266 | DEFSYM (Qand_rest, "&rest"); | 4304 | DEFSYM (Qand_rest, "&rest"); |
| 4267 | DEFSYM (Qand_optional, "&optional"); | 4305 | DEFSYM (Qand_optional, "&optional"); |
| 4268 | DEFSYM (Qclosure, "closure"); | ||
| 4269 | DEFSYM (QCdocumentation, ":documentation"); | 4306 | DEFSYM (QCdocumentation, ":documentation"); |
| 4270 | DEFSYM (Qdebug, "debug"); | 4307 | DEFSYM (Qdebug, "debug"); |
| 4271 | DEFSYM (Qdebug_early, "debug-early"); | 4308 | DEFSYM (Qdebug_early, "debug-early"); |
| @@ -4423,6 +4460,7 @@ alist of active lexical bindings. */); | |||
| 4423 | defsubr (&Ssetq); | 4460 | defsubr (&Ssetq); |
| 4424 | defsubr (&Squote); | 4461 | defsubr (&Squote); |
| 4425 | defsubr (&Sfunction); | 4462 | defsubr (&Sfunction); |
| 4463 | defsubr (&Smake_interpreted_closure); | ||
| 4426 | defsubr (&Sdefault_toplevel_value); | 4464 | defsubr (&Sdefault_toplevel_value); |
| 4427 | defsubr (&Sset_default_toplevel_value); | 4465 | defsubr (&Sset_default_toplevel_value); |
| 4428 | defsubr (&Sdefvar); | 4466 | defsubr (&Sdefvar); |