aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/emacs-lisp/cconv.el
diff options
context:
space:
mode:
authorStefan Monnier2024-03-11 16:12:26 -0400
committerStefan Monnier2024-04-18 15:28:36 -0400
commit126be02077520a943252d0d219bb7677466d0168 (patch)
treef762237714f11b303c708f93f09a8dc72426bb2a /lisp/emacs-lisp/cconv.el
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 'lisp/emacs-lisp/cconv.el')
-rw-r--r--lisp/emacs-lisp/cconv.el38
1 files changed, 22 insertions, 16 deletions
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index 4ff47971351..e6a78f07762 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -902,7 +902,7 @@ lexically and dynamically bound symbols actually used by FORM."
902 (delete-dups cconv--dynbindings))))) 902 (delete-dups cconv--dynbindings)))))
903 (cons fvs dyns))))) 903 (cons fvs dyns)))))
904 904
905(defun cconv-make-interpreted-closure (fun env) 905(defun cconv-make-interpreted-closure (args body env docstring iform)
906 "Make a closure for the interpreter. 906 "Make a closure for the interpreter.
907This is intended to be called at runtime by the ELisp interpreter (when 907This is intended to be called at runtime by the ELisp interpreter (when
908the code has not been compiled). 908the code has not been compiled).
@@ -911,22 +911,27 @@ ENV is the runtime representation of the lexical environment,
911i.e. a list whose elements can be either plain symbols (which indicate 911i.e. a list whose elements can be either plain symbols (which indicate
912that this symbol should use dynamic scoping) or pairs (SYMBOL . VALUE) 912that this symbol should use dynamic scoping) or pairs (SYMBOL . VALUE)
913for the lexical bindings." 913for the lexical bindings."
914 (cl-assert (eq (car-safe fun) 'lambda)) 914 (cl-assert (consp body))
915 (cl-assert (listp args))
915 (let ((lexvars (delq nil (mapcar #'car-safe env)))) 916 (let ((lexvars (delq nil (mapcar #'car-safe env))))
916 (if (or (null lexvars) 917 (if (or
917 ;; Functions with a `:closure-dont-trim-context' marker 918 ;; Functions with a `:closure-dont-trim-context' marker
918 ;; should keep their whole context untrimmed (bug#59213). 919 ;; should keep their whole context untrimmed (bug#59213).
919 (and (eq :closure-dont-trim-context (nth 2 fun)) 920 (and (eq :closure-dont-trim-context (car body))
920 ;; Check the function doesn't just return the magic keyword. 921 ;; Check the function doesn't just return the magic keyword.
921 (nthcdr 3 fun))) 922 (cdr body)
923 ;; Drop the magic marker from the closure.
924 (setq body (cdr body)))
925 ;; There's no var to capture, so skip the analysis.
926 (null lexvars))
922 ;; The lexical environment is empty, or needs to be preserved, 927 ;; The lexical environment is empty, or needs to be preserved,
923 ;; so there's no need to look for free variables. 928 ;; so there's no need to look for free variables.
924 ;; Attempting to replace ,(cdr fun) by a macroexpanded version 929 ;; Attempting to replace body by a macroexpanded version
925 ;; causes bootstrap to fail. 930 ;; caused bootstrap to fail.
926 `(closure ,env . ,(cdr fun)) 931 (make-interpreted-closure args body env docstring iform)
927 ;; We could try and cache the result of the macroexpansion and 932 ;; We could try and cache the result of the macroexpansion and
928 ;; `cconv-fv' analysis. Not sure it's worth the trouble. 933 ;; `cconv-fv' analysis. Not sure it's worth the trouble.
929 (let* ((form `#',fun) 934 (let* ((form `#'(lambda ,args ,iform . ,body))
930 (expanded-form 935 (expanded-form
931 (let ((lexical-binding t) ;; Tell macros which dialect is in use. 936 (let ((lexical-binding t) ;; Tell macros which dialect is in use.
932 ;; Make the macro aware of any defvar declarations in scope. 937 ;; Make the macro aware of any defvar declarations in scope.
@@ -935,10 +940,10 @@ for the lexical bindings."
935 (append env macroexp--dynvars) env))) 940 (append env macroexp--dynvars) env)))
936 (macroexpand-all form macroexpand-all-environment))) 941 (macroexpand-all form macroexpand-all-environment)))
937 ;; Since we macroexpanded the body, we may as well use that. 942 ;; Since we macroexpanded the body, we may as well use that.
938 (expanded-fun-cdr 943 (expanded-fun-body
939 (pcase expanded-form 944 (pcase expanded-form
940 (`#'(lambda . ,cdr) cdr) 945 (`#'(lambda ,_args ,_iform . ,newbody) newbody)
941 (_ (cdr fun)))) 946 (_ body)))
942 947
943 (dynvars (delq nil (mapcar (lambda (b) (if (symbolp b) b)) env))) 948 (dynvars (delq nil (mapcar (lambda (b) (if (symbolp b) b)) env)))
944 (fvs (cconv-fv expanded-form lexvars dynvars)) 949 (fvs (cconv-fv expanded-form lexvars dynvars))
@@ -946,7 +951,8 @@ for the lexical bindings."
946 (cdr fvs)))) 951 (cdr fvs))))
947 ;; Never return a nil env, since nil means to use the dynbind 952 ;; Never return a nil env, since nil means to use the dynbind
948 ;; dialect of ELisp. 953 ;; dialect of ELisp.
949 `(closure ,(or newenv '(t)) . ,expanded-fun-cdr))))) 954 (make-interpreted-closure args expanded-fun-body (or newenv '(t))
955 docstring iform)))))
950 956
951 957
952(provide 'cconv) 958(provide 'cconv)