aboutsummaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorStefan Monnier2024-03-11 16:12:26 -0400
committerStefan Monnier2024-04-18 15:28:36 -0400
commit126be02077520a943252d0d219bb7677466d0168 (patch)
treef762237714f11b303c708f93f09a8dc72426bb2a /src/eval.c
parent7842af6095db4384898725fb4a14ebaa11379a34 (diff)
downloademacs-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.c148
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
513DEFUN ("make-interpreted-closure", Fmake_interpreted_closure,
514 Smake_interpreted_closure, 3, 5, 0,
515 doc: /* Make an interpreted closure.
516ARGS should be the list of formal arguments.
517BODY should be a non-empty list of forms.
518ENV should be a lexical environment, like the second argument of `eval'.
519IFORM 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
513DEFUN ("function", Ffunction, Sfunction, 1, UNEVALLED, 0, 540DEFUN ("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.
515In byte compilation, `function' causes its argument to be handled by 542In 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);