aboutsummaryrefslogtreecommitdiffstats
path: root/src/data.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/data.c')
-rw-r--r--src/data.c213
1 files changed, 189 insertions, 24 deletions
diff --git a/src/data.c b/src/data.c
index 61b5da8b5b6..eee2a52a37a 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,29 @@ 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;
1261 } 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;
1262 1274
1263 maybe_set_redisplay (symbol); 1275 default: emacs_abort ();
1264 sym = XSYMBOL (symbol); 1276 }
1265 1277
1266 start: 1278 start:
1267 switch (sym->redirect) 1279 switch (sym->redirect)
@@ -1385,6 +1397,130 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
1385 } 1397 }
1386 return; 1398 return;
1387} 1399}
1400
1401static void
1402set_symbol_trapped_write (Lisp_Object symbol, enum symbol_trapped_write trap)
1403{
1404 struct Lisp_Symbol* sym = XSYMBOL (symbol);
1405 if (sym->trapped_write == SYMBOL_NOWRITE)
1406 xsignal1 (Qtrapping_constant, symbol);
1407 else if (sym->redirect == SYMBOL_LOCALIZED
1408 && SYMBOL_BLV (sym)->frame_local)
1409 xsignal1 (Qtrapping_frame_local, symbol);
1410 sym->trapped_write = trap;
1411}
1412
1413static void
1414restore_symbol_trapped_write (Lisp_Object symbol)
1415{
1416 set_symbol_trapped_write (symbol, SYMBOL_TRAPPED_WRITE);
1417}
1418
1419static void
1420harmonize_variable_watchers (Lisp_Object alias, Lisp_Object base_variable)
1421{
1422 if (!EQ (base_variable, alias)
1423 && EQ (base_variable, Findirect_variable (alias)))
1424 set_symbol_trapped_write
1425 (alias, XSYMBOL (base_variable)->trapped_write);
1426}
1427
1428DEFUN ("add-variable-watcher", Fadd_variable_watcher, Sadd_variable_watcher,
1429 2, 2, 0,
1430 doc: /* Cause WATCH-FUNCTION to be called when SYMBOL is set.
1431
1432It will be called with 4 arguments: (SYMBOL NEWVAL OPERATION WHERE).
1433SYMBOL is the variable being changed.
1434NEWVAL is the value it will be changed to.
1435OPERATION is a symbol representing the kind of change, one of: `set',
1436`let', `unlet', `makunbound', and `defvaralias'.
1437WHERE is a buffer if the buffer-local value of the variable being
1438changed, nil otherwise.
1439
1440All writes to aliases of SYMBOL will call WATCH-FUNCTION too. */)
1441 (Lisp_Object symbol, Lisp_Object watch_function)
1442{
1443 symbol = Findirect_variable (symbol);
1444 set_symbol_trapped_write (symbol, SYMBOL_TRAPPED_WRITE);
1445 map_obarray (Vobarray, harmonize_variable_watchers, symbol);
1446
1447 Lisp_Object watchers = Fget (symbol, Qwatchers);
1448 Lisp_Object member = Fmember (watch_function, watchers);
1449 if (NILP (member))
1450 Fput (symbol, Qwatchers, Fcons (watch_function, watchers));
1451 return Qnil;
1452}
1453
1454DEFUN ("remove-variable-watcher", Fremove_variable_watcher, Sremove_variable_watcher,
1455 2, 2, 0,
1456 doc: /* Undo the effect of `add-variable-watcher'.
1457Remove WATCH-FUNCTION from the list of functions to be called when
1458SYMBOL (or its aliases) are set. */)
1459 (Lisp_Object symbol, Lisp_Object watch_function)
1460{
1461 symbol = Findirect_variable (symbol);
1462 Lisp_Object watchers = Fget (symbol, Qwatchers);
1463 watchers = Fdelete (watch_function, watchers);
1464 if (NILP (watchers))
1465 {
1466 set_symbol_trapped_write (symbol, SYMBOL_UNTRAPPED_WRITE);
1467 map_obarray (Vobarray, harmonize_variable_watchers, symbol);
1468 }
1469 Fput (symbol, Qwatchers, watchers);
1470 return Qnil;
1471}
1472
1473DEFUN ("get-variable-watchers", Fget_variable_watchers, Sget_variable_watchers,
1474 1, 1, 0,
1475 doc: /* Return a list of SYMBOL's active watchers. */)
1476 (Lisp_Object symbol)
1477{
1478 return (SYMBOL_TRAPPED_WRITE_P (symbol) == SYMBOL_TRAPPED_WRITE)
1479 ? Fget (Findirect_variable (symbol), Qwatchers)
1480 : Qnil;
1481}
1482
1483void
1484notify_variable_watchers (Lisp_Object symbol,
1485 Lisp_Object newval,
1486 Lisp_Object operation,
1487 Lisp_Object where)
1488{
1489 symbol = Findirect_variable (symbol);
1490
1491 ptrdiff_t count = SPECPDL_INDEX ();
1492 record_unwind_protect (restore_symbol_trapped_write, symbol);
1493 /* Avoid recursion. */
1494 set_symbol_trapped_write (symbol, SYMBOL_UNTRAPPED_WRITE);
1495
1496 if (NILP (where)
1497 && !EQ (operation, Qset_default) && !EQ (operation, Qmakunbound)
1498 && !NILP (Flocal_variable_if_set_p (symbol, Fcurrent_buffer ())))
1499 {
1500 XSETBUFFER (where, current_buffer);
1501 }
1502
1503 if (EQ (operation, Qset_default))
1504 operation = Qset;
1505
1506 for (Lisp_Object watchers = Fget (symbol, Qwatchers);
1507 CONSP (watchers);
1508 watchers = XCDR (watchers))
1509 {
1510 Lisp_Object watcher = XCAR (watchers);
1511 /* Call subr directly to avoid gc. */
1512 if (SUBRP (watcher))
1513 {
1514 Lisp_Object args[] = { symbol, newval, operation, where };
1515 funcall_subr (XSUBR (watcher), ARRAYELTS (args), args);
1516 }
1517 else
1518 CALLN (Ffuncall, watcher, symbol, newval, operation, where);
1519 }
1520
1521 unbind_to (count, Qnil);
1522}
1523
1388 1524
1389/* Access or set a buffer-local symbol's default value. */ 1525/* Access or set a buffer-local symbol's default value. */
1390 1526
@@ -1471,16 +1607,27 @@ for this variable. */)
1471 struct Lisp_Symbol *sym; 1607 struct Lisp_Symbol *sym;
1472 1608
1473 CHECK_SYMBOL (symbol); 1609 CHECK_SYMBOL (symbol);
1474 if (SYMBOL_CONSTANT_P (symbol)) 1610 sym = XSYMBOL (symbol);
1611 switch (sym->trapped_write)
1475 { 1612 {
1613 case SYMBOL_NOWRITE:
1476 if (NILP (Fkeywordp (symbol)) 1614 if (NILP (Fkeywordp (symbol))
1477 || !EQ (value, Fdefault_value (symbol))) 1615 || !EQ (value, Fsymbol_value (symbol)))
1478 xsignal1 (Qsetting_constant, symbol); 1616 xsignal1 (Qsetting_constant, symbol);
1479 else 1617 else
1480 /* Allow setting keywords to their own value. */ 1618 /* Allow setting keywords to their own value. */
1481 return value; 1619 return value;
1620
1621 case SYMBOL_TRAPPED_WRITE:
1622 /* Don't notify here if we're going to call Fset anyway. */
1623 if (sym->redirect != SYMBOL_PLAINVAL)
1624 notify_variable_watchers (symbol, value, Qset_default, Qnil);
1625 /* FALLTHROUGH! */
1626 case SYMBOL_UNTRAPPED_WRITE:
1627 break;
1628
1629 default: emacs_abort ();
1482 } 1630 }
1483 sym = XSYMBOL (symbol);
1484 1631
1485 start: 1632 start:
1486 switch (sym->redirect) 1633 switch (sym->redirect)
@@ -1651,7 +1798,7 @@ The function `default-value' gets the default value and `set-default' sets it.
1651 default: emacs_abort (); 1798 default: emacs_abort ();
1652 } 1799 }
1653 1800
1654 if (sym->constant) 1801 if (SYMBOL_CONSTANT_P (variable))
1655 error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable))); 1802 error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable)));
1656 1803
1657 if (!blv) 1804 if (!blv)
@@ -1726,7 +1873,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */)
1726 default: emacs_abort (); 1873 default: emacs_abort ();
1727 } 1874 }
1728 1875
1729 if (sym->constant) 1876 if (sym->trapped_write == SYMBOL_NOWRITE)
1730 error ("Symbol %s may not be buffer-local", 1877 error ("Symbol %s may not be buffer-local",
1731 SDATA (SYMBOL_NAME (variable))); 1878 SDATA (SYMBOL_NAME (variable)));
1732 1879
@@ -1838,6 +1985,9 @@ From now on the default value will apply in this buffer. Return VARIABLE. */)
1838 default: emacs_abort (); 1985 default: emacs_abort ();
1839 } 1986 }
1840 1987
1988 if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
1989 notify_variable_watchers (variable, Qnil, Qmakunbound, Fcurrent_buffer ());
1990
1841 /* Get rid of this buffer's alist element, if any. */ 1991 /* Get rid of this buffer's alist element, if any. */
1842 XSETSYMBOL (variable, sym); /* Propagate variable indirection. */ 1992 XSETSYMBOL (variable, sym); /* Propagate variable indirection. */
1843 tem = Fassq (variable, BVAR (current_buffer, local_var_alist)); 1993 tem = Fassq (variable, BVAR (current_buffer, local_var_alist));
@@ -1920,7 +2070,7 @@ frame-local bindings). */)
1920 default: emacs_abort (); 2070 default: emacs_abort ();
1921 } 2071 }
1922 2072
1923 if (sym->constant) 2073 if (SYMBOL_TRAPPED_WRITE_P (variable))
1924 error ("Symbol %s may not be frame-local", SDATA (SYMBOL_NAME (variable))); 2074 error ("Symbol %s may not be frame-local", SDATA (SYMBOL_NAME (variable)));
1925 2075
1926 blv = make_blv (sym, forwarded, valcontents); 2076 blv = make_blv (sym, forwarded, valcontents);
@@ -3465,6 +3615,8 @@ syms_of_data (void)
3465 DEFSYM (Qcyclic_variable_indirection, "cyclic-variable-indirection"); 3615 DEFSYM (Qcyclic_variable_indirection, "cyclic-variable-indirection");
3466 DEFSYM (Qvoid_variable, "void-variable"); 3616 DEFSYM (Qvoid_variable, "void-variable");
3467 DEFSYM (Qsetting_constant, "setting-constant"); 3617 DEFSYM (Qsetting_constant, "setting-constant");
3618 DEFSYM (Qtrapping_constant, "trapping-constant");
3619 DEFSYM (Qtrapping_frame_local, "trapping-frame-local");
3468 DEFSYM (Qinvalid_read_syntax, "invalid-read-syntax"); 3620 DEFSYM (Qinvalid_read_syntax, "invalid-read-syntax");
3469 3621
3470 DEFSYM (Qinvalid_function, "invalid-function"); 3622 DEFSYM (Qinvalid_function, "invalid-function");
@@ -3543,6 +3695,10 @@ syms_of_data (void)
3543 PUT_ERROR (Qvoid_variable, error_tail, "Symbol's value as variable is void"); 3695 PUT_ERROR (Qvoid_variable, error_tail, "Symbol's value as variable is void");
3544 PUT_ERROR (Qsetting_constant, error_tail, 3696 PUT_ERROR (Qsetting_constant, error_tail,
3545 "Attempt to set a constant symbol"); 3697 "Attempt to set a constant symbol");
3698 PUT_ERROR (Qtrapping_constant, error_tail,
3699 "Attempt to trap writes to a constant symbol");
3700 PUT_ERROR (Qtrapping_frame_local, error_tail,
3701 "Attempt to trap writes to a frame local variable");
3546 PUT_ERROR (Qinvalid_read_syntax, error_tail, "Invalid read syntax"); 3702 PUT_ERROR (Qinvalid_read_syntax, error_tail, "Invalid read syntax");
3547 PUT_ERROR (Qinvalid_function, error_tail, "Invalid function"); 3703 PUT_ERROR (Qinvalid_function, error_tail, "Invalid function");
3548 PUT_ERROR (Qwrong_number_of_arguments, error_tail, 3704 PUT_ERROR (Qwrong_number_of_arguments, error_tail,
@@ -3721,10 +3877,19 @@ syms_of_data (void)
3721 DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, 3877 DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum,
3722 doc: /* The largest value that is representable in a Lisp integer. */); 3878 doc: /* The largest value that is representable in a Lisp integer. */);
3723 Vmost_positive_fixnum = make_number (MOST_POSITIVE_FIXNUM); 3879 Vmost_positive_fixnum = make_number (MOST_POSITIVE_FIXNUM);
3724 XSYMBOL (intern_c_string ("most-positive-fixnum"))->constant = 1; 3880 make_symbol_constant (intern_c_string ("most-positive-fixnum"));
3725 3881
3726 DEFVAR_LISP ("most-negative-fixnum", Vmost_negative_fixnum, 3882 DEFVAR_LISP ("most-negative-fixnum", Vmost_negative_fixnum,
3727 doc: /* The smallest value that is representable in a Lisp integer. */); 3883 doc: /* The smallest value that is representable in a Lisp integer. */);
3728 Vmost_negative_fixnum = make_number (MOST_NEGATIVE_FIXNUM); 3884 Vmost_negative_fixnum = make_number (MOST_NEGATIVE_FIXNUM);
3729 XSYMBOL (intern_c_string ("most-negative-fixnum"))->constant = 1; 3885 make_symbol_constant (intern_c_string ("most-negative-fixnum"));
3886
3887 DEFSYM (Qwatchers, "watchers");
3888 DEFSYM (Qmakunbound, "makunbound");
3889 DEFSYM (Qunlet, "unlet");
3890 DEFSYM (Qset, "set");
3891 DEFSYM (Qset_default, "set-default");
3892 defsubr (&Sadd_variable_watcher);
3893 defsubr (&Sremove_variable_watcher);
3894 defsubr (&Sget_variable_watchers);
3730} 3895}