diff options
Diffstat (limited to 'src/data.c')
-rw-r--r-- | src/data.c | 2047 |
1 files changed, 1281 insertions, 766 deletions
diff --git a/src/data.c b/src/data.c index 2e7f3e017be..221a6f58835 100644 --- a/src/data.c +++ b/src/data.c @@ -1,5 +1,5 @@ /* Primitive operations on Lisp data types for GNU Emacs Lisp interpreter. - Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2017 Free Software + Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <intprops.h> #include "lisp.h" +#include "bignum.h" #include "puresize.h" #include "character.h" #include "buffer.h" @@ -41,55 +42,49 @@ static void swap_in_symval_forwarding (struct Lisp_Symbol *, struct Lisp_Buffer_Local_Value *); static bool -BOOLFWDP (union Lisp_Fwd *a) +BOOLFWDP (lispfwd a) { return XFWDTYPE (a) == Lisp_Fwd_Bool; } static bool -INTFWDP (union Lisp_Fwd *a) +INTFWDP (lispfwd a) { return XFWDTYPE (a) == Lisp_Fwd_Int; } static bool -KBOARD_OBJFWDP (union Lisp_Fwd *a) +KBOARD_OBJFWDP (lispfwd a) { return XFWDTYPE (a) == Lisp_Fwd_Kboard_Obj; } static bool -OBJFWDP (union Lisp_Fwd *a) +OBJFWDP (lispfwd a) { return XFWDTYPE (a) == Lisp_Fwd_Obj; } -static struct Lisp_Boolfwd * -XBOOLFWD (union Lisp_Fwd *a) +static struct Lisp_Boolfwd const * +XBOOLFWD (lispfwd a) { eassert (BOOLFWDP (a)); - return &a->u_boolfwd; + return a.fwdptr; } -static struct Lisp_Kboard_Objfwd * -XKBOARD_OBJFWD (union Lisp_Fwd *a) +static struct Lisp_Kboard_Objfwd const * +XKBOARD_OBJFWD (lispfwd a) { eassert (KBOARD_OBJFWDP (a)); - return &a->u_kboard_objfwd; + return a.fwdptr; } -static struct Lisp_Intfwd * -XINTFWD (union Lisp_Fwd *a) +static struct Lisp_Intfwd const * +XFIXNUMFWD (lispfwd a) { eassert (INTFWDP (a)); - return &a->u_intfwd; + return a.fwdptr; } -static struct Lisp_Objfwd * -XOBJFWD (union Lisp_Fwd *a) +static struct Lisp_Objfwd const * +XOBJFWD (lispfwd a) { eassert (OBJFWDP (a)); - return &a->u_objfwd; -} - -static void -CHECK_SUBR (Lisp_Object x) -{ - CHECK_TYPE (SUBRP (x), Qsubrp, x); + return a.fwdptr; } static void @@ -129,28 +124,22 @@ set_blv_valcell (struct Lisp_Buffer_Local_Value *blv, Lisp_Object val) blv->valcell = val; } -static _Noreturn void +static AVOID wrong_length_argument (Lisp_Object a1, Lisp_Object a2, Lisp_Object a3) { - Lisp_Object size1 = make_number (bool_vector_size (a1)); - Lisp_Object size2 = make_number (bool_vector_size (a2)); + Lisp_Object size1 = make_fixnum (bool_vector_size (a1)); + Lisp_Object size2 = make_fixnum (bool_vector_size (a2)); if (NILP (a3)) xsignal2 (Qwrong_length_argument, size1, size2); else xsignal3 (Qwrong_length_argument, size1, size2, - make_number (bool_vector_size (a3))); + make_fixnum (bool_vector_size (a3))); } -_Noreturn void -wrong_type_argument (register Lisp_Object predicate, register Lisp_Object value) +AVOID +wrong_type_argument (Lisp_Object predicate, Lisp_Object value) { - /* If VALUE is not even a valid Lisp object, we'd want to abort here - where we can get a backtrace showing where it came from. We used - to try and do that by checking the tagbits, but nowadays all - tagbits are potentially valid. */ - /* if ((unsigned int) XTYPE (value) >= Lisp_Type_Limit) - * emacs_abort (); */ - + eassert (!TAGGEDP (value, Lisp_Type_Unused0)); xsignal2 (Qwrong_type_argument, predicate, value); } @@ -221,27 +210,17 @@ for example, (type-of 1) returns `integer'. */) case Lisp_Cons: return Qcons; - case Lisp_Misc: - switch (XMISCTYPE (object)) - { - case Lisp_Misc_Marker: - return Qmarker; - case Lisp_Misc_Overlay: - return Qoverlay; - case Lisp_Misc_Finalizer: - return Qfinalizer; -#ifdef HAVE_MODULES - case Lisp_Misc_User_Ptr: - return Quser_ptr; -#endif - default: - emacs_abort (); - } - case Lisp_Vectorlike: + /* WARNING!! Keep 'cl--typeof-types' in sync with this code!! */ switch (PSEUDOVECTOR_TYPE (XVECTOR (object))) { case PVEC_NORMAL_VECTOR: return Qvector; + case PVEC_BIGNUM: return Qinteger; + case PVEC_MARKER: return Qmarker; + case PVEC_SYMBOL_WITH_POS: return Qsymbol_with_pos; + case PVEC_OVERLAY: return Qoverlay; + case PVEC_FINALIZER: return Qfinalizer; + case PVEC_USER_PTR: return Quser_ptr; case PVEC_WINDOW_CONFIGURATION: return Qwindow_configuration; case PVEC_PROCESS: return Qprocess; case PVEC_WINDOW: return Qwindow; @@ -276,10 +255,17 @@ for example, (type-of 1) returns `integer'. */) } case PVEC_MODULE_FUNCTION: return Qmodule_function; - /* "Impossible" cases. */ + case PVEC_NATIVE_COMP_UNIT: + return Qnative_comp_unit; case PVEC_XWIDGET: - case PVEC_OTHER: + return Qxwidget; case PVEC_XWIDGET_VIEW: + return Qxwidget_view; + case PVEC_SQLITE: + return Qsqlite; + /* "Impossible" cases. */ + case PVEC_MISC_PTR: + case PVEC_OTHER: case PVEC_SUB_CHAR_TABLE: case PVEC_FREE: ; } @@ -334,6 +320,26 @@ DEFUN ("nlistp", Fnlistp, Snlistp, 1, 1, 0, return Qt; } +DEFUN ("bare-symbol-p", Fbare_symbol_p, Sbare_symbol_p, 1, 1, 0, + doc: /* Return t if OBJECT is a symbol, but not a symbol together with position. */ + attributes: const) + (Lisp_Object object) +{ + if (BARE_SYMBOL_P (object)) + return Qt; + return Qnil; +} + +DEFUN ("symbol-with-pos-p", Fsymbol_with_pos_p, Ssymbol_with_pos_p, 1, 1, 0, + doc: /* Return t if OBJECT is a symbol together with position. */ + attributes: const) + (Lisp_Object object) +{ + if (SYMBOL_WITH_POS_P (object)) + return Qt; + return Qnil; +} + DEFUN ("symbolp", Fsymbolp, Ssymbolp, 1, 1, 0, doc: /* Return t if OBJECT is a symbol. */ attributes: const) @@ -344,8 +350,6 @@ DEFUN ("symbolp", Fsymbolp, Ssymbolp, 1, 1, 0, return Qnil; } -/* Define this in C to avoid unnecessarily consing up the symbol - name. */ DEFUN ("keywordp", Fkeywordp, Skeywordp, 1, 1, 0, doc: /* Return t if OBJECT is a keyword. This means that it is a symbol with a print name beginning with `:' @@ -534,9 +538,9 @@ DEFUN ("natnump", Fnatnump, Snatnump, 1, 1, 0, attributes: const) (Lisp_Object object) { - if (NATNUMP (object)) - return Qt; - return Qnil; + return ((FIXNUMP (object) ? 0 <= XFIXNUM (object) + : BIGNUMP (object) && 0 <= mpz_sgn (*xbignum_val (object))) + ? Qt : Qnil); } DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0, @@ -601,8 +605,8 @@ DEFUN ("condition-variable-p", Fcondition_variable_p, Scondition_variable_p, /* Extract and set components of lists. */ DEFUN ("car", Fcar, Scar, 1, 1, 0, - doc: /* Return the car of LIST. If arg is nil, return nil. -Error if arg is not nil and not a cons cell. See also `car-safe'. + doc: /* Return the car of LIST. If LIST is nil, return nil. +Error if LIST is not nil and not a cons cell. See also `car-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic Lisp concepts such as car, cdr, cons cell and list. */) @@ -619,8 +623,8 @@ DEFUN ("car-safe", Fcar_safe, Scar_safe, 1, 1, 0, } DEFUN ("cdr", Fcdr, Scdr, 1, 1, 0, - doc: /* Return the cdr of LIST. If arg is nil, return nil. -Error if arg is not nil and not a cons cell. See also `cdr-safe'. + doc: /* Return the cdr of LIST. If LIST is nil, return nil. +Error if LIST is not nil and not a cons cell. See also `cdr-safe'. See Info node `(elisp)Cons Cells' for a discussion of related basic Lisp concepts such as cdr, car, cons cell and list. */) @@ -670,14 +674,14 @@ global value outside of any lexical scope. */) sym = XSYMBOL (symbol); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_PLAINVAL: valcontents = SYMBOL_VAL (sym); break; case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_LOCALIZED: { struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym); - if (blv->fwd) + if (blv->fwd.fwdptr) /* In set_internal, we un-forward vars when their value is set to Qunbound. */ return Qt; @@ -695,24 +699,30 @@ global value outside of any lexical scope. */) default: emacs_abort (); } - return (EQ (valcontents, Qunbound) ? Qnil : Qt); + return (BASE_EQ (valcontents, Qunbound) ? Qnil : Qt); } /* It has been previously suggested to make this function an alias for symbol-function, but upon discussion at Bug#23957, there is a risk breaking backward compatibility, as some users of fboundp may - expect `t' in particular, rather than any true value. */ + expect t in particular, rather than any true value. */ DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, doc: /* Return t if SYMBOL's function definition is not void. */) - (register Lisp_Object symbol) + (Lisp_Object symbol) { CHECK_SYMBOL (symbol); - return NILP (XSYMBOL (symbol)->function) ? Qnil : Qt; + return NILP (XSYMBOL (symbol)->u.s.function) ? Qnil : Qt; } DEFUN ("makunbound", Fmakunbound, Smakunbound, 1, 1, 0, - doc: /* Make SYMBOL's value be void. -Return SYMBOL. */) + doc: /* Empty out the value cell of SYMBOL, making it void as a variable. +Return SYMBOL. + +If a variable is void, trying to evaluate the variable signals a +`void-variable' error, instead of returning a value. For more +details, see Info node `(elisp) Void Variables'. + +See also `fmakunbound'. */) (register Lisp_Object symbol) { CHECK_SYMBOL (symbol); @@ -723,8 +733,14 @@ Return SYMBOL. */) } DEFUN ("fmakunbound", Ffmakunbound, Sfmakunbound, 1, 1, 0, - doc: /* Make SYMBOL's function definition be nil. -Return SYMBOL. */) + doc: /* Make SYMBOL's function definition be void. +Return SYMBOL. + +If a function definition is void, trying to call a function by that +name will cause a `void-function' error. For more details, see Info +node `(elisp) Function Cells'. + +See also `makunbound'. */) (register Lisp_Object symbol) { CHECK_SYMBOL (symbol); @@ -736,18 +752,18 @@ Return SYMBOL. */) DEFUN ("symbol-function", Fsymbol_function, Ssymbol_function, 1, 1, 0, doc: /* Return SYMBOL's function definition, or nil if that is void. */) - (register Lisp_Object symbol) + (Lisp_Object symbol) { CHECK_SYMBOL (symbol); - return XSYMBOL (symbol)->function; + return XSYMBOL (symbol)->u.s.function; } DEFUN ("symbol-plist", Fsymbol_plist, Ssymbol_plist, 1, 1, 0, doc: /* Return SYMBOL's property list. */) - (register Lisp_Object symbol) + (Lisp_Object symbol) { CHECK_SYMBOL (symbol); - return XSYMBOL (symbol)->plist; + return XSYMBOL (symbol)->u.s.plist; } DEFUN ("symbol-name", Fsymbol_name, Ssymbol_name, 1, 1, 0, @@ -761,34 +777,158 @@ DEFUN ("symbol-name", Fsymbol_name, Ssymbol_name, 1, 1, 0, return name; } +DEFUN ("bare-symbol", Fbare_symbol, Sbare_symbol, 1, 1, 0, + doc: /* Extract, if need be, the bare symbol from SYM, a symbol. */) + (register Lisp_Object sym) +{ + if (BARE_SYMBOL_P (sym)) + return sym; + /* Type checking is done in the following macro. */ + return SYMBOL_WITH_POS_SYM (sym); +} + +DEFUN ("symbol-with-pos-pos", Fsymbol_with_pos_pos, Ssymbol_with_pos_pos, 1, 1, 0, + doc: /* Extract the position from a symbol with position. */) + (register Lisp_Object ls) +{ + /* Type checking is done in the following macro. */ + return SYMBOL_WITH_POS_POS (ls); +} + +DEFUN ("remove-pos-from-symbol", Fremove_pos_from_symbol, + Sremove_pos_from_symbol, 1, 1, 0, + doc: /* If ARG is a symbol with position, return it without the position. +Otherwise, return ARG unchanged. Compare with `bare-symbol'. */) + (register Lisp_Object arg) +{ + if (SYMBOL_WITH_POS_P (arg)) + return (SYMBOL_WITH_POS_SYM (arg)); + return arg; +} + +DEFUN ("position-symbol", Fposition_symbol, Sposition_symbol, 2, 2, 0, + doc: /* Create a new symbol with position. +SYM is a symbol, with or without position, the symbol to position. +POS, the position, is either a fixnum or a symbol with position from which +the position will be taken. */) + (register Lisp_Object sym, register Lisp_Object pos) +{ + Lisp_Object bare; + Lisp_Object position; + + if (BARE_SYMBOL_P (sym)) + bare = sym; + else if (SYMBOL_WITH_POS_P (sym)) + bare = XSYMBOL_WITH_POS (sym)->sym; + else + wrong_type_argument (Qsymbolp, sym); + + if (FIXNUMP (pos)) + position = pos; + else if (SYMBOL_WITH_POS_P (pos)) + position = XSYMBOL_WITH_POS (pos)->pos; + else + wrong_type_argument (Qfixnum_or_symbol_with_pos_p, pos); + + return build_symbol_with_pos (bare, position); +} + DEFUN ("fset", Ffset, Sfset, 2, 2, 0, doc: /* Set SYMBOL's function definition to DEFINITION, and return DEFINITION. */) (register Lisp_Object symbol, Lisp_Object definition) { - register Lisp_Object function; CHECK_SYMBOL (symbol); /* Perhaps not quite the right error signal, but seems good enough. */ - if (NILP (symbol)) + if (NILP (symbol) && !NILP (definition)) + /* There are so many other ways to shoot oneself in the foot, I don't + think this one little sanity check is worth its cost, but anyway. */ xsignal1 (Qsetting_constant, symbol); - function = XSYMBOL (symbol)->function; - - if (!NILP (Vautoload_queue) && !NILP (function)) - Vautoload_queue = Fcons (Fcons (symbol, function), Vautoload_queue); + eassert (valid_lisp_object_p (definition)); - if (AUTOLOADP (function)) - Fput (symbol, Qautoload, XCDR (function)); +#ifdef HAVE_NATIVE_COMP + register Lisp_Object function = XSYMBOL (symbol)->u.s.function; - /* Convert to eassert or remove after GC bug is found. In the - meantime, check unconditionally, at a slight perf hit. */ - if (! valid_lisp_object_p (definition)) - emacs_abort (); + if (comp_enable_subr_trampolines + && SUBRP (function) + && !SUBR_NATIVE_COMPILEDP (function)) + CALLN (Ffuncall, Qcomp_subr_trampoline_install, symbol); +#endif set_symbol_function (symbol, definition); return definition; } +static void +add_to_function_history (Lisp_Object symbol, Lisp_Object olddef) +{ + eassert (!NILP (olddef)); + + Lisp_Object past = Fget (symbol, Qfunction_history); + Lisp_Object file = Qnil; + /* FIXME: Sadly, `Vload_file_name` gives less precise information + (it's sometimes non-nil when it shoujld be nil). */ + Lisp_Object tail = Vcurrent_load_list; + FOR_EACH_TAIL_SAFE (tail) + if (NILP (XCDR (tail)) && STRINGP (XCAR (tail))) + file = XCAR (tail); + + Lisp_Object tem = plist_member (past, file); + if (!NILP (tem)) + { /* New def from a file used before. + Overwrite the previous record associated with this file. */ + if (EQ (tem, past)) + /* The new def is from the same file as the last change, so + there's nothing to do: unloading the file should revert to + the status before the last change rather than before this load. */ + return; + Lisp_Object pastlen = Flength (past); + Lisp_Object temlen = Flength (tem); + EMACS_INT tempos = XFIXNUM (pastlen) - XFIXNUM (temlen); + eassert (tempos > 1); + Lisp_Object prev = Fnthcdr (make_fixnum (tempos - 2), past); + /* Remove the previous info for this file. + E.g. change `hist` from (... OTHERFILE DEF3 THISFILE DEF2 ...) + to (... OTHERFILE DEF2). */ + XSETCDR (prev, XCDR (tem)); + } + /* Push new def from new file. */ + Fput (symbol, Qfunction_history, Fcons (file, Fcons (olddef, past))); +} + +void +defalias (Lisp_Object symbol, Lisp_Object definition) +{ + { + bool autoload = AUTOLOADP (definition); + if (!will_dump_p () || !autoload) + { /* Only add autoload entries after dumping, because the ones before are + not useful and else we get loads of them from the loaddefs.el. + That saves us about 110KB in the pdmp file (Jan 2022). */ + LOADHIST_ATTACH (Fcons (Qdefun, symbol)); + } + } + + { + Lisp_Object olddef = XSYMBOL (symbol)->u.s.function; + if (!NILP (olddef)) + { + if (!NILP (Vautoload_queue)) + Vautoload_queue = Fcons (symbol, Vautoload_queue); + add_to_function_history (symbol, olddef); + } + } + + { /* Handle automatic advice activation. */ + Lisp_Object hook = Fget (symbol, Qdefalias_fset_function); + if (!NILP (hook)) + call2 (hook, symbol, definition); + else + Ffset (symbol, definition); + } +} + DEFUN ("defalias", Fdefalias, Sdefalias, 2, 3, 0, doc: /* Set SYMBOL's function definition to DEFINITION. Associates the function with the current load file, if any. @@ -808,26 +948,9 @@ The return value is undefined. */) && !KEYMAPP (definition)) definition = Fpurecopy (definition); - { - bool autoload = AUTOLOADP (definition); - if (NILP (Vpurify_flag) || !autoload) - { /* Only add autoload entries after dumping, because the ones before are - not useful and else we get loads of them from the loaddefs.el. */ - - if (AUTOLOADP (XSYMBOL (symbol)->function)) - /* Remember that the function was already an autoload. */ - LOADHIST_ATTACH (Fcons (Qt, symbol)); - LOADHIST_ATTACH (Fcons (autoload ? Qautoload : Qdefun, symbol)); - } - } + defalias (symbol, definition); - { /* Handle automatic advice activation. */ - Lisp_Object hook = Fget (symbol, Qdefalias_fset_function); - if (!NILP (hook)) - call2 (hook, symbol, definition); - else - Ffset (symbol, definition); - } + maybe_defer_native_compilation (symbol, definition); if (!NILP (docstring)) Fput (symbol, Qfunction_documentation, docstring); @@ -858,10 +981,10 @@ function with `&rest' args, or `unevalled' for a special form. */) CHECK_SUBR (subr); minargs = XSUBR (subr)->min_args; maxargs = XSUBR (subr)->max_args; - return Fcons (make_number (minargs), + return Fcons (make_fixnum (minargs), maxargs == MANY ? Qmany : maxargs == UNEVALLED ? Qunevalled - : make_number (maxargs)); + : make_fixnum (maxargs)); } DEFUN ("subr-name", Fsubr_name, Ssubr_name, 1, 1, 0, @@ -875,6 +998,74 @@ SUBR must be a built-in function. */) return build_string (name); } +DEFUN ("subr-native-elisp-p", Fsubr_native_elisp_p, Ssubr_native_elisp_p, 1, 1, + 0, doc: /* Return t if the object is native compiled lisp +function, nil otherwise. */) + (Lisp_Object object) +{ + return SUBR_NATIVE_COMPILEDP (object) ? Qt : Qnil; +} + +DEFUN ("subr-native-lambda-list", Fsubr_native_lambda_list, + Ssubr_native_lambda_list, 1, 1, 0, + doc: /* Return the lambda list for a native compiled lisp/d +function or t otherwise. */) + (Lisp_Object subr) +{ + CHECK_SUBR (subr); + +#ifdef HAVE_NATIVE_COMP + if (SUBR_NATIVE_COMPILED_DYNP (subr)) + return XSUBR (subr)->lambda_list; +#endif + return Qt; +} + +DEFUN ("subr-type", Fsubr_type, + Ssubr_type, 1, 1, 0, + doc: /* Return the type of SUBR. */) + (Lisp_Object subr) +{ + CHECK_SUBR (subr); +#ifdef HAVE_NATIVE_COMP + return SUBR_TYPE (subr); +#else + return Qnil; +#endif +} + +#ifdef HAVE_NATIVE_COMP + +DEFUN ("subr-native-comp-unit", Fsubr_native_comp_unit, + Ssubr_native_comp_unit, 1, 1, 0, + doc: /* Return the native compilation unit. */) + (Lisp_Object subr) +{ + CHECK_SUBR (subr); + return XSUBR (subr)->native_comp_u; +} + +DEFUN ("native-comp-unit-file", Fnative_comp_unit_file, + Snative_comp_unit_file, 1, 1, 0, + doc: /* Return the file of the native compilation unit. */) + (Lisp_Object comp_unit) +{ + CHECK_TYPE (NATIVE_COMP_UNITP (comp_unit), Qnative_comp_unit, comp_unit); + return XNATIVE_COMP_UNIT (comp_unit)->file; +} + +DEFUN ("native-comp-unit-set-file", Fnative_comp_unit_set_file, + Snative_comp_unit_set_file, 2, 2, 0, + doc: /* Return the file of the native compilation unit. */) + (Lisp_Object comp_unit, Lisp_Object new_file) +{ + CHECK_TYPE (NATIVE_COMP_UNITP (comp_unit), Qnative_comp_unit, comp_unit); + XNATIVE_COMP_UNIT (comp_unit)->file = new_file; + return comp_unit; +} + +#endif + DEFUN ("interactive-form", Finteractive_form, Sinteractive_form, 1, 1, 0, doc: /* Return the interactive form of CMD or nil if none. If CMD is not a command, the return value is nil. @@ -882,6 +1073,7 @@ Value, if non-nil, is a list (interactive SPEC). */) (Lisp_Object cmd) { Lisp_Object fun = indirect_function (cmd); /* Check cycles. */ + bool genfun = false; if (NILP (fun)) return Qnil; @@ -900,7 +1092,10 @@ Value, if non-nil, is a list (interactive SPEC). */) if (SUBRP (fun)) { - const char *spec = XSUBR (fun)->intspec; + if (SUBR_NATIVE_COMPILEDP (fun) && !NILP (XSUBR (fun)->intspec.native)) + return XSUBR (fun)->intspec.native; + + const char *spec = XSUBR (fun)->intspec.string; if (spec) return list2 (Qinteractive, (*spec != '(') ? build_string (spec) : @@ -909,17 +1104,125 @@ Value, if non-nil, is a list (interactive SPEC). */) else if (COMPILEDP (fun)) { if (PVSIZE (fun) > COMPILED_INTERACTIVE) - return list2 (Qinteractive, AREF (fun, COMPILED_INTERACTIVE)); + { + Lisp_Object form = AREF (fun, COMPILED_INTERACTIVE); + /* The vector form is the new form, where the first + element is the interactive spec, and the second is the + command modes. */ + return list2 (Qinteractive, VECTORP (form) ? AREF (form, 0) : form); + } + else if (PVSIZE (fun) > COMPILED_DOC_STRING) + { + Lisp_Object doc = AREF (fun, COMPILED_DOC_STRING); + /* An invalid "docstring" is a sign that we have an OClosure. */ + genfun = !(NILP (doc) || VALID_DOCSTRING_P (doc)); + } + } +#ifdef HAVE_MODULES + else if (MODULE_FUNCTIONP (fun)) + { + Lisp_Object form + = module_function_interactive_form (XMODULE_FUNCTION (fun)); + if (! NILP (form)) + return form; } +#endif else if (AUTOLOADP (fun)) return Finteractive_form (Fautoload_do_load (fun, cmd, Qnil)); else if (CONSP (fun)) { Lisp_Object funcar = XCAR (fun); - if (EQ (funcar, Qclosure)) - return Fassq (Qinteractive, Fcdr (Fcdr (XCDR (fun)))); - else if (EQ (funcar, Qlambda)) - return Fassq (Qinteractive, Fcdr (XCDR (fun))); + if (EQ (funcar, Qclosure) + || EQ (funcar, Qlambda)) + { + Lisp_Object form = Fcdr (XCDR (fun)); + if (EQ (funcar, Qclosure)) + form = Fcdr (form); + Lisp_Object spec = Fassq (Qinteractive, form); + if (NILP (spec) && VALID_DOCSTRING_P (CAR_SAFE (form))) + /* A "docstring" is a sign that we may have an OClosure. */ + genfun = true; + else if (NILP (Fcdr (Fcdr (spec)))) + return spec; + else + return list2 (Qinteractive, Fcar (Fcdr (spec))); + } + } + if (genfun + /* Avoid burping during bootstrap. */ + && !NILP (Fsymbol_function (Qoclosure_interactive_form))) + return call1 (Qoclosure_interactive_form, fun); + else + return Qnil; +} + +DEFUN ("command-modes", Fcommand_modes, Scommand_modes, 1, 1, 0, + doc: /* Return the modes COMMAND is defined for. +If COMMAND is not a command, the return value is nil. +The value, if non-nil, is a list of mode name symbols. */) + (Lisp_Object command) +{ + Lisp_Object fun = indirect_function (command); /* Check cycles. */ + + if (NILP (fun)) + return Qnil; + + /* Use a `command-modes' property if present, analogous to the + function-documentation property. */ + fun = command; + while (SYMBOLP (fun)) + { + Lisp_Object modes = Fget (fun, Qcommand_modes); + if (!NILP (modes)) + return modes; + else + fun = Fsymbol_function (fun); + } + + if (SUBRP (fun)) + { + return XSUBR (fun)->command_modes; + } + else if (COMPILEDP (fun)) + { + if (PVSIZE (fun) <= COMPILED_INTERACTIVE) + return Qnil; + Lisp_Object form = AREF (fun, COMPILED_INTERACTIVE); + if (VECTORP (form)) + /* New form -- the second element is the command modes. */ + return AREF (form, 1); + else + /* Old .elc file -- no command modes. */ + return Qnil; + } +#ifdef HAVE_MODULES + else if (MODULE_FUNCTIONP (fun)) + { + Lisp_Object form + = module_function_command_modes (XMODULE_FUNCTION (fun)); + if (! NILP (form)) + return form; + } +#endif + else if (AUTOLOADP (fun)) + { + Lisp_Object modes = Fnth (make_int (3), fun); + if (CONSP (modes)) + return modes; + else + return Qnil; + } + else if (CONSP (fun)) + { + Lisp_Object funcar = XCAR (fun); + if (EQ (funcar, Qclosure) + || EQ (funcar, Qlambda)) + { + Lisp_Object form = Fcdr (XCDR (fun)); + if (EQ (funcar, Qclosure)) + form = Fcdr (form); + return Fcdr (Fcdr (Fassq (Qinteractive, form))); + } } return Qnil; } @@ -940,10 +1243,10 @@ indirect_variable (struct Lisp_Symbol *symbol) hare = tortoise = symbol; - while (hare->redirect == SYMBOL_VARALIAS) + while (hare->u.s.redirect == SYMBOL_VARALIAS) { hare = SYMBOL_ALIAS (hare); - if (hare->redirect != SYMBOL_VARALIAS) + if (hare->u.s.redirect != SYMBOL_VARALIAS) break; hare = SYMBOL_ALIAS (hare); @@ -986,14 +1289,12 @@ chain of aliases, signal a `cyclic-variable-indirection' error. */) swap_in_symval_forwarding for that. */ Lisp_Object -do_symval_forwarding (register union Lisp_Fwd *valcontents) +do_symval_forwarding (lispfwd valcontents) { - register Lisp_Object val; switch (XFWDTYPE (valcontents)) { case Lisp_Fwd_Int: - XSETINT (val, *XINTFWD (valcontents)->intvar); - return val; + return make_int (*XFIXNUMFWD (valcontents)->intvar); case Lisp_Fwd_Bool: return (*XBOOLFWD (valcontents)->boolvar ? Qt : Qnil); @@ -1029,7 +1330,7 @@ do_symval_forwarding (register union Lisp_Fwd *valcontents) void wrong_choice (Lisp_Object choice, Lisp_Object wrong) { - ptrdiff_t i = 0, len = XINT (Flength (choice)); + ptrdiff_t i = 0, len = list_length (choice); Lisp_Object obj, *args; AUTO_STRING (one_of, "One of "); AUTO_STRING (comma, ", "); @@ -1049,7 +1350,10 @@ wrong_choice (Lisp_Object choice, Lisp_Object wrong) } obj = Fconcat (i, args); - SAFE_FREE (); + + /* No need to call SAFE_FREE, since signaling does that for us. */ + (void) sa_count; + xsignal2 (Qerror, obj, wrong); } @@ -1076,13 +1380,19 @@ wrong_range (Lisp_Object min, Lisp_Object max, Lisp_Object wrong) current buffer. This only plays a role for per-buffer variables. */ static void -store_symval_forwarding (union Lisp_Fwd *valcontents, register Lisp_Object newval, struct buffer *buf) +store_symval_forwarding (lispfwd valcontents, Lisp_Object newval, + struct buffer *buf) { switch (XFWDTYPE (valcontents)) { case Lisp_Fwd_Int: - CHECK_NUMBER (newval); - *XINTFWD (valcontents)->intvar = XINT (newval); + { + intmax_t i; + CHECK_INTEGER (newval); + if (! integer_to_intmax (newval, &i)) + xsignal1 (Qoverflow_error, newval); + *XFIXNUMFWD (valcontents)->intvar = i; + } break; case Lisp_Fwd_Bool: @@ -1123,20 +1433,21 @@ store_symval_forwarding (union Lisp_Fwd *valcontents, register Lisp_Object newva int offset = XBUFFER_OBJFWD (valcontents)->offset; Lisp_Object predicate = XBUFFER_OBJFWD (valcontents)->predicate; - if (!NILP (newval)) + if (!NILP (newval) && !NILP (predicate)) { - if (SYMBOLP (predicate)) + eassert (SYMBOLP (predicate)); + Lisp_Object choiceprop = Fget (predicate, Qchoice); + if (!NILP (choiceprop)) { - Lisp_Object prop; - - if ((prop = Fget (predicate, Qchoice), !NILP (prop))) - { - if (NILP (Fmemq (newval, prop))) - wrong_choice (prop, newval); - } - else if ((prop = Fget (predicate, Qrange), !NILP (prop))) + if (NILP (Fmemq (newval, choiceprop))) + wrong_choice (choiceprop, newval); + } + else + { + Lisp_Object rangeprop = Fget (predicate, Qrange); + if (CONSP (rangeprop)) { - Lisp_Object min = XCAR (prop), max = XCDR (prop); + Lisp_Object min = XCAR (rangeprop), max = XCDR (rangeprop); if (! NUMBERP (newval) || NILP (CALLN (Fleq, min, newval, max))) wrong_range (min, max, newval); @@ -1178,17 +1489,17 @@ swap_in_global_binding (struct Lisp_Symbol *symbol) struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (symbol); /* Unload the previously loaded binding. */ - if (blv->fwd) + if (blv->fwd.fwdptr) set_blv_value (blv, do_symval_forwarding (blv->fwd)); /* Select the global binding in the symbol. */ set_blv_valcell (blv, blv->defcell); - if (blv->fwd) + if (blv->fwd.fwdptr) store_symval_forwarding (blv->fwd, XCDR (blv->defcell), NULL); /* Indicate that the global binding is set up now. */ set_blv_where (blv, Qnil); - set_blv_found (blv, 0); + set_blv_found (blv, false); } /* Set up the buffer-local symbol SYMBOL for validity in the current buffer. @@ -1213,7 +1524,7 @@ swap_in_symval_forwarding (struct Lisp_Symbol *symbol, struct Lisp_Buffer_Local_ /* Unload the previously loaded binding. */ tem1 = blv->valcell; - if (blv->fwd) + if (blv->fwd.fwdptr) set_blv_value (blv, do_symval_forwarding (blv->fwd)); /* Choose the new binding. */ { @@ -1227,7 +1538,7 @@ swap_in_symval_forwarding (struct Lisp_Symbol *symbol, struct Lisp_Buffer_Local_ /* Load the new binding. */ set_blv_valcell (blv, tem1); - if (blv->fwd) + if (blv->fwd.fwdptr) store_symval_forwarding (blv->fwd, blv_value (blv), NULL); } } @@ -1235,8 +1546,13 @@ swap_in_symval_forwarding (struct Lisp_Symbol *symbol, struct Lisp_Buffer_Local_ /* Find the value of a symbol, returning Qunbound if it's not bound. This is helpful for code which just wants to get a variable's value if it has one, without signaling an error. - Note that it must not be possible to quit - within this function. Great care is required for this. */ + + This function is very similar to buffer_local_value, but we have + two separate code paths here since find_symbol_value has to be very + efficient, while buffer_local_value doesn't have to be. + + Note that it must not be possible to quit within this function. + Great care is required for this. */ Lisp_Object find_symbol_value (Lisp_Object symbol) @@ -1247,7 +1563,7 @@ find_symbol_value (Lisp_Object symbol) sym = XSYMBOL (symbol); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: return SYMBOL_VAL (sym); @@ -1255,9 +1571,10 @@ find_symbol_value (Lisp_Object symbol) { struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym); swap_in_symval_forwarding (sym, blv); - return blv->fwd ? do_symval_forwarding (blv->fwd) : blv_value (blv); + return (blv->fwd.fwdptr + ? do_symval_forwarding (blv->fwd) + : blv_value (blv)); } - /* FALLTHROUGH */ case SYMBOL_FORWARDED: return do_symval_forwarding (SYMBOL_FWD (sym)); default: emacs_abort (); @@ -1273,7 +1590,7 @@ global value outside of any lexical scope. */) Lisp_Object val; val = find_symbol_value (symbol); - if (!EQ (val, Qunbound)) + if (!BASE_EQ (val, Qunbound)) return val; xsignal1 (Qvoid_variable, symbol); @@ -1300,17 +1617,15 @@ void set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, enum Set_Internal_Bind bindflag) { - bool voide = EQ (newval, Qunbound); - struct Lisp_Symbol *sym; - Lisp_Object tem1; + bool voide = BASE_EQ (newval, Qunbound); /* If restoring in a dead buffer, do nothing. */ /* if (BUFFERP (where) && NILP (XBUFFER (where)->name)) return; */ CHECK_SYMBOL (symbol); - sym = XSYMBOL (symbol); - switch (sym->trapped_write) + struct Lisp_Symbol *sym = XSYMBOL (symbol); + switch (sym->u.s.trapped_write) { case SYMBOL_NOWRITE: if (NILP (Fkeywordp (symbol)) @@ -1328,15 +1643,16 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, bindflag == SET_INTERNAL_UNBIND? Qunlet : voide? Qmakunbound : Qset), where); - /* FALLTHROUGH! */ + break; + case SYMBOL_UNTRAPPED_WRITE: - break; + break; default: emacs_abort (); } start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: SET_SYMBOL_VAL (sym , newval); return; @@ -1358,15 +1674,16 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, We need to unload it, and choose a new binding. */ /* Write out `realvalue' to the old loaded binding. */ - if (blv->fwd) + if (blv->fwd.fwdptr) set_blv_value (blv, do_symval_forwarding (blv->fwd)); /* Find the new binding. */ XSETSYMBOL (symbol, sym); /* May have changed via aliasing. */ - tem1 = assq_no_quit (symbol, - BVAR (XBUFFER (where), local_var_alist)); + Lisp_Object tem1 + = assq_no_quit (symbol, + BVAR (XBUFFER (where), local_var_alist)); set_blv_where (blv, where); - blv->found = 1; + blv->found = true; if (NILP (tem1)) { @@ -1381,7 +1698,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, if (bindflag || !blv->local_if_set || let_shadows_buffer_binding_p (sym)) { - blv->found = 0; + blv->found = false; tem1 = blv->defcell; } /* If it's a local_if_set, being set not bound, @@ -1405,12 +1722,12 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, /* Store the new value in the cons cell. */ set_blv_value (blv, newval); - if (blv->fwd) + if (blv->fwd.fwdptr) { if (voide) /* If storing void (making the symbol void), forward only through buffer-local indicator, not through Lisp_Objfwd, etc. */ - blv->fwd = NULL; + blv->fwd.fwdptr = NULL; else store_symval_forwarding (blv->fwd, newval, BUFFERP (where) @@ -1422,21 +1739,25 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, { struct buffer *buf = BUFFERP (where) ? XBUFFER (where) : current_buffer; - union Lisp_Fwd *innercontents = SYMBOL_FWD (sym); + lispfwd innercontents = SYMBOL_FWD (sym); if (BUFFER_OBJFWDP (innercontents)) { int offset = XBUFFER_OBJFWD (innercontents)->offset; int idx = PER_BUFFER_IDX (offset); - if (idx > 0 - && bindflag == SET_INTERNAL_SET - && !let_shadows_buffer_binding_p (sym)) - SET_PER_BUFFER_VALUE_P (buf, idx, 1); + if (idx > 0 && bindflag == SET_INTERNAL_SET + && !PER_BUFFER_VALUE_P (buf, idx)) + { + if (let_shadows_buffer_binding_p (sym)) + set_default_internal (symbol, newval, bindflag); + else + SET_PER_BUFFER_VALUE_P (buf, idx, 1); + } } if (voide) { /* If storing void (making the symbol void), forward only through buffer-local indicator, not through Lisp_Objfwd, etc. */ - sym->redirect = SYMBOL_PLAINVAL; + sym->u.s.redirect = SYMBOL_PLAINVAL; SET_SYMBOL_VAL (sym, newval); } else @@ -1452,9 +1773,9 @@ static void set_symbol_trapped_write (Lisp_Object symbol, enum symbol_trapped_write trap) { struct Lisp_Symbol *sym = XSYMBOL (symbol); - if (sym->trapped_write == SYMBOL_NOWRITE) + if (sym->u.s.trapped_write == SYMBOL_NOWRITE) xsignal1 (Qtrapping_constant, symbol); - sym->trapped_write = trap; + sym->u.s.trapped_write = trap; } static void @@ -1469,25 +1790,27 @@ harmonize_variable_watchers (Lisp_Object alias, Lisp_Object base_variable) if (!EQ (base_variable, alias) && EQ (base_variable, Findirect_variable (alias))) set_symbol_trapped_write - (alias, XSYMBOL (base_variable)->trapped_write); + (alias, XSYMBOL (base_variable)->u.s.trapped_write); } DEFUN ("add-variable-watcher", Fadd_variable_watcher, Sadd_variable_watcher, 2, 2, 0, - doc: /* Cause WATCH-FUNCTION to be called when SYMBOL is set. + doc: /* Cause WATCH-FUNCTION to be called when SYMBOL is about to be set. It will be called with 4 arguments: (SYMBOL NEWVAL OPERATION WHERE). SYMBOL is the variable being changed. -NEWVAL is the value it will be changed to. +NEWVAL is the value it will be changed to. (The variable still has +the old value when WATCH-FUNCTION is called.) OPERATION is a symbol representing the kind of change, one of: `set', `let', `unlet', `makunbound', and `defvaralias'. -WHERE is a buffer if the buffer-local value of the variable being +WHERE is a buffer if the buffer-local value of the variable is being changed, nil otherwise. All writes to aliases of SYMBOL will call WATCH-FUNCTION too. */) (Lisp_Object symbol, Lisp_Object watch_function) { symbol = Findirect_variable (symbol); + CHECK_SYMBOL (symbol); set_symbol_trapped_write (symbol, SYMBOL_TRAPPED_WRITE); map_obarray (Vobarray, harmonize_variable_watchers, symbol); @@ -1535,7 +1858,7 @@ notify_variable_watchers (Lisp_Object symbol, { symbol = Findirect_variable (symbol); - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); record_unwind_protect (restore_symbol_trapped_write, symbol); /* Avoid recursion. */ set_symbol_trapped_write (symbol, SYMBOL_UNTRAPPED_WRITE); @@ -1574,7 +1897,7 @@ notify_variable_watchers (Lisp_Object symbol, /* Return the default value of SYMBOL, but don't check for voidness. Return Qunbound if it is void. */ -static Lisp_Object +Lisp_Object default_value (Lisp_Object symbol) { struct Lisp_Symbol *sym; @@ -1583,7 +1906,7 @@ default_value (Lisp_Object symbol) sym = XSYMBOL (symbol); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: return SYMBOL_VAL (sym); @@ -1594,14 +1917,14 @@ default_value (Lisp_Object symbol) But the `realvalue' slot may be more up to date, since ordinary setq stores just that slot. So use that. */ struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym); - if (blv->fwd && EQ (blv->valcell, blv->defcell)) + if (blv->fwd.fwdptr && EQ (blv->valcell, blv->defcell)) return do_symval_forwarding (blv->fwd); else return XCDR (blv->defcell); } case SYMBOL_FORWARDED: { - union Lisp_Fwd *valcontents = SYMBOL_FWD (sym); + lispfwd valcontents = SYMBOL_FWD (sym); /* For a built-in buffer-local variable, get the default value rather than letting do_symval_forwarding get the current value. */ @@ -1621,14 +1944,15 @@ default_value (Lisp_Object symbol) DEFUN ("default-boundp", Fdefault_boundp, Sdefault_boundp, 1, 1, 0, doc: /* Return t if SYMBOL has a non-void default value. -This is the value that is seen in buffers that do not have their own values -for this variable. */) +A variable may have a buffer-local value. This function says whether +the variable has a non-void value outside of the current buffer +context. Also see `default-value'. */) (Lisp_Object symbol) { register Lisp_Object value; value = default_value (symbol); - return (EQ (value, Qunbound) ? Qnil : Qt); + return (BASE_EQ (value, Qunbound) ? Qnil : Qt); } DEFUN ("default-value", Fdefault_value, Sdefault_value, 1, 1, 0, @@ -1639,7 +1963,7 @@ local bindings in certain buffers. */) (Lisp_Object symbol) { Lisp_Object value = default_value (symbol); - if (!EQ (value, Qunbound)) + if (!BASE_EQ (value, Qunbound)) return value; xsignal1 (Qvoid_variable, symbol); @@ -1649,11 +1973,9 @@ void set_default_internal (Lisp_Object symbol, Lisp_Object value, enum Set_Internal_Bind bindflag) { - struct Lisp_Symbol *sym; - CHECK_SYMBOL (symbol); - sym = XSYMBOL (symbol); - switch (sym->trapped_write) + struct Lisp_Symbol *sym = XSYMBOL (symbol); + switch (sym->u.s.trapped_write) { case SYMBOL_NOWRITE: if (NILP (Fkeywordp (symbol)) @@ -1665,19 +1987,20 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value, case SYMBOL_TRAPPED_WRITE: /* Don't notify here if we're going to call Fset anyway. */ - if (sym->redirect != SYMBOL_PLAINVAL + if (sym->u.s.redirect != SYMBOL_PLAINVAL /* Setting due to thread switching doesn't count. */ && bindflag != SET_INTERNAL_THREAD_SWITCH) notify_variable_watchers (symbol, value, Qset_default, Qnil); - /* FALLTHROUGH! */ + break; + case SYMBOL_UNTRAPPED_WRITE: - break; + break; default: emacs_abort (); } start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: set_internal (symbol, value, Qnil, bindflag); return; @@ -1689,13 +2012,13 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value, XSETCDR (blv->defcell, value); /* If the default binding is now loaded, set the REALVALUE slot too. */ - if (blv->fwd && EQ (blv->defcell, blv->valcell)) + if (blv->fwd.fwdptr && EQ (blv->defcell, blv->valcell)) store_symval_forwarding (blv->fwd, value, NULL); return; } case SYMBOL_FORWARDED: { - union Lisp_Fwd *valcontents = SYMBOL_FWD (sym); + lispfwd valcontents = SYMBOL_FWD (sym); /* Handle variables like case-fold-search that have special slots in the buffer. @@ -1711,11 +2034,21 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value, set it in the buffers that don't nominally have a local value. */ if (idx > 0) { - struct buffer *b; + Lisp_Object buf, tail; + + /* Do this only in live buffers, so that if there are + a lot of buffers which are dead, that doesn't slow + down let-binding of variables that are + automatically local when set, like + case-fold-search. This is for Lisp programs that + let-bind such variables in their inner loops. */ + FOR_EACH_LIVE_BUFFER (tail, buf) + { + struct buffer *b = XBUFFER (buf); - FOR_EACH_BUFFER (b) - if (!PER_BUFFER_VALUE_P (b, idx)) - set_per_buffer_value (b, offset, value); + if (!PER_BUFFER_VALUE_P (b, idx)) + set_per_buffer_value (b, offset, value); + } } } else @@ -1735,43 +2068,13 @@ for this variable. */) set_default_internal (symbol, value, SET_INTERNAL_SET); return value; } - -DEFUN ("setq-default", Fsetq_default, Ssetq_default, 0, UNEVALLED, 0, - doc: /* Set the default value of variable VAR to VALUE. -VAR, the variable name, is literal (not evaluated); -VALUE is an expression: it is evaluated and its value returned. -The default value of a variable is seen in buffers -that do not have their own values for the variable. - -More generally, you can use multiple variables and values, as in - (setq-default VAR VALUE VAR VALUE...) -This sets each VAR's default value to the corresponding VALUE. -The VALUE for the Nth VAR can refer to the new default values -of previous VARs. -usage: (setq-default [VAR VALUE]...) */) - (Lisp_Object args) -{ - Lisp_Object args_left, symbol, val; - - args_left = val = args; - - while (CONSP (args_left)) - { - val = eval_sub (Fcar (XCDR (args_left))); - symbol = XCAR (args_left); - Fset_default (symbol, val); - args_left = Fcdr (XCDR (args_left)); - } - - return val; -} /* Lisp functions for creating and removing buffer-local variables. */ union Lisp_Val_Fwd { Lisp_Object value; - union Lisp_Fwd *fwd; + lispfwd fwd; }; static struct Lisp_Buffer_Local_Value * @@ -1791,12 +2094,16 @@ make_blv (struct Lisp_Symbol *sym, bool forwarded, or keyboard-local forwarding. */ eassert (!(forwarded && BUFFER_OBJFWDP (valcontents.fwd))); eassert (!(forwarded && KBOARD_OBJFWDP (valcontents.fwd))); - blv->fwd = forwarded ? valcontents.fwd : NULL; + if (forwarded) + blv->fwd = valcontents.fwd; + else + blv->fwd.fwdptr = NULL; set_blv_where (blv, Qnil); blv->local_if_set = 0; set_blv_defcell (blv, tem); set_blv_valcell (blv, tem); - set_blv_found (blv, 0); + set_blv_found (blv, false); + __lsan_ignore_object (blv); return blv; } @@ -1817,24 +2124,26 @@ a variable local to the current buffer for one particular use, use while setting up a new major mode, unless they have a `permanent-local' property. -The function `default-value' gets the default value and `set-default' sets it. */) +The function `default-value' gets the default value and `set-default' sets it. + +See also `defvar-local'. */) (register Lisp_Object variable) { struct Lisp_Symbol *sym; struct Lisp_Buffer_Local_Value *blv = NULL; - union Lisp_Val_Fwd valcontents; + union Lisp_Val_Fwd valcontents UNINIT; bool forwarded UNINIT; CHECK_SYMBOL (variable); sym = XSYMBOL (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: forwarded = 0; valcontents.value = SYMBOL_VAL (sym); - if (EQ (valcontents.value, Qunbound)) + if (BASE_EQ (valcontents.value, Qunbound)) valcontents.value = Qnil; break; case SYMBOL_LOCALIZED: @@ -1852,12 +2161,12 @@ The function `default-value' gets the default value and `set-default' sets it. } if (SYMBOL_CONSTANT_P (variable)) - error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable))); + xsignal1 (Qsetting_constant, variable); if (!blv) { blv = make_blv (sym, forwarded, valcontents); - sym->redirect = SYMBOL_LOCALIZED; + sym->u.s.redirect = SYMBOL_LOCALIZED; SET_SYMBOL_BLV (sym, blv); } @@ -1888,8 +2197,8 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) (Lisp_Object variable) { Lisp_Object tem; - bool forwarded; - union Lisp_Val_Fwd valcontents; + bool forwarded UNINIT; + union Lisp_Val_Fwd valcontents UNINIT; struct Lisp_Symbol *sym; struct Lisp_Buffer_Local_Value *blv = NULL; @@ -1897,7 +2206,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) sym = XSYMBOL (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: @@ -1914,9 +2223,8 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) default: emacs_abort (); } - if (sym->trapped_write == SYMBOL_NOWRITE) - error ("Symbol %s may not be buffer-local", - SDATA (SYMBOL_NAME (variable))); + if (sym->u.s.trapped_write == SYMBOL_NOWRITE) + xsignal1 (Qsetting_constant, variable); if (blv ? blv->local_if_set : (forwarded && BUFFER_OBJFWDP (valcontents.fwd))) @@ -1930,13 +2238,13 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) if (!blv) { blv = make_blv (sym, forwarded, valcontents); - sym->redirect = SYMBOL_LOCALIZED; + sym->u.s.redirect = SYMBOL_LOCALIZED; SET_SYMBOL_BLV (sym, blv); } /* Make sure this buffer has its own value of symbol. */ XSETSYMBOL (variable, sym); /* Update in case of aliasing. */ - tem = Fassq (variable, BVAR (current_buffer, local_var_alist)); + tem = assq_no_quit (variable, BVAR (current_buffer, local_var_alist)); if (NILP (tem)) { if (let_shadows_buffer_binding_p (sym)) @@ -1946,30 +2254,27 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) CALLN (Fmessage, format, SYMBOL_NAME (variable)); } - /* Swap out any local binding for some other buffer, and make - sure the current value is permanently recorded, if it's the - default value. */ - find_symbol_value (variable); + if (BUFFERP (blv->where) && current_buffer == XBUFFER (blv->where)) + /* Make sure the current value is permanently recorded, if it's the + default value. */ + swap_in_global_binding (sym); bset_local_var_alist (current_buffer, Fcons (Fcons (variable, XCDR (blv->defcell)), BVAR (current_buffer, local_var_alist))); - /* Make sure symbol does not think it is set up for this buffer; - force it to look once again for this buffer's value. */ - if (current_buffer == XBUFFER (blv->where)) - set_blv_where (blv, Qnil); - set_blv_found (blv, 0); + /* If the symbol forwards into a C variable, then load the binding + for this buffer now, to preserve the invariant that forwarded + variables must always hold the value corresponding to the + current buffer (they are swapped eagerly). + Otherwise, if C code modifies the variable before we load the + binding in, then that new value would clobber the default binding + the next time we unload it. See bug#34318. */ + if (blv->fwd.fwdptr) + swap_in_symval_forwarding (sym, blv); } - /* If the symbol forwards into a C variable, then load the binding - for this buffer now. If C code modifies the variable before we - load the binding in, then that new value will clobber the default - binding the next time we unload it. */ - if (blv->fwd) - swap_in_symval_forwarding (sym, blv); - return variable; } @@ -1987,13 +2292,13 @@ From now on the default value will apply in this buffer. Return VARIABLE. */) sym = XSYMBOL (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: return variable; case SYMBOL_FORWARDED: { - union Lisp_Fwd *valcontents = SYMBOL_FWD (sym); + lispfwd valcontents = SYMBOL_FWD (sym); if (BUFFER_OBJFWDP (valcontents)) { int offset = XBUFFER_OBJFWD (valcontents)->offset; @@ -2014,12 +2319,12 @@ From now on the default value will apply in this buffer. Return VARIABLE. */) default: emacs_abort (); } - if (sym->trapped_write == SYMBOL_TRAPPED_WRITE) + if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE) notify_variable_watchers (variable, Qnil, Qmakunbound, Fcurrent_buffer ()); /* Get rid of this buffer's alist element, if any. */ XSETSYMBOL (variable, sym); /* Propagate variable indirection. */ - tem = Fassq (variable, BVAR (current_buffer, local_var_alist)); + tem = assq_no_quit (variable, BVAR (current_buffer, local_var_alist)); if (!NILP (tem)) bset_local_var_alist (current_buffer, @@ -2030,12 +2335,8 @@ From now on the default value will apply in this buffer. Return VARIABLE. */) forwarded objects won't work right. */ { Lisp_Object buf; XSETBUFFER (buf, current_buffer); - if (EQ (buf, blv->where)) - { - set_blv_where (blv, Qnil); - blv->found = 0; - find_symbol_value (variable); - } + if (BASE_EQ (buf, blv->where)) + swap_in_global_binding (sym); } return variable; @@ -2046,7 +2347,9 @@ From now on the default value will apply in this buffer. Return VARIABLE. */) DEFUN ("local-variable-p", Flocal_variable_p, Slocal_variable_p, 1, 2, 0, doc: /* Non-nil if VARIABLE has a local binding in buffer BUFFER. -BUFFER defaults to the current buffer. */) +BUFFER defaults to the current buffer. + +Also see `buffer-local-boundp'.*/) (Lisp_Object variable, Lisp_Object buffer) { struct buffer *buf = decode_buffer (buffer); @@ -2056,13 +2359,13 @@ BUFFER defaults to the current buffer. */) sym = XSYMBOL (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: return Qnil; case SYMBOL_LOCALIZED: { - Lisp_Object tail, elt, tmp; + Lisp_Object tmp; struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym); XSETBUFFER (tmp, buf); XSETSYMBOL (variable, sym); /* Update in case of aliasing. */ @@ -2070,17 +2373,13 @@ BUFFER defaults to the current buffer. */) if (EQ (blv->where, tmp)) /* The binding is already loaded. */ return blv_found (blv) ? Qt : Qnil; else - for (tail = BVAR (buf, local_var_alist); CONSP (tail); tail = XCDR (tail)) - { - elt = XCAR (tail); - if (EQ (variable, XCAR (elt))) - return Qt; - } - return Qnil; + return NILP (assq_no_quit (variable, BVAR (buf, local_var_alist))) + ? Qnil + : Qt; } case SYMBOL_FORWARDED: { - union Lisp_Fwd *valcontents = SYMBOL_FWD (sym); + lispfwd valcontents = SYMBOL_FWD (sym); if (BUFFER_OBJFWDP (valcontents)) { int offset = XBUFFER_OBJFWD (valcontents)->offset; @@ -2110,7 +2409,7 @@ value in BUFFER, or if VARIABLE is automatically buffer-local (see sym = XSYMBOL (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: return Qnil; @@ -2145,13 +2444,13 @@ If the current binding is global (the default), the value is nil. */) find_symbol_value (variable); start: - switch (sym->redirect) + switch (sym->u.s.redirect) { case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start; case SYMBOL_PLAINVAL: return Qnil; case SYMBOL_FORWARDED: { - union Lisp_Fwd *valcontents = SYMBOL_FWD (sym); + lispfwd valcontents = SYMBOL_FWD (sym); if (KBOARD_OBJFWDP (valcontents)) return Fframe_terminal (selected_frame); else if (!BUFFER_OBJFWDP (valcontents)) @@ -2163,7 +2462,7 @@ If the current binding is global (the default), the value is nil. */) buffer's or frame's value we are saving. */ if (!NILP (Flocal_variable_p (variable, Qnil))) return Fcurrent_buffer (); - else if (sym->redirect == SYMBOL_LOCALIZED + else if (sym->u.s.redirect == SYMBOL_LOCALIZED && blv_found (SYMBOL_BLV (sym))) return SYMBOL_BLV (sym)->where; else @@ -2172,47 +2471,6 @@ If the current binding is global (the default), the value is nil. */) } } -/* This code is disabled now that we use the selected frame to return - keyboard-local-values. */ -#if 0 -extern struct terminal *get_terminal (Lisp_Object display, int); - -DEFUN ("terminal-local-value", Fterminal_local_value, - Sterminal_local_value, 2, 2, 0, - doc: /* Return the terminal-local value of SYMBOL on TERMINAL. -If SYMBOL is not a terminal-local variable, then return its normal -value, like `symbol-value'. - -TERMINAL may be a terminal object, a frame, or nil (meaning the -selected frame's terminal device). */) - (Lisp_Object symbol, Lisp_Object terminal) -{ - Lisp_Object result; - struct terminal *t = get_terminal (terminal, 1); - push_kboard (t->kboard); - result = Fsymbol_value (symbol); - pop_kboard (); - return result; -} - -DEFUN ("set-terminal-local-value", Fset_terminal_local_value, - Sset_terminal_local_value, 3, 3, 0, - doc: /* Set the terminal-local binding of SYMBOL on TERMINAL to VALUE. -If VARIABLE is not a terminal-local variable, then set its normal -binding, like `set'. - -TERMINAL may be a terminal object, a frame, or nil (meaning the -selected frame's terminal device). */) - (Lisp_Object symbol, Lisp_Object terminal, Lisp_Object value) -{ - Lisp_Object result; - struct terminal *t = get_terminal (terminal, 1); - push_kboard (d->kboard); - result = Fset (symbol, value); - pop_kboard (); - return result; -} -#endif /* Find the function at the end of a chain of symbol function indirections. */ @@ -2234,12 +2492,12 @@ indirect_function (register Lisp_Object object) { if (!SYMBOLP (hare) || NILP (hare)) break; - hare = XSYMBOL (hare)->function; + hare = XSYMBOL (hare)->u.s.function; if (!SYMBOLP (hare) || NILP (hare)) break; - hare = XSYMBOL (hare)->function; + hare = XSYMBOL (hare)->u.s.function; - tortoise = XSYMBOL (tortoise)->function; + tortoise = XSYMBOL (tortoise)->u.s.function; if (EQ (hare, tortoise)) xsignal1 (Qcyclic_function_indirection, object); @@ -2261,7 +2519,7 @@ function chain of symbols. */) /* Optimize for no indirection. */ result = object; if (SYMBOLP (result) && !NILP (result) - && (result = XSYMBOL (result)->function, SYMBOLP (result))) + && (result = XSYMBOL (result)->u.s.function, SYMBOLP (result))) result = indirect_function (result); if (!NILP (result)) return result; @@ -2272,15 +2530,15 @@ function chain of symbols. */) /* Extract and set vector and string elements. */ DEFUN ("aref", Faref, Saref, 2, 2, 0, - doc: /* Return the element of ARG at index IDX. -ARG may be a vector, a string, a char-table, a bool-vector, a record, + doc: /* Return the element of ARRAY at index IDX. +ARRAY may be a vector, a string, a char-table, a bool-vector, a record, or a byte-code object. IDX starts at 0. */) (register Lisp_Object array, Lisp_Object idx) { register EMACS_INT idxval; - CHECK_NUMBER (idx); - idxval = XINT (idx); + CHECK_FIXNUM (idx); + idxval = XFIXNUM (idx); if (STRINGP (array)) { int c; @@ -2289,11 +2547,11 @@ or a byte-code object. IDX starts at 0. */) if (idxval < 0 || idxval >= SCHARS (array)) args_out_of_range (array, idx); if (! STRING_MULTIBYTE (array)) - return make_number ((unsigned char) SREF (array, idxval)); + return make_fixnum ((unsigned char) SREF (array, idxval)); idxval_byte = string_char_to_byte (array, idxval); c = STRING_CHAR (SDATA (array) + idxval_byte); - return make_number (c); + return make_fixnum (c); } else if (BOOL_VECTOR_P (array)) { @@ -2330,8 +2588,8 @@ bool-vector. IDX starts at 0. */) { register EMACS_INT idxval; - CHECK_NUMBER (idx); - idxval = XINT (idx); + CHECK_FIXNUM (idx); + idxval = XFIXNUM (idx); if (! RECORDP (array)) CHECK_ARRAY (array, Qarrayp); @@ -2361,61 +2619,45 @@ bool-vector. IDX starts at 0. */) } else /* STRINGP */ { - int c; - CHECK_IMPURE (array, XSTRING (array)); if (idxval < 0 || idxval >= SCHARS (array)) args_out_of_range (array, idx); CHECK_CHARACTER (newelt); - c = XFASTINT (newelt); + int c = XFIXNAT (newelt); + ptrdiff_t idxval_byte; + int prev_bytes; + unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1; if (STRING_MULTIBYTE (array)) { - ptrdiff_t idxval_byte, nbytes; - int prev_bytes, new_bytes; - unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1; - - nbytes = SBYTES (array); idxval_byte = string_char_to_byte (array, idxval); p1 = SDATA (array) + idxval_byte; prev_bytes = BYTES_BY_CHAR_HEAD (*p1); - new_bytes = CHAR_STRING (c, p0); - if (prev_bytes != new_bytes) - { - /* We must relocate the string data. */ - ptrdiff_t nchars = SCHARS (array); - USE_SAFE_ALLOCA; - unsigned char *str = SAFE_ALLOCA (nbytes); - - memcpy (str, SDATA (array), nbytes); - allocate_string_data (XSTRING (array), nchars, - nbytes + new_bytes - prev_bytes); - memcpy (SDATA (array), str, idxval_byte); - p1 = SDATA (array) + idxval_byte; - memcpy (p1 + new_bytes, str + idxval_byte + prev_bytes, - nbytes - (idxval_byte + prev_bytes)); - SAFE_FREE (); - clear_string_char_byte_cache (); - } - while (new_bytes--) - *p1++ = *p0++; } - else + else if (SINGLE_BYTE_CHAR_P (c)) { - if (! SINGLE_BYTE_CHAR_P (c)) - { - ptrdiff_t i; - - for (i = SBYTES (array) - 1; i >= 0; i--) - if (SREF (array, i) >= 0x80) - args_out_of_range (array, newelt); - /* ARRAY is an ASCII string. Convert it to a multibyte - string, and try `aset' again. */ - STRING_SET_MULTIBYTE (array); - return Faset (array, idx, newelt); - } SSET (array, idxval, c); + return newelt; + } + else + { + for (ptrdiff_t i = SBYTES (array) - 1; i >= 0; i--) + if (!ASCII_CHAR_P (SREF (array, i))) + args_out_of_range (array, newelt); + /* ARRAY is an ASCII string. Convert it to a multibyte string. */ + STRING_SET_MULTIBYTE (array); + idxval_byte = idxval; + p1 = SDATA (array) + idxval_byte; + prev_bytes = 1; } + + int new_bytes = CHAR_STRING (c, p0); + if (prev_bytes != new_bytes) + p1 = resize_string_data (array, idxval_byte, prev_bytes, new_bytes); + + do + *p1++ = *p0++; + while (--new_bytes != 0); } return newelt; @@ -2423,34 +2665,55 @@ bool-vector. IDX starts at 0. */) /* Arithmetic functions */ +static Lisp_Object +check_integer_coerce_marker (Lisp_Object x) +{ + if (MARKERP (x)) + return make_fixnum (marker_position (x)); + CHECK_TYPE (INTEGERP (x), Qinteger_or_marker_p, x); + return x; +} + +static Lisp_Object +check_number_coerce_marker (Lisp_Object x) +{ + if (MARKERP (x)) + return make_fixnum (marker_position (x)); + CHECK_TYPE (NUMBERP (x), Qnumber_or_marker_p, x); + return x; +} + Lisp_Object arithcompare (Lisp_Object num1, Lisp_Object num2, enum Arith_Comparison comparison) { - double f1, f2; - EMACS_INT i1, i2; - bool fneq; + EMACS_INT i1 = 0, i2 = 0; + bool lt, eq = true, gt; bool test; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num1); - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num2); + num1 = check_number_coerce_marker (num1); + num2 = check_number_coerce_marker (num2); - /* If either arg is floating point, set F1 and F2 to the 'double' - approximations of the two arguments, and set FNEQ if floating-point - comparison reports that F1 is not equal to F2, possibly because F1 - or F2 is a NaN. Regardless, set I1 and I2 to integers that break - ties if the floating-point comparison is either not done or reports + /* If the comparison is mostly done by comparing two doubles, + set LT, EQ, and GT to the <, ==, > results of that comparison, + respectively, taking care to avoid problems if either is a NaN, + and trying to avoid problems on platforms where variables (in + violation of the C standard) can contain excess precision. + Regardless, set I1 and I2 to integers that break ties if the + two-double comparison is either not done or reports equality. */ if (FLOATP (num1)) { - f1 = XFLOAT_DATA (num1); + double f1 = XFLOAT_DATA (num1); if (FLOATP (num2)) { - i1 = i2 = 0; - f2 = XFLOAT_DATA (num2); + double f2 = XFLOAT_DATA (num2); + lt = f1 < f2; + eq = f1 == f2; + gt = f1 > f2; } - else + else if (FIXNUMP (num2)) { /* Compare a float NUM1 to an integer NUM2 by converting the integer I2 (i.e., NUM2) to the double F2 (a conversion that @@ -2460,52 +2723,85 @@ arithcompare (Lisp_Object num1, Lisp_Object num2, floating-point comparison reports a tie, NUM1 = F1 = F2 = I1 (exactly) so I1 - I2 = NUM1 - NUM2 (exactly), so comparing I1 to I2 will break the tie correctly. */ - i1 = f2 = i2 = XINT (num2); + double f2 = XFIXNUM (num2); + lt = f1 < f2; + eq = f1 == f2; + gt = f1 > f2; + i1 = f2; + i2 = XFIXNUM (num2); } - fneq = f1 != f2; + else if (isnan (f1)) + lt = eq = gt = false; + else + i2 = mpz_cmp_d (*xbignum_val (num2), f1); } - else + else if (FIXNUMP (num1)) { - i1 = XINT (num1); if (FLOATP (num2)) { /* Compare an integer NUM1 to a float NUM2. This is the converse of comparing float to integer (see above). */ - i2 = f1 = i1; - f2 = XFLOAT_DATA (num2); - fneq = f1 != f2; + double f1 = XFIXNUM (num1), f2 = XFLOAT_DATA (num2); + lt = f1 < f2; + eq = f1 == f2; + gt = f1 > f2; + i1 = XFIXNUM (num1); + i2 = f1; } - else + else if (FIXNUMP (num2)) { - i2 = XINT (num2); - fneq = false; + i1 = XFIXNUM (num1); + i2 = XFIXNUM (num2); } + else + i2 = mpz_sgn (*xbignum_val (num2)); + } + else if (FLOATP (num2)) + { + double f2 = XFLOAT_DATA (num2); + if (isnan (f2)) + lt = eq = gt = false; + else + i1 = mpz_cmp_d (*xbignum_val (num1), f2); + } + else if (FIXNUMP (num2)) + i1 = mpz_sgn (*xbignum_val (num1)); + else + i1 = mpz_cmp (*xbignum_val (num1), *xbignum_val (num2)); + + if (eq) + { + /* The two-double comparison either reported equality, or was not done. + Break the tie by comparing the integers. */ + lt = i1 < i2; + eq = i1 == i2; + gt = i1 > i2; } switch (comparison) { case ARITH_EQUAL: - test = !fneq && i1 == i2; + test = eq; break; case ARITH_NOTEQUAL: - test = fneq || i1 != i2; + test = !eq; break; case ARITH_LESS: - test = fneq ? f1 < f2 : i1 < i2; + test = lt; break; case ARITH_LESS_OR_EQUAL: - test = fneq ? f1 <= f2 : i1 <= i2; + test = lt | eq; break; case ARITH_GRTR: - test = fneq ? f1 > f2 : i1 > i2; + test = gt; break; case ARITH_GRTR_OR_EQUAL: - test = fneq ? f1 >= f2 : i1 >= i2; + test = gt | eq; break; default: @@ -2538,6 +2834,9 @@ DEFUN ("<", Flss, Slss, 1, MANY, 0, usage: (< NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { + if (nargs == 2 && FIXNUMP (args[0]) && FIXNUMP (args[1])) + return XFIXNUM (args[0]) < XFIXNUM (args[1]) ? Qt : Qnil; + return arithcompare_driver (nargs, args, ARITH_LESS); } @@ -2546,6 +2845,9 @@ DEFUN (">", Fgtr, Sgtr, 1, MANY, 0, usage: (> NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { + if (nargs == 2 && FIXNUMP (args[0]) && FIXNUMP (args[1])) + return XFIXNUM (args[0]) > XFIXNUM (args[1]) ? Qt : Qnil; + return arithcompare_driver (nargs, args, ARITH_GRTR); } @@ -2554,6 +2856,9 @@ DEFUN ("<=", Fleq, Sleq, 1, MANY, 0, usage: (<= NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { + if (nargs == 2 && FIXNUMP (args[0]) && FIXNUMP (args[1])) + return XFIXNUM (args[0]) <= XFIXNUM (args[1]) ? Qt : Qnil; + return arithcompare_driver (nargs, args, ARITH_LESS_OR_EQUAL); } @@ -2562,6 +2867,9 @@ DEFUN (">=", Fgeq, Sgeq, 1, MANY, 0, usage: (>= NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { + if (nargs == 2 && FIXNUMP (args[0]) && FIXNUMP (args[1])) + return XFIXNUM (args[0]) >= XFIXNUM (args[1]) ? Qt : Qnil; + return arithcompare_driver (nargs, args, ARITH_GRTR_OR_EQUAL); } @@ -2572,48 +2880,21 @@ DEFUN ("/=", Fneq, Sneq, 2, 2, 0, return arithcompare (num1, num2, ARITH_NOTEQUAL); } -/* Convert the integer I to a cons-of-integers, where I is not in - fixnum range. */ - -#define INTBIG_TO_LISP(i, extremum) \ - (eassert (FIXNUM_OVERFLOW_P (i)), \ - (! (FIXNUM_OVERFLOW_P ((extremum) >> 16) \ - && FIXNUM_OVERFLOW_P ((i) >> 16)) \ - ? Fcons (make_number ((i) >> 16), make_number ((i) & 0xffff)) \ - : ! (FIXNUM_OVERFLOW_P ((extremum) >> 16 >> 24) \ - && FIXNUM_OVERFLOW_P ((i) >> 16 >> 24)) \ - ? Fcons (make_number ((i) >> 16 >> 24), \ - Fcons (make_number ((i) >> 16 & 0xffffff), \ - make_number ((i) & 0xffff))) \ - : make_float (i))) - -Lisp_Object -intbig_to_lisp (intmax_t i) -{ - return INTBIG_TO_LISP (i, INTMAX_MIN); -} - -Lisp_Object -uintbig_to_lisp (uintmax_t i) -{ - return INTBIG_TO_LISP (i, UINTMAX_MAX); -} - /* Convert the cons-of-integers, integer, or float value C to an unsigned value with maximum value MAX, where MAX is one less than a power of 2. Signal an error if C does not have a valid format or - is out of range. */ + is out of range. + + Although Emacs represents large integers with bignums instead of + cons-of-integers or floats, for now this function still accepts the + obsolete forms in case some old Lisp code still generates them. */ uintmax_t cons_to_unsigned (Lisp_Object c, uintmax_t max) { bool valid = false; uintmax_t val UNINIT; - if (INTEGERP (c)) - { - valid = XINT (c) >= 0; - val = XINT (c); - } - else if (FLOATP (c)) + + if (FLOATP (c)) { double d = XFLOAT_DATA (c); if (d >= 0 && d < 1.0 + max) @@ -2622,27 +2903,34 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) valid = val == d; } } - else if (CONSP (c) && NATNUMP (XCAR (c))) + else { - uintmax_t top = XFASTINT (XCAR (c)); - Lisp_Object rest = XCDR (c); - if (top <= UINTMAX_MAX >> 24 >> 16 - && CONSP (rest) - && NATNUMP (XCAR (rest)) && XFASTINT (XCAR (rest)) < 1 << 24 - && NATNUMP (XCDR (rest)) && XFASTINT (XCDR (rest)) < 1 << 16) - { - uintmax_t mid = XFASTINT (XCAR (rest)); - val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); - valid = true; - } - else if (top <= UINTMAX_MAX >> 16) + Lisp_Object hi = CONSP (c) ? XCAR (c) : c; + valid = INTEGERP (hi) && integer_to_uintmax (hi, &val); + + if (valid && CONSP (c)) { - if (CONSP (rest)) - rest = XCAR (rest); - if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) + uintmax_t top = val; + Lisp_Object rest = XCDR (c); + if (top <= UINTMAX_MAX >> 24 >> 16 + && CONSP (rest) + && FIXNATP (XCAR (rest)) && XFIXNAT (XCAR (rest)) < 1 << 24 + && FIXNATP (XCDR (rest)) && XFIXNAT (XCDR (rest)) < 1 << 16) + { + uintmax_t mid = XFIXNAT (XCAR (rest)); + val = top << 24 << 16 | mid << 16 | XFIXNAT (XCDR (rest)); + } + else { - val = top << 16 | XFASTINT (rest); - valid = true; + valid = top <= UINTMAX_MAX >> 16; + if (valid) + { + if (CONSP (rest)) + rest = XCAR (rest); + valid = FIXNATP (rest) && XFIXNAT (rest) < 1 << 16; + if (valid) + val = top << 16 | XFIXNAT (rest); + } } } } @@ -2656,18 +2944,18 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) value with extrema MIN and MAX. MAX should be one less than a power of 2, and MIN should be zero or the negative of a power of 2. Signal an error if C does not have a valid format or is out of - range. */ + range. + + Although Emacs represents large integers with bignums instead of + cons-of-integers or floats, for now this function still accepts the + obsolete forms in case some old Lisp code still generates them. */ intmax_t cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) { bool valid = false; intmax_t val UNINIT; - if (INTEGERP (c)) - { - val = XINT (c); - valid = true; - } - else if (FLOATP (c)) + + if (FLOATP (c)) { double d = XFLOAT_DATA (c); if (d >= min && d < 1.0 + max) @@ -2676,27 +2964,34 @@ cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) valid = val == d; } } - else if (CONSP (c) && INTEGERP (XCAR (c))) + else { - intmax_t top = XINT (XCAR (c)); - Lisp_Object rest = XCDR (c); - if (top >= INTMAX_MIN >> 24 >> 16 && top <= INTMAX_MAX >> 24 >> 16 - && CONSP (rest) - && NATNUMP (XCAR (rest)) && XFASTINT (XCAR (rest)) < 1 << 24 - && NATNUMP (XCDR (rest)) && XFASTINT (XCDR (rest)) < 1 << 16) - { - intmax_t mid = XFASTINT (XCAR (rest)); - val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); - valid = true; - } - else if (top >= INTMAX_MIN >> 16 && top <= INTMAX_MAX >> 16) + Lisp_Object hi = CONSP (c) ? XCAR (c) : c; + valid = INTEGERP (hi) && integer_to_intmax (hi, &val); + + if (valid && CONSP (c)) { - if (CONSP (rest)) - rest = XCAR (rest); - if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) + intmax_t top = val; + Lisp_Object rest = XCDR (c); + if (top >= INTMAX_MIN >> 24 >> 16 && top <= INTMAX_MAX >> 24 >> 16 + && CONSP (rest) + && FIXNATP (XCAR (rest)) && XFIXNAT (XCAR (rest)) < 1 << 24 + && FIXNATP (XCDR (rest)) && XFIXNAT (XCDR (rest)) < 1 << 16) { - val = top << 16 | XFASTINT (rest); - valid = true; + intmax_t mid = XFIXNAT (XCAR (rest)); + val = top << 24 << 16 | mid << 16 | XFIXNAT (XCDR (rest)); + } + else + { + valid = INTMAX_MIN >> 16 <= top && top <= INTMAX_MAX >> 16; + if (valid) + { + if (CONSP (rest)) + rest = XCAR (rest); + valid = FIXNATP (rest) && XFIXNAT (rest) < 1 << 16; + if (valid) + val = top << 16 | XFIXNAT (rest); + } } } } @@ -2706,6 +3001,29 @@ cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) return val; } +/* Render NUMBER in decimal into BUFFER which ends right before END. + Return the start of the string; the end is always at END. + The string is not null-terminated. */ +char * +fixnum_to_string (EMACS_INT number, char *buffer, char *end) +{ + EMACS_INT x = number; + bool negative = x < 0; + if (negative) + x = -x; + char *p = end; + do + { + eassume (p > buffer && p - 1 < end); + *--p = '0' + x % 10; + x /= 10; + } + while (x); + if (negative) + *--p = '-'; + return p; +} + DEFUN ("number-to-string", Fnumber_to_string, Snumber_to_string, 1, 1, 0, doc: /* Return the decimal representation of NUMBER as a string. Uses a minus sign if negative. @@ -2713,16 +3031,22 @@ NUMBER may be an integer or a floating point number. */) (Lisp_Object number) { char buffer[max (FLOAT_TO_STRING_BUFSIZE, INT_BUFSIZE_BOUND (EMACS_INT))]; - int len; - CHECK_NUMBER_OR_FLOAT (number); + if (FIXNUMP (number)) + { + char *end = buffer + sizeof buffer; + char *p = fixnum_to_string (XFIXNUM (number), buffer, end); + return make_unibyte_string (p, end - p); + } + + if (BIGNUMP (number)) + return bignum_to_string (number, 10); if (FLOATP (number)) - len = float_to_string (buffer, XFLOAT_DATA (number)); - else - len = sprintf (buffer, "%"pI"d", XINT (number)); + return make_unibyte_string (buffer, + float_to_string (buffer, XFLOAT_DATA (number))); - return make_unibyte_string (buffer, len); + wrong_type_argument (Qnumberp, number); } DEFUN ("string-to-number", Fstring_to_number, Sstring_to_number, 1, 2, 0, @@ -2735,9 +3059,7 @@ present, base 10 is used. BASE must be between 2 and 16 (inclusive). If the base used is not 10, STRING is always parsed as an integer. */) (register Lisp_Object string, Lisp_Object base) { - register char *p; - register int b; - Lisp_Object val; + int b; CHECK_STRING (string); @@ -2745,18 +3067,18 @@ If the base used is not 10, STRING is always parsed as an integer. */) b = 10; else { - CHECK_NUMBER (base); - if (! (XINT (base) >= 2 && XINT (base) <= 16)) + CHECK_FIXNUM (base); + if (! (XFIXNUM (base) >= 2 && XFIXNUM (base) <= 16)) xsignal1 (Qargs_out_of_range, base); - b = XINT (base); + b = XFIXNUM (base); } - p = SSDATA (string); + char *p = SSDATA (string); while (*p == ' ' || *p == '\t') p++; - val = string_to_number (p, b, 1); - return NILP (val) ? make_number (0) : val; + Lisp_Object val = string_to_number (p, b, 0); + return NILP (val) ? make_fixnum (0) : val; } enum arithop @@ -2769,151 +3091,175 @@ enum arithop Alogior, Alogxor }; +static bool +floating_point_op (enum arithop code) +{ + return code <= Adiv; +} + +/* Return the result of applying the floating-point operation CODE to + the NARGS arguments starting at ARGS. If ARGNUM is positive, + ARGNUM of the arguments were already consumed, yielding ACCUM. + 0 <= ARGNUM < NARGS, 2 <= NARGS, and NEXT is the value of + ARGS[ARGSNUM], converted to double. */ -static Lisp_Object float_arith_driver (double, ptrdiff_t, enum arithop, - ptrdiff_t, Lisp_Object *); static Lisp_Object -arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) +floatop_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + ptrdiff_t argnum, double accum, double next) { - Lisp_Object val; - ptrdiff_t argnum, ok_args; - EMACS_INT accum = 0; - EMACS_INT next, ok_accum; - bool overflow = 0; - - switch (code) - { - case Alogior: - case Alogxor: - case Aadd: - case Asub: - accum = 0; - break; - case Amult: - case Adiv: - accum = 1; - break; - case Alogand: - accum = -1; - break; - default: - break; + if (argnum == 0) + { + accum = next; + goto next_arg; } - for (argnum = 0; argnum < nargs; argnum++) + while (true) { - if (! overflow) - { - ok_args = argnum; - ok_accum = accum; - } - - /* Using args[argnum] as argument to CHECK_NUMBER_... */ - val = args[argnum]; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val); - - if (FLOATP (val)) - return float_arith_driver (ok_accum, ok_args, code, - nargs, args); - args[argnum] = val; - next = XINT (args[argnum]); switch (code) { - case Aadd: - overflow |= INT_ADD_WRAPV (accum, next, &accum); - break; - case Asub: - if (! argnum) - accum = nargs == 1 ? - next : next; - else - overflow |= INT_SUBTRACT_WRAPV (accum, next, &accum); - break; - case Amult: - overflow |= INT_MULTIPLY_WRAPV (accum, next, &accum); - break; + case Aadd : accum += next; break; + case Asub : accum -= next; break; + case Amult: accum *= next; break; case Adiv: - if (! (argnum || nargs == 1)) - accum = next; - else - { - if (next == 0) - xsignal0 (Qarith_error); - if (INT_DIVIDE_OVERFLOW (accum, next)) - overflow = true; - else - accum /= next; - } - break; - case Alogand: - accum &= next; - break; - case Alogior: - accum |= next; - break; - case Alogxor: - accum ^= next; + if (! IEEE_FLOATING_POINT && next == 0) + xsignal0 (Qarith_error); + accum /= next; break; + default: eassume (false); } + + next_arg: + argnum++; + if (argnum == nargs) + return make_float (accum); + next = XFLOATINT (check_number_coerce_marker (args[argnum])); } +} - XSETINT (val, accum); - return val; +/* Like floatop_arith_driver, except CODE might not be a floating-point + operation, and NEXT is a Lisp float rather than a C double. */ + +static Lisp_Object +float_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + ptrdiff_t argnum, double accum, Lisp_Object next) +{ + if (! floating_point_op (code)) + wrong_type_argument (Qinteger_or_marker_p, next); + return floatop_arith_driver (code, nargs, args, argnum, accum, + XFLOAT_DATA (next)); } -#ifndef isnan -# define isnan(x) ((x) != (x)) -#endif +/* Return the result of applying the arithmetic operation CODE to the + NARGS arguments starting at ARGS. If ARGNUM is positive, ARGNUM of + the arguments were already consumed, yielding IACCUM. 0 <= ARGNUM + < NARGS, 2 <= NARGS, and VAL is the value of ARGS[ARGSNUM], + converted to integer. */ static Lisp_Object -float_arith_driver (double accum, ptrdiff_t argnum, enum arithop code, - ptrdiff_t nargs, Lisp_Object *args) +bignum_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + ptrdiff_t argnum, intmax_t iaccum, Lisp_Object val) { - register Lisp_Object val; - double next; + mpz_t const *accum; + if (argnum == 0) + { + accum = bignum_integer (&mpz[0], val); + goto next_arg; + } + mpz_set_intmax (mpz[0], iaccum); + accum = &mpz[0]; - for (; argnum < nargs; argnum++) + while (true) { - val = args[argnum]; /* using args[argnum] as argument to CHECK_NUMBER_... */ - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val); + mpz_t const *next = bignum_integer (&mpz[1], val); - if (FLOATP (val)) - { - next = XFLOAT_DATA (val); - } - else - { - args[argnum] = val; /* runs into a compiler bug. */ - next = XINT (args[argnum]); - } switch (code) { - case Aadd: - accum += next; - break; - case Asub: - accum = argnum ? accum - next : nargs == 1 ? - next : next; - break; - case Amult: - accum *= next; - break; + case Aadd : mpz_add (mpz[0], *accum, *next); break; + case Asub : mpz_sub (mpz[0], *accum, *next); break; + case Amult : emacs_mpz_mul (mpz[0], *accum, *next); break; + case Alogand: mpz_and (mpz[0], *accum, *next); break; + case Alogior: mpz_ior (mpz[0], *accum, *next); break; + case Alogxor: mpz_xor (mpz[0], *accum, *next); break; case Adiv: - if (! (argnum || nargs == 1)) - accum = next; - else - { - if (! IEEE_FLOATING_POINT && next == 0) - xsignal0 (Qarith_error); - accum /= next; - } + if (mpz_sgn (*next) == 0) + xsignal0 (Qarith_error); + mpz_tdiv_q (mpz[0], *accum, *next); break; - case Alogand: - case Alogior: - case Alogxor: - wrong_type_argument (Qinteger_or_marker_p, val); + default: + eassume (false); } + accum = &mpz[0]; + + next_arg: + argnum++; + if (argnum == nargs) + return make_integer_mpz (); + val = check_number_coerce_marker (args[argnum]); + if (FLOATP (val)) + return float_arith_driver (code, nargs, args, argnum, + mpz_get_d_rounded (*accum), val); } +} + +/* Return the result of applying the arithmetic operation CODE to the + NARGS arguments starting at ARGS, with the first argument being the + number VAL. 2 <= NARGS. Check that the remaining arguments are + numbers or markers. */ - return make_float (accum); +static Lisp_Object +arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + Lisp_Object val) +{ + eassume (2 <= nargs); + + ptrdiff_t argnum = 0; + /* Set ACCUM to VAL's value if it is a fixnum, otherwise to some + ignored value to avoid using an uninitialized variable later. */ + intmax_t accum = XFIXNUM_RAW (val); + + if (FIXNUMP (val)) + while (true) + { + argnum++; + if (argnum == nargs) + return make_int (accum); + val = check_number_coerce_marker (args[argnum]); + + /* Set NEXT to the next value if it fits, else exit the loop. */ + intmax_t next; + if (! (INTEGERP (val) && integer_to_intmax (val, &next))) + break; + + /* Set ACCUM to the next operation's result if it fits, + else exit the loop. */ + bool overflow; + intmax_t a; + switch (code) + { + case Aadd : overflow = INT_ADD_WRAPV (accum, next, &a); break; + case Amult: overflow = INT_MULTIPLY_WRAPV (accum, next, &a); break; + case Asub : overflow = INT_SUBTRACT_WRAPV (accum, next, &a); break; + case Adiv: + if (next == 0) + xsignal0 (Qarith_error); + /* This cannot overflow, as integer overflow can + occur only if the dividend is INTMAX_MIN, but + INTMAX_MIN < MOST_NEGATIVE_FIXNUM <= accum. */ + accum /= next; + continue; + case Alogand: accum &= next; continue; + case Alogior: accum |= next; continue; + case Alogxor: accum ^= next; continue; + default: eassume (false); + } + if (overflow) + break; + accum = a; + } + + return (FLOATP (val) + ? float_arith_driver (code, nargs, args, argnum, accum, val) + : bignum_arith_driver (code, nargs, args, argnum, accum, val)); } @@ -2922,7 +3268,10 @@ DEFUN ("+", Fplus, Splus, 0, MANY, 0, usage: (+ &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Aadd, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = check_number_coerce_marker (args[0]); + return nargs == 1 ? a : arith_driver (Aadd, nargs, args, a); } DEFUN ("-", Fminus, Sminus, 0, MANY, 0, @@ -2932,7 +3281,19 @@ subtracts all but the first from the first. usage: (- &optional NUMBER-OR-MARKER &rest MORE-NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Asub, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = check_number_coerce_marker (args[0]); + if (nargs == 1) + { + if (FIXNUMP (a)) + return make_int (-XFIXNUM (a)); + if (FLOATP (a)) + return make_float (-XFLOAT_DATA (a)); + mpz_neg (mpz[0], *xbignum_val (a)); + return make_integer_mpz (); + } + return arith_driver (Asub, nargs, args, a); } DEFUN ("*", Ftimes, Stimes, 0, MANY, 0, @@ -2940,7 +3301,10 @@ DEFUN ("*", Ftimes, Stimes, 0, MANY, 0, usage: (* &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Amult, nargs, args); + if (nargs == 0) + return make_fixnum (1); + Lisp_Object a = check_number_coerce_marker (args[0]); + return nargs == 1 ? a : arith_driver (Amult, nargs, args, a); } DEFUN ("/", Fquo, Squo, 1, MANY, 0, @@ -2951,71 +3315,116 @@ The arguments must be numbers or markers. usage: (/ NUMBER &rest DIVISORS) */) (ptrdiff_t nargs, Lisp_Object *args) { - ptrdiff_t argnum; - for (argnum = 2; argnum < nargs; argnum++) + Lisp_Object a = check_number_coerce_marker (args[0]); + if (nargs == 1) + { + if (FIXNUMP (a)) + { + if (XFIXNUM (a) == 0) + xsignal0 (Qarith_error); + return make_fixnum (1 / XFIXNUM (a)); + } + if (FLOATP (a)) + { + if (! IEEE_FLOATING_POINT && XFLOAT_DATA (a) == 0) + xsignal0 (Qarith_error); + return make_float (1 / XFLOAT_DATA (a)); + } + /* Dividing 1 by any bignum yields 0. */ + return make_fixnum (0); + } + + /* Do all computation in floating-point if any arg is a float. */ + for (ptrdiff_t argnum = 2; argnum < nargs; argnum++) if (FLOATP (args[argnum])) - return float_arith_driver (0, 0, Adiv, nargs, args); - return arith_driver (Adiv, nargs, args); + return floatop_arith_driver (Adiv, nargs, args, 0, 0, XFLOATINT (a)); + return arith_driver (Adiv, nargs, args, a); } -DEFUN ("%", Frem, Srem, 2, 2, 0, - doc: /* Return remainder of X divided by Y. -Both must be integers or markers. */) - (register Lisp_Object x, Lisp_Object y) +/* Return NUM % DEN (or NUM mod DEN, if MODULO). NUM and DEN must be + integers. */ +static Lisp_Object +integer_remainder (Lisp_Object num, Lisp_Object den, bool modulo) { - Lisp_Object val; + if (FIXNUMP (den)) + { + EMACS_INT d = XFIXNUM (den); + if (d == 0) + xsignal0 (Qarith_error); - CHECK_NUMBER_COERCE_MARKER (x); - CHECK_NUMBER_COERCE_MARKER (y); + EMACS_INT r; + bool have_r = false; + if (FIXNUMP (num)) + { + r = XFIXNUM (num) % d; + have_r = true; + } + else if (eabs (d) <= ULONG_MAX) + { + mpz_t const *n = xbignum_val (num); + bool neg_n = mpz_sgn (*n) < 0; + r = mpz_tdiv_ui (*n, eabs (d)); + if (neg_n) + r = -r; + have_r = true; + } - if (XINT (y) == 0) - xsignal0 (Qarith_error); + if (have_r) + { + /* If MODULO and the remainder has the wrong sign, fix it. */ + if (modulo && (d < 0 ? r > 0 : r < 0)) + r += d; - XSETINT (val, XINT (x) % XINT (y)); - return val; + return make_fixnum (r); + } + } + + mpz_t const *d = bignum_integer (&mpz[1], den); + mpz_t *r = &mpz[0]; + mpz_tdiv_r (*r, *bignum_integer (&mpz[0], num), *d); + + if (modulo) + { + /* If the remainder has the wrong sign, fix it. */ + int sgn_r = mpz_sgn (*r); + if (mpz_sgn (*d) < 0 ? sgn_r > 0 : sgn_r < 0) + mpz_add (*r, *r, *d); + } + + return make_integer_mpz (); +} + +DEFUN ("%", Frem, Srem, 2, 2, 0, + doc: /* Return remainder of X divided by Y. +Both must be integers or markers. */) + (Lisp_Object x, Lisp_Object y) +{ + x = check_integer_coerce_marker (x); + y = check_integer_coerce_marker (y); + return integer_remainder (x, y, false); } DEFUN ("mod", Fmod, Smod, 2, 2, 0, doc: /* Return X modulo Y. The result falls between zero (inclusive) and Y (exclusive). Both X and Y must be numbers or markers. */) - (register Lisp_Object x, Lisp_Object y) + (Lisp_Object x, Lisp_Object y) { - Lisp_Object val; - EMACS_INT i1, i2; - - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (x); - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (y); - + x = check_number_coerce_marker (x); + y = check_number_coerce_marker (y); if (FLOATP (x) || FLOATP (y)) return fmod_float (x, y); - - i1 = XINT (x); - i2 = XINT (y); - - if (i2 == 0) - xsignal0 (Qarith_error); - - i1 %= i2; - - /* If the "remainder" comes out with the wrong sign, fix it. */ - if (i2 < 0 ? i1 > 0 : i1 < 0) - i1 += i2; - - XSETINT (val, i1); - return val; + return integer_remainder (x, y, true); } static Lisp_Object minmax_driver (ptrdiff_t nargs, Lisp_Object *args, enum Arith_Comparison comparison) { - Lisp_Object accum = args[0]; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (accum); + Lisp_Object accum = check_number_coerce_marker (args[0]); for (ptrdiff_t argnum = 1; argnum < nargs; argnum++) { - Lisp_Object val = args[argnum]; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val); + Lisp_Object val = check_number_coerce_marker (args[argnum]); if (!NILP (arithcompare (val, accum, comparison))) accum = val; else if (FLOATP (val) && isnan (XFLOAT_DATA (val))) @@ -3048,7 +3457,10 @@ Arguments may be integers, or markers converted to integers. usage: (logand &rest INTS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Alogand, nargs, args); + if (nargs == 0) + return make_fixnum (-1); + Lisp_Object a = check_integer_coerce_marker (args[0]); + return nargs == 1 ? a : arith_driver (Alogand, nargs, args, a); } DEFUN ("logior", Flogior, Slogior, 0, MANY, 0, @@ -3057,7 +3469,10 @@ Arguments may be integers, or markers converted to integers. usage: (logior &rest INTS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Alogior, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = check_integer_coerce_marker (args[0]); + return nargs == 1 ? a : arith_driver (Alogior, nargs, args, a); } DEFUN ("logxor", Flogxor, Slogxor, 0, MANY, 0, @@ -3066,7 +3481,10 @@ Arguments may be integers, or markers converted to integers. usage: (logxor &rest INTS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Alogxor, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = check_integer_coerce_marker (args[0]); + return nargs == 1 ? a : arith_driver (Alogxor, nargs, args, a); } DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, @@ -3076,91 +3494,157 @@ of VALUE. If VALUE is negative, return the number of zero bits in the representation. */) (Lisp_Object value) { - CHECK_NUMBER (value); - EMACS_INT v = XINT (value) < 0 ? -1 - XINT (value) : XINT (value); - return make_number (EMACS_UINT_WIDTH <= UINT_WIDTH + CHECK_INTEGER (value); + + if (BIGNUMP (value)) + { + mpz_t const *nonneg = xbignum_val (value); + if (mpz_sgn (*nonneg) < 0) + { + mpz_com (mpz[0], *nonneg); + nonneg = &mpz[0]; + } + return make_fixnum (mpz_popcount (*nonneg)); + } + + eassume (FIXNUMP (value)); + EMACS_INT v = XFIXNUM (value) < 0 ? -1 - XFIXNUM (value) : XFIXNUM (value); + return make_fixnum (EMACS_UINT_WIDTH <= UINT_WIDTH ? count_one_bits (v) : EMACS_UINT_WIDTH <= ULONG_WIDTH ? count_one_bits_l (v) : count_one_bits_ll (v)); } -static Lisp_Object -ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) -{ - /* This code assumes that signed right shifts are arithmetic. */ - verify ((EMACS_INT) -1 >> 1 == -1); +DEFUN ("ash", Fash, Sash, 2, 2, 0, + doc: /* Return integer VALUE with its bits shifted left by COUNT bit positions. +If COUNT is negative, shift VALUE to the right instead. +VALUE and COUNT must be integers. +Mathematically, the return value is VALUE multiplied by 2 to the +power of COUNT, rounded down. If the result is non-zero, its sign +is the same as that of VALUE. +In terms of bits, when COUNT is positive, the function moves +the bits of VALUE to the left, adding zero bits on the right; when +COUNT is negative, it moves the bits of VALUE to the right, +discarding bits. */) + (Lisp_Object value, Lisp_Object count) +{ + CHECK_INTEGER (value); + CHECK_INTEGER (count); + + if (! FIXNUMP (count)) + { + if (BASE_EQ (value, make_fixnum (0))) + return value; + if (mpz_sgn (*xbignum_val (count)) < 0) + { + EMACS_INT v = (FIXNUMP (value) ? XFIXNUM (value) + : mpz_sgn (*xbignum_val (value))); + return make_fixnum (v < 0 ? -1 : 0); + } + overflow_error (); + } - Lisp_Object val; + if (XFIXNUM (count) <= 0) + { + if (XFIXNUM (count) == 0) + return value; - CHECK_NUMBER (value); - CHECK_NUMBER (count); + if ((EMACS_INT) -1 >> 1 == -1 && FIXNUMP (value)) + { + EMACS_INT shift = -XFIXNUM (count); + EMACS_INT result + = (shift < EMACS_INT_WIDTH ? XFIXNUM (value) >> shift + : XFIXNUM (value) < 0 ? -1 : 0); + return make_fixnum (result); + } + } - if (XINT (count) >= EMACS_INT_WIDTH) - XSETINT (val, 0); - else if (XINT (count) > 0) - XSETINT (val, XUINT (value) << XINT (count)); - else if (XINT (count) <= -EMACS_INT_WIDTH) - XSETINT (val, lsh ? 0 : XINT (value) < 0 ? -1 : 0); + mpz_t const *zval = bignum_integer (&mpz[0], value); + if (XFIXNUM (count) < 0) + { + if (TYPE_MAXIMUM (mp_bitcnt_t) < - XFIXNUM (count)) + return make_fixnum (mpz_sgn (*zval) < 0 ? -1 : 0); + mpz_fdiv_q_2exp (mpz[0], *zval, - XFIXNUM (count)); + } else - XSETINT (val, (lsh ? XUINT (value) >> -XINT (count) - : XINT (value) >> -XINT (count))); - return val; + emacs_mpz_mul_2exp (mpz[0], *zval, XFIXNUM (count)); + return make_integer_mpz (); } -DEFUN ("ash", Fash, Sash, 2, 2, 0, - doc: /* Return VALUE with its bits shifted left by COUNT. -If COUNT is negative, shifting is actually to the right. -In this case, the sign bit is duplicated. */) - (register Lisp_Object value, Lisp_Object count) -{ - return ash_lsh_impl (value, count, false); -} +/* Return X ** Y as an integer. X and Y must be integers, and Y must + be nonnegative. */ -DEFUN ("lsh", Flsh, Slsh, 2, 2, 0, - doc: /* Return VALUE with its bits shifted left by COUNT. -If COUNT is negative, shifting is actually to the right. -In this case, zeros are shifted in on the left. */) - (register Lisp_Object value, Lisp_Object count) -{ - return ash_lsh_impl (value, count, true); +Lisp_Object +expt_integer (Lisp_Object x, Lisp_Object y) +{ + /* Special cases for -1 <= x <= 1, which never overflow. */ + if (BASE_EQ (x, make_fixnum (1))) + return x; + if (BASE_EQ (x, make_fixnum (0))) + return BASE_EQ (x, y) ? make_fixnum (1) : x; + if (BASE_EQ (x, make_fixnum (-1))) + return ((FIXNUMP (y) ? XFIXNUM (y) & 1 : mpz_odd_p (*xbignum_val (y))) + ? x : make_fixnum (1)); + + unsigned long exp; + if (FIXNUMP (y)) + { + if (ULONG_MAX < XFIXNUM (y)) + overflow_error (); + exp = XFIXNUM (y); + } + else + { + if (ULONG_MAX <= MOST_POSITIVE_FIXNUM + || !mpz_fits_ulong_p (*xbignum_val (y))) + overflow_error (); + exp = mpz_get_ui (*xbignum_val (y)); + } + + emacs_mpz_pow_ui (mpz[0], *bignum_integer (&mpz[0], x), exp); + return make_integer_mpz (); } DEFUN ("1+", Fadd1, Sadd1, 1, 1, 0, doc: /* Return NUMBER plus one. NUMBER may be a number or a marker. Markers are converted to integers. */) - (register Lisp_Object number) + (Lisp_Object number) { - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (number); + number = check_number_coerce_marker (number); + if (FIXNUMP (number)) + return make_int (XFIXNUM (number) + 1); if (FLOATP (number)) return (make_float (1.0 + XFLOAT_DATA (number))); - - XSETINT (number, XINT (number) + 1); - return number; + mpz_add_ui (mpz[0], *xbignum_val (number), 1); + return make_integer_mpz (); } DEFUN ("1-", Fsub1, Ssub1, 1, 1, 0, doc: /* Return NUMBER minus one. NUMBER may be a number or a marker. Markers are converted to integers. */) - (register Lisp_Object number) + (Lisp_Object number) { - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (number); + number = check_number_coerce_marker (number); + if (FIXNUMP (number)) + return make_int (XFIXNUM (number) - 1); if (FLOATP (number)) return (make_float (-1.0 + XFLOAT_DATA (number))); - - XSETINT (number, XINT (number) - 1); - return number; + mpz_sub_ui (mpz[0], *xbignum_val (number), 1); + return make_integer_mpz (); } DEFUN ("lognot", Flognot, Slognot, 1, 1, 0, doc: /* Return the bitwise complement of NUMBER. NUMBER must be an integer. */) (register Lisp_Object number) { - CHECK_NUMBER (number); - XSETINT (number, ~XINT (number)); - return number; + CHECK_INTEGER (number); + if (FIXNUMP (number)) + return make_fixnum (~XFIXNUM (number)); + mpz_com (mpz[0], *xbignum_val (number)); + return make_integer_mpz (); } DEFUN ("byteorder", Fbyteorder, Sbyteorder, 0, 0, 0, @@ -3173,7 +3657,7 @@ lowercase l) for small endian machines. */ unsigned i = 0x04030201; int order = *(char *)&i == 1 ? 108 : 66; - return make_number (order); + return make_fixnum (order); } /* Because we round up the bool vector allocate size to word_size @@ -3186,27 +3670,14 @@ bool_vector_spare_mask (EMACS_INT nr_bits) return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1; } -/* Info about unsigned long long, falling back on unsigned long - if unsigned long long is not available. */ - -#if HAVE_UNSIGNED_LONG_LONG_INT && defined ULLONG_WIDTH -enum { ULL_WIDTH = ULLONG_WIDTH }; -# define ULL_MAX ULLONG_MAX -#else -enum { ULL_WIDTH = ULONG_WIDTH }; -# define ULL_MAX ULONG_MAX -# define count_one_bits_ll count_one_bits_l -# define count_trailing_zeros_ll count_trailing_zeros_l -#endif - /* Shift VAL right by the width of an unsigned long long. - ULL_WIDTH must be less than BITS_PER_BITS_WORD. */ + ULLONG_WIDTH must be less than BITS_PER_BITS_WORD. */ static bits_word shift_right_ull (bits_word w) { /* Pacify bogus GCC warning about shift count exceeding type width. */ - int shift = ULL_WIDTH - BITS_PER_BITS_WORD < 0 ? ULL_WIDTH : 0; + int shift = ULLONG_WIDTH - BITS_PER_BITS_WORD < 0 ? ULLONG_WIDTH : 0; return w >> shift; } @@ -3223,7 +3694,7 @@ count_one_bits_word (bits_word w) { int i = 0, count = 0; while (count += count_one_bits_ll (w), - (i += ULL_WIDTH) < BITS_PER_BITS_WORD) + (i += ULLONG_WIDTH) < BITS_PER_BITS_WORD) w = shift_right_ull (w); return count; } @@ -3354,7 +3825,7 @@ count_trailing_zero_bits (bits_word val) return count_trailing_zeros (val); if (BITS_WORD_MAX == ULONG_MAX) return count_trailing_zeros_l (val); - if (BITS_WORD_MAX == ULL_MAX) + if (BITS_WORD_MAX == ULLONG_MAX) return count_trailing_zeros_ll (val); /* The rest of this code is for the unlikely platform where bits_word differs @@ -3368,18 +3839,18 @@ count_trailing_zero_bits (bits_word val) { int count; for (count = 0; - count < BITS_PER_BITS_WORD - ULL_WIDTH; - count += ULL_WIDTH) + count < BITS_PER_BITS_WORD - ULLONG_WIDTH; + count += ULLONG_WIDTH) { - if (val & ULL_MAX) + if (val & ULLONG_MAX) return count + count_trailing_zeros_ll (val); val = shift_right_ull (val); } - if (BITS_PER_BITS_WORD % ULL_WIDTH != 0 + if (BITS_PER_BITS_WORD % ULLONG_WIDTH != 0 && BITS_WORD_MAX == (bits_word) -1) val |= (bits_word) 1 << pre_value (ULONG_MAX < BITS_WORD_MAX, - BITS_PER_BITS_WORD % ULL_WIDTH); + BITS_PER_BITS_WORD % ULLONG_WIDTH); return count + count_trailing_zeros_ll (val); } } @@ -3392,10 +3863,8 @@ bits_word_to_host_endian (bits_word val) #else if (BITS_WORD_MAX >> 31 == 1) return bswap_32 (val); -# if HAVE_UNSIGNED_LONG_LONG if (BITS_WORD_MAX >> 31 >> 31 >> 1 == 1) return bswap_64 (val); -# endif { int i; bits_word r = 0; @@ -3526,7 +3995,7 @@ value from A's length. */) for (i = 0; i < nwords; i++) count += count_one_bits_word (adata[i]); - return make_number (count); + return make_fixnum (count); } DEFUN ("bool-vector-count-consecutive", Fbool_vector_count_consecutive, @@ -3545,16 +4014,16 @@ A is a bool vector, B is t or nil, and I is an index into A. */) ptrdiff_t nr_words; CHECK_BOOL_VECTOR (a); - CHECK_NATNUM (i); + CHECK_FIXNAT (i); nr_bits = bool_vector_size (a); - if (XFASTINT (i) > nr_bits) /* Allow one past the end for convenience */ + if (XFIXNAT (i) > nr_bits) /* Allow one past the end for convenience */ args_out_of_range (a, i); adata = bool_vector_data (a); nr_words = bool_vector_words (nr_bits); - pos = XFASTINT (i) / BITS_PER_BITS_WORD; - offset = XFASTINT (i) % BITS_PER_BITS_WORD; + pos = XFIXNAT (i) / BITS_PER_BITS_WORD; + offset = XFIXNAT (i) % BITS_PER_BITS_WORD; count = 0; /* By XORing with twiddle, we transform the problem of "count @@ -3575,7 +4044,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) count = count_trailing_zero_bits (mword); pos++; if (count + offset < BITS_PER_BITS_WORD) - return make_number (count); + return make_fixnum (count); } /* Scan whole words until we either reach the end of the vector or @@ -3602,14 +4071,14 @@ A is a bool vector, B is t or nil, and I is an index into A. */) count -= BITS_PER_BITS_WORD - nr_bits % BITS_PER_BITS_WORD; } - return make_number (count); + return make_fixnum (count); } void syms_of_data (void) { - Lisp_Object error_tail, arith_tail; + Lisp_Object error_tail, arith_tail, recursion_tail; DEFSYM (Qquote, "quote"); DEFSYM (Qlambda, "lambda"); @@ -3620,6 +4089,7 @@ syms_of_data (void) DEFSYM (Qerror, "error"); DEFSYM (Quser_error, "user-error"); DEFSYM (Qquit, "quit"); + DEFSYM (Qminibuffer_quit, "minibuffer-quit"); DEFSYM (Qwrong_length_argument, "wrong-length-argument"); DEFSYM (Qwrong_type_argument, "wrong-type-argument"); DEFSYM (Qargs_out_of_range, "args-out-of-range"); @@ -3641,11 +4111,20 @@ syms_of_data (void) DEFSYM (Qbuffer_read_only, "buffer-read-only"); DEFSYM (Qtext_read_only, "text-read-only"); DEFSYM (Qmark_inactive, "mark-inactive"); + DEFSYM (Qinhibited_interaction, "inhibited-interaction"); + + DEFSYM (Qrecursion_error, "recursion-error"); + DEFSYM (Qexcessive_variable_binding, "excessive-variable-binding"); + DEFSYM (Qexcessive_lisp_nesting, "excessive-lisp-nesting"); DEFSYM (Qlistp, "listp"); DEFSYM (Qconsp, "consp"); + DEFSYM (Qbare_symbol_p, "bare-symbol-p"); + DEFSYM (Qsymbol_with_pos_p, "symbol-with-pos-p"); DEFSYM (Qsymbolp, "symbolp"); + DEFSYM (Qfixnump, "fixnump"); DEFSYM (Qintegerp, "integerp"); + DEFSYM (Qbooleanp, "booleanp"); DEFSYM (Qnatnump, "natnump"); DEFSYM (Qwholenump, "wholenump"); DEFSYM (Qstringp, "stringp"); @@ -3657,9 +4136,7 @@ syms_of_data (void) DEFSYM (Qbool_vector_p, "bool-vector-p"); DEFSYM (Qchar_or_string_p, "char-or-string-p"); DEFSYM (Qmarkerp, "markerp"); -#ifdef HAVE_MODULES DEFSYM (Quser_ptrp, "user-ptrp"); -#endif DEFSYM (Qbuffer_or_string_p, "buffer-or-string-p"); DEFSYM (Qinteger_or_marker_p, "integer-or-marker-p"); DEFSYM (Qfboundp, "fboundp"); @@ -3670,6 +4147,8 @@ syms_of_data (void) DEFSYM (Qchar_table_p, "char-table-p"); DEFSYM (Qvector_or_char_table_p, "vector-or-char-table-p"); + DEFSYM (Qfixnum_or_symbol_with_pos_p, "fixnum-or-symbol-with-pos-p"); + DEFSYM (Qoclosure_interactive_form, "oclosure-interactive-form"); DEFSYM (Qsubrp, "subrp"); DEFSYM (Qunevalled, "unevalled"); @@ -3692,6 +4171,7 @@ syms_of_data (void) Fput (sym, Qerror_message, build_pure_c_string (msg)) PUT_ERROR (Qquit, Qnil, "Quit"); + PUT_ERROR (Qminibuffer_quit, pure_cons (Qquit, Qnil), "Quit"); PUT_ERROR (Quser_error, error_tail, ""); PUT_ERROR (Qwrong_length_argument, error_tail, "Wrong length argument"); @@ -3726,6 +4206,8 @@ syms_of_data (void) PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only"); PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail), "Text is read-only"); + PUT_ERROR (Qinhibited_interaction, error_tail, + "User interaction while inhibited"); DEFSYM (Qrange_error, "range-error"); DEFSYM (Qdomain_error, "domain-error"); @@ -3740,23 +4222,33 @@ syms_of_data (void) PUT_ERROR (Qsingularity_error, Fcons (Qdomain_error, arith_tail), "Arithmetic singularity error"); - PUT_ERROR (Qoverflow_error, Fcons (Qdomain_error, arith_tail), + PUT_ERROR (Qoverflow_error, Fcons (Qrange_error, arith_tail), "Arithmetic overflow error"); - PUT_ERROR (Qunderflow_error, Fcons (Qdomain_error, arith_tail), + PUT_ERROR (Qunderflow_error, Fcons (Qrange_error, arith_tail), "Arithmetic underflow error"); + recursion_tail = pure_cons (Qrecursion_error, error_tail); + Fput (Qrecursion_error, Qerror_conditions, recursion_tail); + Fput (Qrecursion_error, Qerror_message, build_pure_c_string + ("Excessive recursive calling error")); + + PUT_ERROR (Qexcessive_variable_binding, recursion_tail, + "Variable binding depth exceeds max-specpdl-size"); + PUT_ERROR (Qexcessive_lisp_nesting, recursion_tail, + "Lisp nesting exceeds `max-lisp-eval-depth'"); + /* Types that type-of returns. */ DEFSYM (Qinteger, "integer"); DEFSYM (Qsymbol, "symbol"); DEFSYM (Qstring, "string"); DEFSYM (Qcons, "cons"); DEFSYM (Qmarker, "marker"); + DEFSYM (Qsymbol_with_pos, "symbol-with-pos"); DEFSYM (Qoverlay, "overlay"); DEFSYM (Qfinalizer, "finalizer"); -#ifdef HAVE_MODULES DEFSYM (Qmodule_function, "module-function"); + DEFSYM (Qnative_comp_unit, "native-comp-unit"); DEFSYM (Quser_ptr, "user-ptr"); -#endif DEFSYM (Qfloat, "float"); DEFSYM (Qwindow_configuration, "window-configuration"); DEFSYM (Qprocess, "process"); @@ -3777,14 +4269,20 @@ syms_of_data (void) DEFSYM (Qfont_entity, "font-entity"); DEFSYM (Qfont_object, "font-object"); DEFSYM (Qterminal, "terminal"); + DEFSYM (Qxwidget, "xwidget"); + DEFSYM (Qxwidget_view, "xwidget-view"); DEFSYM (Qdefun, "defun"); DEFSYM (Qinteractive_form, "interactive-form"); DEFSYM (Qdefalias_fset_function, "defalias-fset-function"); + DEFSYM (Qfunction_history, "function-history"); + + DEFSYM (Qbyte_code_function_p, "byte-code-function-p"); defsubr (&Sindirect_variable); defsubr (&Sinteractive_form); + defsubr (&Scommand_modes); defsubr (&Seq); defsubr (&Snull); defsubr (&Stype_of); @@ -3798,6 +4296,8 @@ syms_of_data (void) defsubr (&Snumber_or_marker_p); defsubr (&Sfloatp); defsubr (&Snatnump); + defsubr (&Sbare_symbol_p); + defsubr (&Ssymbol_with_pos_p); defsubr (&Ssymbolp); defsubr (&Skeywordp); defsubr (&Sstringp); @@ -3828,6 +4328,10 @@ syms_of_data (void) defsubr (&Sindirect_function); defsubr (&Ssymbol_plist); defsubr (&Ssymbol_name); + defsubr (&Sbare_symbol); + defsubr (&Ssymbol_with_pos_pos); + defsubr (&Sremove_pos_from_symbol); + defsubr (&Sposition_symbol); defsubr (&Smakunbound); defsubr (&Sfmakunbound); defsubr (&Sboundp); @@ -3840,17 +4344,12 @@ syms_of_data (void) defsubr (&Sdefault_boundp); defsubr (&Sdefault_value); defsubr (&Sset_default); - defsubr (&Ssetq_default); defsubr (&Smake_variable_buffer_local); defsubr (&Smake_local_variable); defsubr (&Skill_local_variable); defsubr (&Slocal_variable_p); defsubr (&Slocal_variable_if_set_p); defsubr (&Svariable_binding_locus); -#if 0 /* XXX Remove this. --lorentey */ - defsubr (&Sterminal_local_value); - defsubr (&Sset_terminal_local_value); -#endif defsubr (&Saref); defsubr (&Saset); defsubr (&Snumber_to_string); @@ -3873,7 +4372,6 @@ syms_of_data (void) defsubr (&Slogior); defsubr (&Slogxor); defsubr (&Slogcount); - defsubr (&Slsh); defsubr (&Sash); defsubr (&Sadd1); defsubr (&Ssub1); @@ -3881,6 +4379,14 @@ syms_of_data (void) defsubr (&Sbyteorder); defsubr (&Ssubr_arity); defsubr (&Ssubr_name); + defsubr (&Ssubr_native_elisp_p); + defsubr (&Ssubr_native_lambda_list); + defsubr (&Ssubr_type); +#ifdef HAVE_NATIVE_COMP + defsubr (&Ssubr_native_comp_unit); + defsubr (&Snative_comp_unit_file); + defsubr (&Snative_comp_unit_set_file); +#endif #ifdef HAVE_MODULES defsubr (&Suser_ptrp); #endif @@ -3894,23 +4400,32 @@ syms_of_data (void) defsubr (&Sbool_vector_count_consecutive); defsubr (&Sbool_vector_count_population); - set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->function); + set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->u.s.function); DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, - doc: /* The largest value that is representable in a Lisp integer. */); - Vmost_positive_fixnum = make_number (MOST_POSITIVE_FIXNUM); + doc: /* The greatest integer that is represented efficiently. +This variable cannot be set; trying to do so will signal an error. */); + Vmost_positive_fixnum = make_fixnum (MOST_POSITIVE_FIXNUM); make_symbol_constant (intern_c_string ("most-positive-fixnum")); DEFVAR_LISP ("most-negative-fixnum", Vmost_negative_fixnum, - doc: /* The smallest value that is representable in a Lisp integer. */); - Vmost_negative_fixnum = make_number (MOST_NEGATIVE_FIXNUM); + doc: /* The least integer that is represented efficiently. +This variable cannot be set; trying to do so will signal an error. */); + Vmost_negative_fixnum = make_fixnum (MOST_NEGATIVE_FIXNUM); make_symbol_constant (intern_c_string ("most-negative-fixnum")); + DEFSYM (Qsymbols_with_pos_enabled, "symbols-with-pos-enabled"); + DEFVAR_BOOL ("symbols-with-pos-enabled", symbols_with_pos_enabled, + doc: /* Non-nil when "symbols with position" can be used as symbols. +Bind this to non-nil in applications such as the byte compiler. */); + symbols_with_pos_enabled = false; + DEFSYM (Qwatchers, "watchers"); DEFSYM (Qmakunbound, "makunbound"); DEFSYM (Qunlet, "unlet"); DEFSYM (Qset, "set"); DEFSYM (Qset_default, "set-default"); + DEFSYM (Qcommand_modes, "command-modes"); defsubr (&Sadd_variable_watcher); defsubr (&Sremove_variable_watcher); defsubr (&Sget_variable_watchers); |