aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoam Postavsky2015-11-19 19:50:06 -0500
committerNoam Postavsky2016-12-02 20:25:14 -0500
commit227213164e06363f0a4fb2beeeb647c99749299e (patch)
tree8fda48112af0631ce9b6c595e33101a9b5961909
parent0fc4761ca88175c30da7209c9ab1cde788b66a76 (diff)
downloademacs-227213164e06363f0a4fb2beeeb647c99749299e.tar.gz
emacs-227213164e06363f0a4fb2beeeb647c99749299e.zip
Add lisp watchpoints
This allows calling a function whenever a symbol-value is changed. * src/lisp.h (lisp_h_SYMBOL_TRAPPED_WRITE_P): (SYMBOL_TRAPPED_WRITE_P): New function/macro. (lisp_h_SYMBOL_CONSTANT_P): Check for SYMBOL_NOWRITE specifically. (enum symbol_trapped_write): New enumeration. (struct Lisp_Symbol): Rename field constant to trapped_write. (make_symbol_constant): New function. * src/data.c (Fadd_variable_watcher, Fremove_variable_watcher): (set_symbol_trapped_write, restore_symbol_trapped_write): (harmonize_variable_watchers, notify_variable_watchers): New functions. * src/data.c (Fset_default): Call `notify_variable_watchers' for trapped symbols. (set_internal): Change bool argument BIND to 3-value enum and call `notify_variable_watchers' for trapped symbols. * src/data.c (syms_of_data): * src/data.c (syms_of_data): * src/font.c (syms_of_font): * src/lread.c (intern_sym, init_obarray): * src/buffer.c (syms_of_buffer): Use make_symbol_constant. * src/alloc.c (init_symbol): * src/bytecode.c (exec_byte_code): Use SYMBOL_TRAPPED_WRITE_P. * src/data.c (Fmake_variable_buffer_local, Fmake_local_variable): (Fmake_variable_frame_local): * src/eval.c (Fdefvaralias, specbind): Refer to Lisp_Symbol's trapped_write instead of constant. (Ffuncall): Move subr calling code into separate function. (funcall_subr): New function.
-rw-r--r--src/alloc.c2
-rw-r--r--src/buffer.c82
-rw-r--r--src/bytecode.c4
-rw-r--r--src/data.c191
-rw-r--r--src/eval.c206
-rw-r--r--src/font.c6
-rw-r--r--src/lisp.h54
-rw-r--r--src/lread.c6
8 files changed, 378 insertions, 173 deletions
diff --git a/src/alloc.c b/src/alloc.c
index ae32400708a..6eced7bab18 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3567,7 +3567,7 @@ init_symbol (Lisp_Object val, Lisp_Object name)
3567 set_symbol_next (val, NULL); 3567 set_symbol_next (val, NULL);
3568 p->gcmarkbit = false; 3568 p->gcmarkbit = false;
3569 p->interned = SYMBOL_UNINTERNED; 3569 p->interned = SYMBOL_UNINTERNED;
3570 p->constant = 0; 3570 p->trapped_write = SYMBOL_UNTRAPPED_WRITE;
3571 p->declared_special = false; 3571 p->declared_special = false;
3572 p->pinned = false; 3572 p->pinned = false;
3573} 3573}
diff --git a/src/buffer.c b/src/buffer.c
index aa556b75bc6..6815aa7f7ed 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -984,40 +984,54 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too)
984 bset_local_var_alist (b, Qnil); 984 bset_local_var_alist (b, Qnil);
985 else 985 else
986 { 986 {
987 Lisp_Object tmp, prop, last = Qnil; 987 Lisp_Object tmp, last = Qnil;
988 for (tmp = BVAR (b, local_var_alist); CONSP (tmp); tmp = XCDR (tmp)) 988 for (tmp = BVAR (b, local_var_alist); CONSP (tmp); tmp = XCDR (tmp))
989 if (!NILP (prop = Fget (XCAR (XCAR (tmp)), Qpermanent_local))) 989 {
990 { 990 Lisp_Object local_var = XCAR (XCAR (tmp));
991 /* If permanent-local, keep it. */ 991 Lisp_Object prop = Fget (local_var, Qpermanent_local);
992 last = tmp; 992
993 if (EQ (prop, Qpermanent_local_hook)) 993 if (!NILP (prop))
994 { 994 {
995 /* This is a partially permanent hook variable. 995 /* If permanent-local, keep it. */
996 Preserve only the elements that want to be preserved. */ 996 last = tmp;
997 Lisp_Object list, newlist; 997 if (EQ (prop, Qpermanent_local_hook))
998 list = XCDR (XCAR (tmp)); 998 {
999 if (!CONSP (list)) 999 /* This is a partially permanent hook variable.
1000 newlist = list; 1000 Preserve only the elements that want to be preserved. */
1001 else 1001 Lisp_Object list, newlist;
1002 for (newlist = Qnil; CONSP (list); list = XCDR (list)) 1002 list = XCDR (XCAR (tmp));
1003 { 1003 if (!CONSP (list))
1004 Lisp_Object elt = XCAR (list); 1004 newlist = list;
1005 /* Preserve element ELT if it's t, 1005 else
1006 if it is a function with a `permanent-local-hook' property, 1006 for (newlist = Qnil; CONSP (list); list = XCDR (list))
1007 or if it's not a symbol. */ 1007 {
1008 if (! SYMBOLP (elt) 1008 Lisp_Object elt = XCAR (list);
1009 || EQ (elt, Qt) 1009 /* Preserve element ELT if it's t,
1010 || !NILP (Fget (elt, Qpermanent_local_hook))) 1010 if it is a function with a `permanent-local-hook' property,
1011 newlist = Fcons (elt, newlist); 1011 or if it's not a symbol. */
1012 } 1012 if (! SYMBOLP (elt)
1013 XSETCDR (XCAR (tmp), Fnreverse (newlist)); 1013 || EQ (elt, Qt)
1014 } 1014 || !NILP (Fget (elt, Qpermanent_local_hook)))
1015 } 1015 newlist = Fcons (elt, newlist);
1016 /* Delete this local variable. */ 1016 }
1017 else if (NILP (last)) 1017 newlist = Fnreverse (newlist);
1018 bset_local_var_alist (b, XCDR (tmp)); 1018 if (XSYMBOL (local_var)->trapped_write == SYMBOL_TRAPPED_WRITE)
1019 else 1019 notify_variable_watchers (local_var, newlist,
1020 XSETCDR (last, XCDR (tmp)); 1020 Qmakunbound, Fcurrent_buffer ());
1021 XSETCDR (XCAR (tmp), newlist);
1022 continue; /* Don't do variable write trapping twice. */
1023 }
1024 }
1025 /* Delete this local variable. */
1026 else if (NILP (last))
1027 bset_local_var_alist (b, XCDR (tmp));
1028 else
1029 XSETCDR (last, XCDR (tmp));
1030
1031 if (XSYMBOL (local_var)->trapped_write == SYMBOL_TRAPPED_WRITE)
1032 notify_variable_watchers (local_var, Qnil,
1033 Qmakunbound, Fcurrent_buffer ());
1034 }
1021 } 1035 }
1022 1036
1023 for (i = 0; i < last_per_buffer_idx; ++i) 1037 for (i = 0; i < last_per_buffer_idx; ++i)
@@ -5541,7 +5555,7 @@ file I/O and the behavior of various editing commands.
5541This variable is buffer-local but you cannot set it directly; 5555This variable is buffer-local but you cannot set it directly;
5542use the function `set-buffer-multibyte' to change a buffer's representation. 5556use the function `set-buffer-multibyte' to change a buffer's representation.
5543See also Info node `(elisp)Text Representations'. */); 5557See also Info node `(elisp)Text Representations'. */);
5544 XSYMBOL (intern_c_string ("enable-multibyte-characters"))->constant = 1; 5558 make_symbol_constant (intern_c_string ("enable-multibyte-characters"));
5545 5559
5546 DEFVAR_PER_BUFFER ("buffer-file-coding-system", 5560 DEFVAR_PER_BUFFER ("buffer-file-coding-system",
5547 &BVAR (current_buffer, buffer_file_coding_system), Qnil, 5561 &BVAR (current_buffer, buffer_file_coding_system), Qnil,
diff --git a/src/bytecode.c b/src/bytecode.c
index be39a81c5e9..868c0148d30 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -569,10 +569,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
569 if (SYMBOLP (sym) 569 if (SYMBOLP (sym)
570 && !EQ (val, Qunbound) 570 && !EQ (val, Qunbound)
571 && !XSYMBOL (sym)->redirect 571 && !XSYMBOL (sym)->redirect
572 && !SYMBOL_CONSTANT_P (sym)) 572 && !SYMBOL_TRAPPED_WRITE_P (sym))
573 SET_SYMBOL_VAL (XSYMBOL (sym), val); 573 SET_SYMBOL_VAL (XSYMBOL (sym), val);
574 else 574 else
575 set_internal (sym, val, Qnil, false); 575 set_internal (sym, val, Qnil, SET_INTERNAL_SET);
576 } 576 }
577 NEXT; 577 NEXT;
578 578
diff --git a/src/data.c b/src/data.c
index 61b5da8b5b6..07730d0924f 100644
--- a/src/data.c
+++ b/src/data.c
@@ -1225,7 +1225,7 @@ DEFUN ("set", Fset, Sset, 2, 2, 0,
1225 doc: /* Set SYMBOL's value to NEWVAL, and return NEWVAL. */) 1225 doc: /* Set SYMBOL's value to NEWVAL, and return NEWVAL. */)
1226 (register Lisp_Object symbol, Lisp_Object newval) 1226 (register Lisp_Object symbol, Lisp_Object newval)
1227{ 1227{
1228 set_internal (symbol, newval, Qnil, 0); 1228 set_internal (symbol, newval, Qnil, SET_INTERNAL_SET);
1229 return newval; 1229 return newval;
1230} 1230}
1231 1231
@@ -1233,13 +1233,14 @@ DEFUN ("set", Fset, Sset, 2, 2, 0,
1233 If buffer/frame-locality is an issue, WHERE specifies which context to use. 1233 If buffer/frame-locality is an issue, WHERE specifies which context to use.
1234 (nil stands for the current buffer/frame). 1234 (nil stands for the current buffer/frame).
1235 1235
1236 If BINDFLAG is false, then if this symbol is supposed to become 1236 If BINDFLAG is SET_INTERNAL_SET, then if this symbol is supposed to
1237 local in every buffer where it is set, then we make it local. 1237 become local in every buffer where it is set, then we make it
1238 If BINDFLAG is true, we don't do that. */ 1238 local. If BINDFLAG is SET_INTERNAL_BIND or SET_INTERNAL_UNBIND, we
1239 don't do that. */
1239 1240
1240void 1241void
1241set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where, 1242set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
1242 bool bindflag) 1243 enum Set_Internal_Bind bindflag)
1243{ 1244{
1244 bool voide = EQ (newval, Qunbound); 1245 bool voide = EQ (newval, Qunbound);
1245 struct Lisp_Symbol *sym; 1246 struct Lisp_Symbol *sym;
@@ -1250,18 +1251,31 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
1250 return; */ 1251 return; */
1251 1252
1252 CHECK_SYMBOL (symbol); 1253 CHECK_SYMBOL (symbol);
1253 if (SYMBOL_CONSTANT_P (symbol)) 1254 sym = XSYMBOL (symbol);
1255 switch (sym->trapped_write)
1254 { 1256 {
1257 case SYMBOL_NOWRITE:
1255 if (NILP (Fkeywordp (symbol)) 1258 if (NILP (Fkeywordp (symbol))
1256 || !EQ (newval, Fsymbol_value (symbol))) 1259 || !EQ (newval, Fsymbol_value (symbol)))
1257 xsignal1 (Qsetting_constant, symbol); 1260 xsignal1 (Qsetting_constant, symbol);
1258 else 1261 else
1259 /* Allow setting keywords to their own value. */ 1262 /* Allow setting keywords to their own value. */
1260 return; 1263 return;
1264
1265 case SYMBOL_TRAPPED_WRITE:
1266 notify_variable_watchers (symbol, voide? Qnil : newval,
1267 (bindflag == SET_INTERNAL_BIND? Qlet :
1268 bindflag == SET_INTERNAL_UNBIND? Qunlet :
1269 voide? Qmakunbound : Qset),
1270 where);
1271 /* FALLTHROUGH! */
1272 case SYMBOL_UNTRAPPED_WRITE:
1273 break;
1274
1275 default: emacs_abort ();
1261 } 1276 }
1262 1277
1263 maybe_set_redisplay (symbol); 1278 maybe_set_redisplay (symbol);
1264 sym = XSYMBOL (symbol);
1265 1279
1266 start: 1280 start:
1267 switch (sym->redirect) 1281 switch (sym->redirect)
@@ -1385,6 +1399,111 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
1385 } 1399 }
1386 return; 1400 return;
1387} 1401}
1402
1403static void
1404set_symbol_trapped_write (Lisp_Object symbol, enum symbol_trapped_write trap)
1405{
1406 struct Lisp_Symbol* sym = XSYMBOL (symbol);
1407 if (sym->trapped_write == SYMBOL_NOWRITE)
1408 xsignal1 (Qtrapping_constant, symbol);
1409 else if (sym->redirect == SYMBOL_LOCALIZED
1410 && SYMBOL_BLV (sym)->frame_local)
1411 xsignal1 (Qtrapping_frame_local, symbol);
1412 sym->trapped_write = trap;
1413}
1414
1415static void
1416restore_symbol_trapped_write (Lisp_Object symbol)
1417{
1418 set_symbol_trapped_write (symbol, SYMBOL_TRAPPED_WRITE);
1419}
1420
1421static void
1422harmonize_variable_watchers (Lisp_Object alias, Lisp_Object base_variable)
1423{
1424 if (!EQ (base_variable, alias)
1425 && EQ (base_variable, Findirect_variable (alias)))
1426 set_symbol_trapped_write
1427 (alias, XSYMBOL (base_variable)->trapped_write);
1428}
1429
1430DEFUN ("add-variable-watcher", Fadd_variable_watcher, Sadd_variable_watcher,
1431 2, 2, 0,
1432 doc: /* Cause WATCH-FUNCTION to be called when SYMBOL is set.
1433All writes to aliases of SYMBOL will call WATCH-FUNCTION too. */)
1434 (Lisp_Object symbol, Lisp_Object watch_function)
1435{
1436 symbol = Findirect_variable (symbol);
1437 set_symbol_trapped_write (symbol, SYMBOL_TRAPPED_WRITE);
1438 map_obarray (Vobarray, harmonize_variable_watchers, symbol);
1439
1440 Lisp_Object watchers = Fget (symbol, Qwatchers);
1441 Lisp_Object member = Fmember (watch_function, watchers);
1442 if (NILP (member))
1443 Fput (symbol, Qwatchers, Fcons (watch_function, watchers));
1444 return Qnil;
1445}
1446
1447DEFUN ("remove-variable-watcher", Fremove_variable_watcher, Sremove_variable_watcher,
1448 2, 2, 0,
1449 doc: /* Undo the effect of `add-variable-watcher'.
1450Remove WATCH-FUNCTION from the list of functions to be called when
1451SYMBOL (or its aliases) are set. */)
1452 (Lisp_Object symbol, Lisp_Object watch_function)
1453{
1454 symbol = Findirect_variable (symbol);
1455 Lisp_Object watchers = Fget (symbol, Qwatchers);
1456 watchers = Fdelete (watch_function, watchers);
1457 if (NILP (watchers))
1458 {
1459 set_symbol_trapped_write (symbol, SYMBOL_UNTRAPPED_WRITE);
1460 map_obarray (Vobarray, harmonize_variable_watchers, symbol);
1461 }
1462 Fput (symbol, Qwatchers, watchers);
1463 return Qnil;
1464}
1465
1466void
1467notify_variable_watchers (Lisp_Object symbol,
1468 Lisp_Object newval,
1469 Lisp_Object operation,
1470 Lisp_Object where)
1471{
1472 symbol = Findirect_variable (symbol);
1473
1474 ptrdiff_t count = SPECPDL_INDEX ();
1475 record_unwind_protect (restore_symbol_trapped_write, symbol);
1476 /* Avoid recursion. */
1477 set_symbol_trapped_write (symbol, SYMBOL_UNTRAPPED_WRITE);
1478
1479 if (NILP (where)
1480 && !EQ (operation, Qset_default) && !EQ (operation, Qmakunbound)
1481 && !NILP (Flocal_variable_if_set_p (symbol, Fcurrent_buffer ())))
1482 {
1483 XSETBUFFER (where, current_buffer);
1484 }
1485
1486 if (EQ (operation, Qset_default))
1487 operation = Qset;
1488
1489 for (Lisp_Object watchers = Fget (symbol, Qwatchers);
1490 CONSP (watchers);
1491 watchers = XCDR (watchers))
1492 {
1493 Lisp_Object watcher = XCAR (watchers);
1494 /* Call subr directly to avoid gc. */
1495 if (SUBRP (watcher))
1496 {
1497 Lisp_Object args[] = { symbol, newval, operation, where };
1498 funcall_subr (XSUBR (watcher), ARRAYELTS (args), args);
1499 }
1500 else
1501 CALLN (Ffuncall, watcher, symbol, newval, operation, where);
1502 }
1503
1504 unbind_to (count, Qnil);
1505}
1506
1388 1507
1389/* Access or set a buffer-local symbol's default value. */ 1508/* Access or set a buffer-local symbol's default value. */
1390 1509
@@ -1471,16 +1590,27 @@ for this variable. */)
1471 struct Lisp_Symbol *sym; 1590 struct Lisp_Symbol *sym;
1472 1591
1473 CHECK_SYMBOL (symbol); 1592 CHECK_SYMBOL (symbol);
1474 if (SYMBOL_CONSTANT_P (symbol)) 1593 sym = XSYMBOL (symbol);
1594 switch (sym->trapped_write)
1475 { 1595 {
1596 case SYMBOL_NOWRITE:
1476 if (NILP (Fkeywordp (symbol)) 1597 if (NILP (Fkeywordp (symbol))
1477 || !EQ (value, Fdefault_value (symbol))) 1598 || !EQ (value, Fsymbol_value (symbol)))
1478 xsignal1 (Qsetting_constant, symbol); 1599 xsignal1 (Qsetting_constant, symbol);
1479 else 1600 else
1480 /* Allow setting keywords to their own value. */ 1601 /* Allow setting keywords to their own value. */
1481 return value; 1602 return value;
1603
1604 case SYMBOL_TRAPPED_WRITE:
1605 /* Don't notify here if we're going to call Fset anyway. */
1606 if (sym->redirect != SYMBOL_PLAINVAL)
1607 notify_variable_watchers (symbol, value, Qset_default, Qnil);
1608 /* FALLTHROUGH! */
1609 case SYMBOL_UNTRAPPED_WRITE:
1610 break;
1611
1612 default: emacs_abort ();
1482 } 1613 }
1483 sym = XSYMBOL (symbol);
1484 1614
1485 start: 1615 start:
1486 switch (sym->redirect) 1616 switch (sym->redirect)
@@ -1651,7 +1781,7 @@ The function `default-value' gets the default value and `set-default' sets it.
1651 default: emacs_abort (); 1781 default: emacs_abort ();
1652 } 1782 }
1653 1783
1654 if (sym->constant) 1784 if (SYMBOL_CONSTANT_P (variable))
1655 error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable))); 1785 error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable)));
1656 1786
1657 if (!blv) 1787 if (!blv)
@@ -1726,7 +1856,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */)
1726 default: emacs_abort (); 1856 default: emacs_abort ();
1727 } 1857 }
1728 1858
1729 if (sym->constant) 1859 if (sym->trapped_write == SYMBOL_NOWRITE)
1730 error ("Symbol %s may not be buffer-local", 1860 error ("Symbol %s may not be buffer-local",
1731 SDATA (SYMBOL_NAME (variable))); 1861 SDATA (SYMBOL_NAME (variable)));
1732 1862
@@ -1838,6 +1968,9 @@ From now on the default value will apply in this buffer. Return VARIABLE. */)
1838 default: emacs_abort (); 1968 default: emacs_abort ();
1839 } 1969 }
1840 1970
1971 if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
1972 notify_variable_watchers (variable, Qnil, Qmakunbound, Fcurrent_buffer ());
1973
1841 /* Get rid of this buffer's alist element, if any. */ 1974 /* Get rid of this buffer's alist element, if any. */
1842 XSETSYMBOL (variable, sym); /* Propagate variable indirection. */ 1975 XSETSYMBOL (variable, sym); /* Propagate variable indirection. */
1843 tem = Fassq (variable, BVAR (current_buffer, local_var_alist)); 1976 tem = Fassq (variable, BVAR (current_buffer, local_var_alist));
@@ -1920,7 +2053,7 @@ frame-local bindings). */)
1920 default: emacs_abort (); 2053 default: emacs_abort ();
1921 } 2054 }
1922 2055
1923 if (sym->constant) 2056 if (SYMBOL_TRAPPED_WRITE_P (variable))
1924 error ("Symbol %s may not be frame-local", SDATA (SYMBOL_NAME (variable))); 2057 error ("Symbol %s may not be frame-local", SDATA (SYMBOL_NAME (variable)));
1925 2058
1926 blv = make_blv (sym, forwarded, valcontents); 2059 blv = make_blv (sym, forwarded, valcontents);
@@ -3465,6 +3598,8 @@ syms_of_data (void)
3465 DEFSYM (Qcyclic_variable_indirection, "cyclic-variable-indirection"); 3598 DEFSYM (Qcyclic_variable_indirection, "cyclic-variable-indirection");
3466 DEFSYM (Qvoid_variable, "void-variable"); 3599 DEFSYM (Qvoid_variable, "void-variable");
3467 DEFSYM (Qsetting_constant, "setting-constant"); 3600 DEFSYM (Qsetting_constant, "setting-constant");
3601 DEFSYM (Qtrapping_constant, "trapping-constant");
3602 DEFSYM (Qtrapping_frame_local, "trapping-frame-local");
3468 DEFSYM (Qinvalid_read_syntax, "invalid-read-syntax"); 3603 DEFSYM (Qinvalid_read_syntax, "invalid-read-syntax");
3469 3604
3470 DEFSYM (Qinvalid_function, "invalid-function"); 3605 DEFSYM (Qinvalid_function, "invalid-function");
@@ -3543,6 +3678,10 @@ syms_of_data (void)
3543 PUT_ERROR (Qvoid_variable, error_tail, "Symbol's value as variable is void"); 3678 PUT_ERROR (Qvoid_variable, error_tail, "Symbol's value as variable is void");
3544 PUT_ERROR (Qsetting_constant, error_tail, 3679 PUT_ERROR (Qsetting_constant, error_tail,
3545 "Attempt to set a constant symbol"); 3680 "Attempt to set a constant symbol");
3681 PUT_ERROR (Qtrapping_constant, error_tail,
3682 "Attempt to trap writes to a constant symbol");
3683 PUT_ERROR (Qtrapping_frame_local, error_tail,
3684 "Attempt to trap writes to a frame local variable");
3546 PUT_ERROR (Qinvalid_read_syntax, error_tail, "Invalid read syntax"); 3685 PUT_ERROR (Qinvalid_read_syntax, error_tail, "Invalid read syntax");
3547 PUT_ERROR (Qinvalid_function, error_tail, "Invalid function"); 3686 PUT_ERROR (Qinvalid_function, error_tail, "Invalid function");
3548 PUT_ERROR (Qwrong_number_of_arguments, error_tail, 3687 PUT_ERROR (Qwrong_number_of_arguments, error_tail,
@@ -3721,10 +3860,18 @@ syms_of_data (void)
3721 DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, 3860 DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum,
3722 doc: /* The largest value that is representable in a Lisp integer. */); 3861 doc: /* The largest value that is representable in a Lisp integer. */);
3723 Vmost_positive_fixnum = make_number (MOST_POSITIVE_FIXNUM); 3862 Vmost_positive_fixnum = make_number (MOST_POSITIVE_FIXNUM);
3724 XSYMBOL (intern_c_string ("most-positive-fixnum"))->constant = 1; 3863 make_symbol_constant (intern_c_string ("most-positive-fixnum"));
3725 3864
3726 DEFVAR_LISP ("most-negative-fixnum", Vmost_negative_fixnum, 3865 DEFVAR_LISP ("most-negative-fixnum", Vmost_negative_fixnum,
3727 doc: /* The smallest value that is representable in a Lisp integer. */); 3866 doc: /* The smallest value that is representable in a Lisp integer. */);
3728 Vmost_negative_fixnum = make_number (MOST_NEGATIVE_FIXNUM); 3867 Vmost_negative_fixnum = make_number (MOST_NEGATIVE_FIXNUM);
3729 XSYMBOL (intern_c_string ("most-negative-fixnum"))->constant = 1; 3868 make_symbol_constant (intern_c_string ("most-negative-fixnum"));
3869
3870 DEFSYM (Qwatchers, "watchers");
3871 DEFSYM (Qmakunbound, "makunbound");
3872 DEFSYM (Qunlet, "unlet");
3873 DEFSYM (Qset, "set");
3874 DEFSYM (Qset_default, "set-default");
3875 defsubr (&Sadd_variable_watcher);
3876 defsubr (&Sremove_variable_watcher);
3730} 3877}
diff --git a/src/eval.c b/src/eval.c
index bbc1518be54..724f0018a58 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -593,12 +593,12 @@ The return value is BASE-VARIABLE. */)
593 CHECK_SYMBOL (new_alias); 593 CHECK_SYMBOL (new_alias);
594 CHECK_SYMBOL (base_variable); 594 CHECK_SYMBOL (base_variable);
595 595
596 sym = XSYMBOL (new_alias); 596 if (SYMBOL_CONSTANT_P (new_alias))
597 597 /* Making it an alias effectively changes its value. */
598 if (sym->constant)
599 /* Not sure why, but why not? */
600 error ("Cannot make a constant an alias"); 598 error ("Cannot make a constant an alias");
601 599
600 sym = XSYMBOL (new_alias);
601
602 switch (sym->redirect) 602 switch (sym->redirect)
603 { 603 {
604 case SYMBOL_FORWARDED: 604 case SYMBOL_FORWARDED:
@@ -617,8 +617,8 @@ The return value is BASE-VARIABLE. */)
617 so that old-code that affects n_a before the aliasing is setup 617 so that old-code that affects n_a before the aliasing is setup
618 still works. */ 618 still works. */
619 if (NILP (Fboundp (base_variable))) 619 if (NILP (Fboundp (base_variable)))
620 set_internal (base_variable, find_symbol_value (new_alias), Qnil, 1); 620 set_internal (base_variable, find_symbol_value (new_alias),
621 621 Qnil, SET_INTERNAL_BIND);
622 { 622 {
623 union specbinding *p; 623 union specbinding *p;
624 624
@@ -628,11 +628,14 @@ The return value is BASE-VARIABLE. */)
628 error ("Don't know how to make a let-bound variable an alias"); 628 error ("Don't know how to make a let-bound variable an alias");
629 } 629 }
630 630
631 if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
632 notify_variable_watchers (new_alias, base_variable, Qdefvaralias, Qnil);
633
631 sym->declared_special = 1; 634 sym->declared_special = 1;
632 XSYMBOL (base_variable)->declared_special = 1; 635 XSYMBOL (base_variable)->declared_special = 1;
633 sym->redirect = SYMBOL_VARALIAS; 636 sym->redirect = SYMBOL_VARALIAS;
634 SET_SYMBOL_ALIAS (sym, XSYMBOL (base_variable)); 637 SET_SYMBOL_ALIAS (sym, XSYMBOL (base_variable));
635 sym->constant = SYMBOL_CONSTANT_P (base_variable); 638 sym->trapped_write = XSYMBOL (base_variable)->trapped_write;
636 LOADHIST_ATTACH (new_alias); 639 LOADHIST_ATTACH (new_alias);
637 /* Even if docstring is nil: remove old docstring. */ 640 /* Even if docstring is nil: remove old docstring. */
638 Fput (new_alias, Qvariable_documentation, docstring); 641 Fput (new_alias, Qvariable_documentation, docstring);
@@ -2645,9 +2648,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
2645 Lisp_Object fun, original_fun; 2648 Lisp_Object fun, original_fun;
2646 Lisp_Object funcar; 2649 Lisp_Object funcar;
2647 ptrdiff_t numargs = nargs - 1; 2650 ptrdiff_t numargs = nargs - 1;
2648 Lisp_Object lisp_numargs;
2649 Lisp_Object val; 2651 Lisp_Object val;
2650 Lisp_Object *internal_args;
2651 ptrdiff_t count; 2652 ptrdiff_t count;
2652 2653
2653 QUIT; 2654 QUIT;
@@ -2680,86 +2681,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
2680 fun = indirect_function (fun); 2681 fun = indirect_function (fun);
2681 2682
2682 if (SUBRP (fun)) 2683 if (SUBRP (fun))
2683 { 2684 val = funcall_subr (XSUBR (fun), numargs, args + 1);
2684 if (numargs < XSUBR (fun)->min_args
2685 || (XSUBR (fun)->max_args >= 0 && XSUBR (fun)->max_args < numargs))
2686 {
2687 XSETFASTINT (lisp_numargs, numargs);
2688 xsignal2 (Qwrong_number_of_arguments, original_fun, lisp_numargs);
2689 }
2690
2691 else if (XSUBR (fun)->max_args == UNEVALLED)
2692 xsignal1 (Qinvalid_function, original_fun);
2693
2694 else if (XSUBR (fun)->max_args == MANY)
2695 val = (XSUBR (fun)->function.aMANY) (numargs, args + 1);
2696 else
2697 {
2698 Lisp_Object internal_argbuf[8];
2699 if (XSUBR (fun)->max_args > numargs)
2700 {
2701 eassert (XSUBR (fun)->max_args <= ARRAYELTS (internal_argbuf));
2702 internal_args = internal_argbuf;
2703 memcpy (internal_args, args + 1, numargs * word_size);
2704 memclear (internal_args + numargs,
2705 (XSUBR (fun)->max_args - numargs) * word_size);
2706 }
2707 else
2708 internal_args = args + 1;
2709 switch (XSUBR (fun)->max_args)
2710 {
2711 case 0:
2712 val = (XSUBR (fun)->function.a0 ());
2713 break;
2714 case 1:
2715 val = (XSUBR (fun)->function.a1 (internal_args[0]));
2716 break;
2717 case 2:
2718 val = (XSUBR (fun)->function.a2
2719 (internal_args[0], internal_args[1]));
2720 break;
2721 case 3:
2722 val = (XSUBR (fun)->function.a3
2723 (internal_args[0], internal_args[1], internal_args[2]));
2724 break;
2725 case 4:
2726 val = (XSUBR (fun)->function.a4
2727 (internal_args[0], internal_args[1], internal_args[2],
2728 internal_args[3]));
2729 break;
2730 case 5:
2731 val = (XSUBR (fun)->function.a5
2732 (internal_args[0], internal_args[1], internal_args[2],
2733 internal_args[3], internal_args[4]));
2734 break;
2735 case 6:
2736 val = (XSUBR (fun)->function.a6
2737 (internal_args[0], internal_args[1], internal_args[2],
2738 internal_args[3], internal_args[4], internal_args[5]));
2739 break;
2740 case 7:
2741 val = (XSUBR (fun)->function.a7
2742 (internal_args[0], internal_args[1], internal_args[2],
2743 internal_args[3], internal_args[4], internal_args[5],
2744 internal_args[6]));
2745 break;
2746
2747 case 8:
2748 val = (XSUBR (fun)->function.a8
2749 (internal_args[0], internal_args[1], internal_args[2],
2750 internal_args[3], internal_args[4], internal_args[5],
2751 internal_args[6], internal_args[7]));
2752 break;
2753
2754 default:
2755
2756 /* If a subr takes more than 8 arguments without using MANY
2757 or UNEVALLED, we need to extend this function to support it.
2758 Until this is done, there is no way to call the function. */
2759 emacs_abort ();
2760 }
2761 }
2762 }
2763 else if (COMPILEDP (fun)) 2685 else if (COMPILEDP (fun))
2764 val = funcall_lambda (fun, numargs, args + 1); 2686 val = funcall_lambda (fun, numargs, args + 1);
2765 else 2687 else
@@ -2791,6 +2713,89 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
2791 return val; 2713 return val;
2792} 2714}
2793 2715
2716
2717/* Apply a C subroutine SUBR to the NUMARGS evaluated arguments in ARG_VECTOR
2718 and return the result of evaluation. */
2719
2720Lisp_Object
2721funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args)
2722{
2723 if (numargs < subr->min_args
2724 || (subr->max_args >= 0 && subr->max_args < numargs))
2725 {
2726 Lisp_Object fun;
2727 XSETSUBR (fun, subr);
2728 xsignal2 (Qwrong_number_of_arguments, fun, make_number (numargs));
2729 }
2730
2731 else if (subr->max_args == UNEVALLED)
2732 {
2733 Lisp_Object fun;
2734 XSETSUBR (fun, subr);
2735 xsignal1 (Qinvalid_function, fun);
2736 }
2737
2738 else if (subr->max_args == MANY)
2739 return (subr->function.aMANY) (numargs, args);
2740 else
2741 {
2742 Lisp_Object internal_argbuf[8];
2743 Lisp_Object *internal_args;
2744 if (subr->max_args > numargs)
2745 {
2746 eassert (subr->max_args <= ARRAYELTS (internal_argbuf));
2747 internal_args = internal_argbuf;
2748 memcpy (internal_args, args, numargs * word_size);
2749 memclear (internal_args + numargs,
2750 (subr->max_args - numargs) * word_size);
2751 }
2752 else
2753 internal_args = args;
2754 switch (subr->max_args)
2755 {
2756 case 0:
2757 return (subr->function.a0 ());
2758 case 1:
2759 return (subr->function.a1 (internal_args[0]));
2760 case 2:
2761 return (subr->function.a2
2762 (internal_args[0], internal_args[1]));
2763 case 3:
2764 return (subr->function.a3
2765 (internal_args[0], internal_args[1], internal_args[2]));
2766 case 4:
2767 return (subr->function.a4
2768 (internal_args[0], internal_args[1], internal_args[2],
2769 internal_args[3]));
2770 case 5:
2771 return (subr->function.a5
2772 (internal_args[0], internal_args[1], internal_args[2],
2773 internal_args[3], internal_args[4]));
2774 case 6:
2775 return (subr->function.a6
2776 (internal_args[0], internal_args[1], internal_args[2],
2777 internal_args[3], internal_args[4], internal_args[5]));
2778 case 7:
2779 return (subr->function.a7
2780 (internal_args[0], internal_args[1], internal_args[2],
2781 internal_args[3], internal_args[4], internal_args[5],
2782 internal_args[6]));
2783 case 8:
2784 return (subr->function.a8
2785 (internal_args[0], internal_args[1], internal_args[2],
2786 internal_args[3], internal_args[4], internal_args[5],
2787 internal_args[6], internal_args[7]));
2788
2789 default:
2790
2791 /* If a subr takes more than 8 arguments without using MANY
2792 or UNEVALLED, we need to extend this function to support it.
2793 Until this is done, there is no way to call the function. */
2794 emacs_abort ();
2795 }
2796 }
2797}
2798
2794static Lisp_Object 2799static Lisp_Object
2795apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count) 2800apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count)
2796{ 2801{
@@ -3171,10 +3176,10 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3171 specpdl_ptr->let.symbol = symbol; 3176 specpdl_ptr->let.symbol = symbol;
3172 specpdl_ptr->let.old_value = SYMBOL_VAL (sym); 3177 specpdl_ptr->let.old_value = SYMBOL_VAL (sym);
3173 grow_specpdl (); 3178 grow_specpdl ();
3174 if (!sym->constant) 3179 if (!sym->trapped_write)
3175 SET_SYMBOL_VAL (sym, value); 3180 SET_SYMBOL_VAL (sym, value);
3176 else 3181 else
3177 set_internal (symbol, value, Qnil, 1); 3182 set_internal (symbol, value, Qnil, SET_INTERNAL_BIND);
3178 break; 3183 break;
3179 case SYMBOL_LOCALIZED: 3184 case SYMBOL_LOCALIZED:
3180 if (SYMBOL_BLV (sym)->frame_local) 3185 if (SYMBOL_BLV (sym)->frame_local)
@@ -3214,7 +3219,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
3214 specpdl_ptr->let.kind = SPECPDL_LET; 3219 specpdl_ptr->let.kind = SPECPDL_LET;
3215 3220
3216 grow_specpdl (); 3221 grow_specpdl ();
3217 set_internal (symbol, value, Qnil, 1); 3222 set_internal (symbol, value, Qnil, SET_INTERNAL_BIND);
3218 break; 3223 break;
3219 } 3224 }
3220 default: emacs_abort (); 3225 default: emacs_abort ();
@@ -3341,14 +3346,16 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3341 case SPECPDL_BACKTRACE: 3346 case SPECPDL_BACKTRACE:
3342 break; 3347 break;
3343 case SPECPDL_LET: 3348 case SPECPDL_LET:
3344 { /* If variable has a trivial value (no forwarding), we can 3349 { /* If variable has a trivial value (no forwarding), and
3345 just set it. No need to check for constant symbols here, 3350 isn't trapped, we can just set it. */
3346 since that was already done by specbind. */
3347 Lisp_Object sym = specpdl_symbol (specpdl_ptr); 3351 Lisp_Object sym = specpdl_symbol (specpdl_ptr);
3348 if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL) 3352 if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
3349 { 3353 {
3350 SET_SYMBOL_VAL (XSYMBOL (sym), 3354 if (XSYMBOL (sym)->trapped_write == SYMBOL_UNTRAPPED_WRITE)
3351 specpdl_old_value (specpdl_ptr)); 3355 SET_SYMBOL_VAL (XSYMBOL (sym), specpdl_old_value (specpdl_ptr));
3356 else
3357 set_internal (sym, specpdl_old_value (specpdl_ptr),
3358 Qnil, SET_INTERNAL_UNBIND);
3352 break; 3359 break;
3353 } 3360 }
3354 else 3361 else
@@ -3371,7 +3378,7 @@ unbind_to (ptrdiff_t count, Lisp_Object value)
3371 /* If this was a local binding, reset the value in the appropriate 3378 /* If this was a local binding, reset the value in the appropriate
3372 buffer, but only if that buffer's binding still exists. */ 3379 buffer, but only if that buffer's binding still exists. */
3373 if (!NILP (Flocal_variable_p (symbol, where))) 3380 if (!NILP (Flocal_variable_p (symbol, where)))
3374 set_internal (symbol, old_value, where, 1); 3381 set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND);
3375 } 3382 }
3376 break; 3383 break;
3377 } 3384 }
@@ -3596,7 +3603,7 @@ backtrace_eval_unrewind (int distance)
3596 { 3603 {
3597 set_specpdl_old_value 3604 set_specpdl_old_value
3598 (tmp, Fbuffer_local_value (symbol, where)); 3605 (tmp, Fbuffer_local_value (symbol, where));
3599 set_internal (symbol, old_value, where, 1); 3606 set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND);
3600 } 3607 }
3601 } 3608 }
3602 break; 3609 break;
@@ -3940,6 +3947,7 @@ alist of active lexical bindings. */);
3940 defsubr (&Sset_default_toplevel_value); 3947 defsubr (&Sset_default_toplevel_value);
3941 defsubr (&Sdefvar); 3948 defsubr (&Sdefvar);
3942 defsubr (&Sdefvaralias); 3949 defsubr (&Sdefvaralias);
3950 DEFSYM (Qdefvaralias, "defvaralias");
3943 defsubr (&Sdefconst); 3951 defsubr (&Sdefconst);
3944 defsubr (&Smake_var_non_special); 3952 defsubr (&Smake_var_non_special);
3945 defsubr (&Slet); 3953 defsubr (&Slet);
diff --git a/src/font.c b/src/font.c
index 9fe7c26ea9c..36e71669453 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5415,19 +5415,19 @@ Each element has the form:
5415 [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...] 5415 [NUMERIC-VALUE SYMBOLIC-NAME ALIAS-NAME ...]
5416NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symbols. */); 5416NUMERIC-VALUE is an integer, and SYMBOLIC-NAME and ALIAS-NAME are symbols. */);
5417 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table); 5417 Vfont_weight_table = BUILD_STYLE_TABLE (weight_table);
5418 XSYMBOL (intern_c_string ("font-weight-table"))->constant = 1; 5418 make_symbol_constant (intern_c_string ("font-weight-table"));
5419 5419
5420 DEFVAR_LISP_NOPRO ("font-slant-table", Vfont_slant_table, 5420 DEFVAR_LISP_NOPRO ("font-slant-table", Vfont_slant_table,
5421 doc: /* Vector of font slant symbols vs the corresponding numeric values. 5421 doc: /* Vector of font slant symbols vs the corresponding numeric values.
5422See `font-weight-table' for the format of the vector. */); 5422See `font-weight-table' for the format of the vector. */);
5423 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table); 5423 Vfont_slant_table = BUILD_STYLE_TABLE (slant_table);
5424 XSYMBOL (intern_c_string ("font-slant-table"))->constant = 1; 5424 make_symbol_constant (intern_c_string ("font-slant-table"));
5425 5425
5426 DEFVAR_LISP_NOPRO ("font-width-table", Vfont_width_table, 5426 DEFVAR_LISP_NOPRO ("font-width-table", Vfont_width_table,
5427 doc: /* Alist of font width symbols vs the corresponding numeric values. 5427 doc: /* Alist of font width symbols vs the corresponding numeric values.
5428See `font-weight-table' for the format of the vector. */); 5428See `font-weight-table' for the format of the vector. */);
5429 Vfont_width_table = BUILD_STYLE_TABLE (width_table); 5429 Vfont_width_table = BUILD_STYLE_TABLE (width_table);
5430 XSYMBOL (intern_c_string ("font-width-table"))->constant = 1; 5430 make_symbol_constant (intern_c_string ("font-width-table"));
5431 5431
5432 staticpro (&font_style_table); 5432 staticpro (&font_style_table);
5433 font_style_table = make_uninit_vector (3); 5433 font_style_table = make_uninit_vector (3);
diff --git a/src/lisp.h b/src/lisp.h
index b6c46687b28..94f1152a56e 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -320,7 +320,8 @@ error !;
320#define lisp_h_NILP(x) EQ (x, Qnil) 320#define lisp_h_NILP(x) EQ (x, Qnil)
321#define lisp_h_SET_SYMBOL_VAL(sym, v) \ 321#define lisp_h_SET_SYMBOL_VAL(sym, v) \
322 (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value = (v)) 322 (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value = (v))
323#define lisp_h_SYMBOL_CONSTANT_P(sym) (XSYMBOL (sym)->constant) 323#define lisp_h_SYMBOL_CONSTANT_P(sym) (XSYMBOL (sym)->trapped_write == SYMBOL_NOWRITE)
324#define lisp_h_SYMBOL_TRAPPED_WRITE_P(sym) (XSYMBOL (sym)->trapped_write)
324#define lisp_h_SYMBOL_VAL(sym) \ 325#define lisp_h_SYMBOL_VAL(sym) \
325 (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value) 326 (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value)
326#define lisp_h_SYMBOLP(x) (XTYPE (x) == Lisp_Symbol) 327#define lisp_h_SYMBOLP(x) (XTYPE (x) == Lisp_Symbol)
@@ -375,6 +376,7 @@ error !;
375# define NILP(x) lisp_h_NILP (x) 376# define NILP(x) lisp_h_NILP (x)
376# define SET_SYMBOL_VAL(sym, v) lisp_h_SET_SYMBOL_VAL (sym, v) 377# define SET_SYMBOL_VAL(sym, v) lisp_h_SET_SYMBOL_VAL (sym, v)
377# define SYMBOL_CONSTANT_P(sym) lisp_h_SYMBOL_CONSTANT_P (sym) 378# define SYMBOL_CONSTANT_P(sym) lisp_h_SYMBOL_CONSTANT_P (sym)
379# define SYMBOL_TRAPPED_WRITE_P(sym) lisp_h_SYMBOL_TRAPPED_WRITE_P (sym)
378# define SYMBOL_VAL(sym) lisp_h_SYMBOL_VAL (sym) 380# define SYMBOL_VAL(sym) lisp_h_SYMBOL_VAL (sym)
379# define SYMBOLP(x) lisp_h_SYMBOLP (x) 381# define SYMBOLP(x) lisp_h_SYMBOLP (x)
380# define VECTORLIKEP(x) lisp_h_VECTORLIKEP (x) 382# define VECTORLIKEP(x) lisp_h_VECTORLIKEP (x)
@@ -600,6 +602,9 @@ extern void char_table_set (Lisp_Object, int, Lisp_Object);
600/* Defined in data.c. */ 602/* Defined in data.c. */
601extern _Noreturn Lisp_Object wrong_type_argument (Lisp_Object, Lisp_Object); 603extern _Noreturn Lisp_Object wrong_type_argument (Lisp_Object, Lisp_Object);
602extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object); 604extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object);
605extern void notify_variable_watchers (Lisp_Object symbol, Lisp_Object newval,
606 Lisp_Object operation, Lisp_Object where);
607
603 608
604#ifdef CANNOT_DUMP 609#ifdef CANNOT_DUMP
605enum { might_dump = false }; 610enum { might_dump = false };
@@ -632,6 +637,13 @@ enum symbol_redirect
632 SYMBOL_FORWARDED = 3 637 SYMBOL_FORWARDED = 3
633}; 638};
634 639
640enum symbol_trapped_write
641{
642 SYMBOL_UNTRAPPED_WRITE = 0,
643 SYMBOL_NOWRITE = 1,
644 SYMBOL_TRAPPED_WRITE = 2
645};
646
635struct Lisp_Symbol 647struct Lisp_Symbol
636{ 648{
637 bool_bf gcmarkbit : 1; 649 bool_bf gcmarkbit : 1;
@@ -643,10 +655,10 @@ struct Lisp_Symbol
643 3 : it's a forwarding variable, the value is in `forward'. */ 655 3 : it's a forwarding variable, the value is in `forward'. */
644 ENUM_BF (symbol_redirect) redirect : 3; 656 ENUM_BF (symbol_redirect) redirect : 3;
645 657
646 /* Non-zero means symbol is constant, i.e. changing its value 658 /* 0 : normal case, just set the value
647 should signal an error. If the value is 3, then the var 659 1 : constant, cannot set, e.g. nil, t, :keywords.
648 can be changed, but only by `defconst'. */ 660 2 : trap the write, call watcher functions. */
649 unsigned constant : 2; 661 ENUM_BF (symbol_trapped_write) trapped_write : 2;
650 662
651 /* Interned state of the symbol. This is an enumerator from 663 /* Interned state of the symbol. This is an enumerator from
652 enum symbol_interned. */ 664 enum symbol_interned. */
@@ -1850,9 +1862,20 @@ SYMBOL_INTERNED_IN_INITIAL_OBARRAY_P (Lisp_Object sym)
1850 return XSYMBOL (sym)->interned == SYMBOL_INTERNED_IN_INITIAL_OBARRAY; 1862 return XSYMBOL (sym)->interned == SYMBOL_INTERNED_IN_INITIAL_OBARRAY;
1851} 1863}
1852 1864
1853/* Value is non-zero if symbol is considered a constant, i.e. its 1865/* Value is non-zero if symbol cannot be changed through a simple set,
1854 value cannot be changed (there is an exception for keyword symbols, 1866 i.e. it's a constant (e.g. nil, t, :keywords), or it has some
1855 whose value can be set to the keyword symbol itself). */ 1867 watching functions. */
1868
1869INLINE int
1870(SYMBOL_TRAPPED_WRITE_P) (Lisp_Object sym)
1871{
1872 return lisp_h_SYMBOL_TRAPPED_WRITE_P (sym);
1873}
1874
1875/* Value is non-zero if symbol cannot be changed at all, i.e. it's a
1876 constant (e.g. nil, t, :keywords). Code that actually wants to
1877 write to SYM, should also check whether there are any watching
1878 functions. */
1856 1879
1857INLINE int 1880INLINE int
1858(SYMBOL_CONSTANT_P) (Lisp_Object sym) 1881(SYMBOL_CONSTANT_P) (Lisp_Object sym)
@@ -3286,6 +3309,12 @@ set_symbol_next (Lisp_Object sym, struct Lisp_Symbol *next)
3286 XSYMBOL (sym)->next = next; 3309 XSYMBOL (sym)->next = next;
3287} 3310}
3288 3311
3312INLINE void
3313make_symbol_constant (Lisp_Object sym)
3314{
3315 XSYMBOL (sym)->trapped_write = SYMBOL_NOWRITE;
3316}
3317
3289/* Buffer-local (also frame-local) variable access functions. */ 3318/* Buffer-local (also frame-local) variable access functions. */
3290 3319
3291INLINE int 3320INLINE int
@@ -3394,7 +3423,13 @@ extern _Noreturn void args_out_of_range (Lisp_Object, Lisp_Object);
3394extern _Noreturn void args_out_of_range_3 (Lisp_Object, Lisp_Object, 3423extern _Noreturn void args_out_of_range_3 (Lisp_Object, Lisp_Object,
3395 Lisp_Object); 3424 Lisp_Object);
3396extern Lisp_Object do_symval_forwarding (union Lisp_Fwd *); 3425extern Lisp_Object do_symval_forwarding (union Lisp_Fwd *);
3397extern void set_internal (Lisp_Object, Lisp_Object, Lisp_Object, bool); 3426enum Set_Internal_Bind {
3427 SET_INTERNAL_SET,
3428 SET_INTERNAL_BIND,
3429 SET_INTERNAL_UNBIND
3430};
3431extern void set_internal (Lisp_Object, Lisp_Object, Lisp_Object,
3432 enum Set_Internal_Bind);
3398extern void syms_of_data (void); 3433extern void syms_of_data (void);
3399extern void swap_in_global_binding (struct Lisp_Symbol *); 3434extern void swap_in_global_binding (struct Lisp_Symbol *);
3400 3435
@@ -3877,6 +3912,7 @@ extern _Noreturn void xsignal2 (Lisp_Object, Lisp_Object, Lisp_Object);
3877extern _Noreturn void xsignal3 (Lisp_Object, Lisp_Object, Lisp_Object, 3912extern _Noreturn void xsignal3 (Lisp_Object, Lisp_Object, Lisp_Object,
3878 Lisp_Object); 3913 Lisp_Object);
3879extern _Noreturn void signal_error (const char *, Lisp_Object); 3914extern _Noreturn void signal_error (const char *, Lisp_Object);
3915extern Lisp_Object funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *arg_vector);
3880extern Lisp_Object eval_sub (Lisp_Object form); 3916extern Lisp_Object eval_sub (Lisp_Object form);
3881extern Lisp_Object apply1 (Lisp_Object, Lisp_Object); 3917extern Lisp_Object apply1 (Lisp_Object, Lisp_Object);
3882extern Lisp_Object call0 (Lisp_Object); 3918extern Lisp_Object call0 (Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index eab9b8bea08..14f9393cc47 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3833,7 +3833,7 @@ intern_sym (Lisp_Object sym, Lisp_Object obarray, Lisp_Object index)
3833 3833
3834 if (SREF (SYMBOL_NAME (sym), 0) == ':' && EQ (obarray, initial_obarray)) 3834 if (SREF (SYMBOL_NAME (sym), 0) == ':' && EQ (obarray, initial_obarray))
3835 { 3835 {
3836 XSYMBOL (sym)->constant = 1; 3836 make_symbol_constant (sym);
3837 XSYMBOL (sym)->redirect = SYMBOL_PLAINVAL; 3837 XSYMBOL (sym)->redirect = SYMBOL_PLAINVAL;
3838 SET_SYMBOL_VAL (XSYMBOL (sym), sym); 3838 SET_SYMBOL_VAL (XSYMBOL (sym), sym);
3839 } 3839 }
@@ -4120,12 +4120,12 @@ init_obarray (void)
4120 4120
4121 DEFSYM (Qnil, "nil"); 4121 DEFSYM (Qnil, "nil");
4122 SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil); 4122 SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil);
4123 XSYMBOL (Qnil)->constant = 1; 4123 make_symbol_constant (Qnil);
4124 XSYMBOL (Qnil)->declared_special = true; 4124 XSYMBOL (Qnil)->declared_special = true;
4125 4125
4126 DEFSYM (Qt, "t"); 4126 DEFSYM (Qt, "t");
4127 SET_SYMBOL_VAL (XSYMBOL (Qt), Qt); 4127 SET_SYMBOL_VAL (XSYMBOL (Qt), Qt);
4128 XSYMBOL (Qt)->constant = 1; 4128 make_symbol_constant (Qt);
4129 XSYMBOL (Qt)->declared_special = true; 4129 XSYMBOL (Qt)->declared_special = true;
4130 4130
4131 /* Qt is correct even if CANNOT_DUMP. loadup.el will set to nil at end. */ 4131 /* Qt is correct even if CANNOT_DUMP. loadup.el will set to nil at end. */