Mercurial > hg > xemacs-beta
comparison src/print.c @ 5560:58b38d5b32d0
Implement print-circle, allowing recursive and circular structures to be read.
src/ChangeLog addition:
2011-09-04 Aidan Kehoe <kehoea@parhasard.net>
* alloc.c:
* alloc.c (ALLOC_FROB_BLOCK_LISP_OBJECT_1):
* alloc.c (ALLOC_FROB_BLOCK_LISP_OBJECT):
* alloc.c (cons_print_preprocess):
* alloc.c (vector_print_preprocess):
* alloc.c (vector_nsubst_structures_descend):
* alloc.c (Fmake_symbol):
* alloc.c (UNMARK_symbol):
* alloc.c (sweep_symbols):
* alloc.c (reinit_alloc_objects_early):
* alloc.c (reinit_alloc_early):
* bytecode.c:
* bytecode.c (compiled_function_print_preprocess):
* bytecode.c (compiled_function_nsubst_structures_descend):
* bytecode.c (set_compiled_function_arglist):
* bytecode.c (set_compiled_function_interactive):
* bytecode.c (bytecode_objects_create):
* chartab.c:
* chartab.c (print_preprocess_mapper):
* chartab.c (nsubst_structures_mapper):
* chartab.c (char_table_nsubst_structures_descend):
* chartab.c (chartab_objects_create):
* elhash.c:
* elhash.c (nsubst_structures_map_hash_table):
* elhash.c (hash_table_nsubst_structures_descend):
* elhash.c (print_preprocess_mapper):
* elhash.c (hash_table_print_preprocess):
* elhash.c (inchash_eq):
* elhash.c (hash_table_objects_create):
* elhash.c (syms_of_elhash):
* elhash.h:
* emacs.c (main_1):
* fns.c:
* fns.c (check_eq_nokey):
* fns.c (Fnsubst):
* fns.c (syms_of_fns):
* lisp.h:
* lisp.h (struct Lisp_Symbol):
* lisp.h (IN_OBARRAY):
* lisp.h (struct):
* lisp.h (PRINT_PREPROCESS):
* lread.c (read1):
* lrecord.h:
* lrecord.h (struct lrecord_implementation):
* lrecord.h (DEFINE_DUMPABLE_MODULE_LISP_OBJECT):
* print.c:
* print.c (PRINT_CIRCLE_LIMIT):
* print.c (print_continuous_numbering_changed):
* print.c (print_prepare):
* print.c (print_finish):
* print.c (Fprin1_to_string):
* print.c (print_cons):
* print.c (print_preprocess_inchash_eq):
* print.c (print_preprocess):
* print.c (print_sort_get_numbers):
* print.c (print_sort_compare_ordinals):
* print.c (print_gensym_or_circle):
* print.c (nsubst_structures_descend):
* print.c (nsubst_structures):
* print.c (print_internal):
* print.c (print_symbol):
* print.c (vars_of_print):
* rangetab.c:
* rangetab.c (range_table_print_preprocess):
* rangetab.c (range_table_nsubst_structures_descend):
* rangetab.c (rangetab_objects_create):
* rangetab.c (syms_of_rangetab):
* symbols.c:
* symbols.c (symbol_print_preprocess):
* symbols.c (Fintern):
* symbols.c (Funintern):
* symbols.c (reinit_symbol_objects_early):
* symbols.c (init_symbols_once_early):
* symsinit.h:
Implement print-circle, printing circular structures in a readable
fashion, and treating them appropriately on read. This is by means
of two new object methods, print_preprocess (detecting
circularities), and nsubst_structures_descend (replacing
placeholders with the read objects).
Expose the substitution to Lisp via #'nsubst and its new
:descend-structures keyword.
Store information as to whether symbols are interned in obarray or
not in their header, making checking for keywords and uninterned
symbols (and thus printing) cheaper.
Default print_gensym to t, as Common Lisp does, and as a
more-than-decade old comment suggests.
lisp/ChangeLog addition:
2011-09-04 Aidan Kehoe <kehoea@parhasard.net>
* bytecomp.el (byte-compile-output-file-form):
* bytecomp.el (byte-compile-output-docform):
Bind print-circle, print-continuous-numbering in these functions,
now those variables are available.
* lisp.el (forward-sexp):
* lisp.el (backward-sexp):
Recognise leading #N= as being part of an expression.
tests/ChangeLog addition:
2011-09-04 Aidan Kehoe <kehoea@parhasard.net>
* automated/lisp-reader-tests.el:
* automated/lisp-tests.el (literal-with-uninterned):
* automated/symbol-tests.el (foo):
Test print-circle, for printing (mutually-)recursive and circular
structures.
Bind print-continuous-numbering where appropriate.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Sun, 04 Sep 2011 19:51:35 +0100 |
parents | b9167d522a9a |
children | 56144c8593a8 |
comparison
equal
deleted
inserted
replaced
5559:f3ab0c29c246 | 5560:58b38d5b32d0 |
---|---|
48 #ifdef WIN32_NATIVE | 48 #ifdef WIN32_NATIVE |
49 #include "console-msw.h" | 49 #include "console-msw.h" |
50 #endif | 50 #endif |
51 | 51 |
52 #include "sysfile.h" | 52 #include "sysfile.h" |
53 #include "elhash.h" | |
53 | 54 |
54 #include <float.h> | 55 #include <float.h> |
55 /* Define if not in float.h */ | 56 /* Define if not in float.h */ |
56 #ifndef DBL_DIG | 57 #ifndef DBL_DIG |
57 #define DBL_DIG 16 | 58 #define DBL_DIG 16 |
69 | 70 |
70 /* Avoid actual stack overflow in print. */ | 71 /* Avoid actual stack overflow in print. */ |
71 static int print_depth; | 72 static int print_depth; |
72 | 73 |
73 /* Detect most circularities to print finite output. */ | 74 /* Detect most circularities to print finite output. */ |
74 #define PRINT_CIRCLE 200 | 75 #define PRINT_CIRCLE_LIMIT 200 |
75 static Lisp_Object being_printed[PRINT_CIRCLE]; | 76 static Lisp_Object being_printed[PRINT_CIRCLE_LIMIT]; |
76 | 77 |
77 /* Maximum length of list or vector to print in full; noninteger means | 78 /* Maximum length of list or vector to print in full; noninteger means |
78 effectively infinity */ | 79 effectively infinity */ |
79 | 80 |
80 Lisp_Object Vprint_length; | 81 Lisp_Object Vprint_length; |
94 /* Label to use when making echo-area messages. */ | 95 /* Label to use when making echo-area messages. */ |
95 | 96 |
96 Lisp_Object Vprint_message_label; | 97 Lisp_Object Vprint_message_label; |
97 | 98 |
98 /* Nonzero means print newlines in strings as \n. */ | 99 /* Nonzero means print newlines in strings as \n. */ |
99 | 100 Boolint print_escape_newlines; |
100 int print_escape_newlines; | 101 |
101 int print_readably; | 102 Boolint print_readably; |
102 | 103 |
103 /* Non-nil means print #: before uninterned symbols. | 104 /* Non-zero means print #: before uninterned symbols, and use the #n= and |
104 Neither t nor nil means so that and don't clear Vprint_gensym_alist | 105 #n# syntax for them. */ |
105 on entry to and exit from print functions. */ | 106 Boolint print_gensym; |
106 Lisp_Object Vprint_gensym; | 107 |
107 Lisp_Object Vprint_gensym_alist; | 108 /* Non-zero means print recursive structures using #n= and #n# syntax. */ |
109 Boolint print_circle; | |
110 | |
111 /* Non-zero means keep continuous numbers for #n= and #n# syntax between | |
112 several print functions. Setting or binding the corresponding Lisp | |
113 variable to a non-nil value silently *clears* Vprint_number_table. */ | |
114 Boolint print_continuous_numbering; | |
115 | |
116 /* Vprint_number_table is a hash table mapping objects to their statuses for | |
117 this print operation. The statuses are represented by integers. */ | |
118 Lisp_Object Vprint_number_table; | |
119 | |
120 /* These describe the bit fields of the integers in Vprint_number_table. */ | |
121 enum PRINT_NUMBER_FIELDS { | |
122 /* Lowest four bits describe the number of times a given object has | |
123 been seen, allowing entries to be manipulated cheaply by | |
124 inchash_eq() when encountered. */ | |
125 PRINT_NUMBER_SEEN_MASK = 0xF, | |
126 | |
127 /* The next twenty-five bits give the sequence number for the object, | |
128 corresponding to the order in which print_preprocess encountered the | |
129 objects; as such, it's related to print_number_index. */ | |
130 PRINT_NUMBER_ORDINAL_MASK = 0x1FFFFFF0, | |
131 PRINT_NUMBER_ORDINAL_SHIFT = 4, | |
132 | |
133 /* And the next bit describes whether the object has already been printed | |
134 in this print operation (or in these print operations, if | |
135 print-continuous-numbering is relevant). */ | |
136 PRINT_NUMBER_PRINTED_MASK = 0x20000000, | |
137 }; | |
138 | |
139 /* Reflects the number of repeated or possibly-repeated objects encountered | |
140 by print_preprocess(); reset whenever Vprint_number_table is cleared. */ | |
141 Elemcount print_number_index; | |
108 | 142 |
109 Lisp_Object Qdisplay_error; | 143 Lisp_Object Qdisplay_error; |
110 Lisp_Object Qprint_message_label; | 144 Lisp_Object Qprint_message_label; |
111 | 145 |
112 /* Force immediate output of all printed data. Used for debugging. */ | 146 /* Force immediate output of all printed data. Used for debugging. */ |
538 } | 572 } |
539 | 573 |
540 UNGCPRO; | 574 UNGCPRO; |
541 } | 575 } |
542 | 576 |
543 #define RESET_PRINT_GENSYM do { \ | 577 static int |
544 if (!CONSP (Vprint_gensym)) \ | 578 print_continuous_numbering_changed (Lisp_Object UNUSED (sym), |
545 Vprint_gensym_alist = Qnil; \ | 579 Lisp_Object *val, |
546 } while (0) | 580 Lisp_Object UNUSED (in_object), |
547 | 581 int UNUSED (flags)) |
582 { | |
583 if (!NILP (*val) && !print_continuous_numbering) | |
584 { | |
585 Fclrhash (Vprint_number_table); | |
586 print_number_index = 0; | |
587 } | |
588 | |
589 return 0; | |
590 } | |
591 | |
592 #define RESET_PRINT_NUMBER_TABLE do { \ | |
593 if (!print_continuous_numbering) \ | |
594 { \ | |
595 Fclrhash (Vprint_number_table); \ | |
596 print_number_index = 0; \ | |
597 } \ | |
598 } while (0) | |
599 | |
548 Lisp_Object | 600 Lisp_Object |
549 canonicalize_printcharfun (Lisp_Object printcharfun) | 601 canonicalize_printcharfun (Lisp_Object printcharfun) |
550 { | 602 { |
551 if (NILP (printcharfun)) | 603 if (NILP (printcharfun)) |
552 printcharfun = Vstandard_output; | 604 printcharfun = Vstandard_output; |
563 /* Emacs won't print while GCing, but an external debugger might */ | 615 /* Emacs won't print while GCing, but an external debugger might */ |
564 #ifdef NO_PRINT_DURING_GC | 616 #ifdef NO_PRINT_DURING_GC |
565 if (gc_in_progress) | 617 if (gc_in_progress) |
566 return Qnil; | 618 return Qnil; |
567 #endif | 619 #endif |
568 | 620 |
569 RESET_PRINT_GENSYM; | 621 RESET_PRINT_NUMBER_TABLE; |
570 | 622 |
571 printcharfun = canonicalize_printcharfun (printcharfun); | 623 printcharfun = canonicalize_printcharfun (printcharfun); |
572 | 624 |
573 /* Here we could safely return the canonicalized PRINTCHARFUN. | 625 /* Here we could safely return the canonicalized PRINTCHARFUN. |
574 However, if PRINTCHARFUN is a frame, printing of complex | 626 However, if PRINTCHARFUN is a frame, printing of complex |
610 /* Emacs won't print while GCing, but an external debugger might */ | 662 /* Emacs won't print while GCing, but an external debugger might */ |
611 #ifdef NO_PRINT_DURING_GC | 663 #ifdef NO_PRINT_DURING_GC |
612 if (gc_in_progress) | 664 if (gc_in_progress) |
613 return; | 665 return; |
614 #endif | 666 #endif |
615 | 667 |
616 RESET_PRINT_GENSYM; | 668 RESET_PRINT_NUMBER_TABLE; |
617 | 669 |
618 /* See the comment in print_prepare(). */ | 670 /* See the comment in print_prepare(). */ |
619 if (FRAMEP (frame_kludge)) | 671 if (FRAMEP (frame_kludge)) |
620 { | 672 { |
621 struct frame *f = XFRAME (frame_kludge); | 673 struct frame *f = XFRAME (frame_kludge); |
933 (object, noescape)) | 985 (object, noescape)) |
934 { | 986 { |
935 /* This function can GC */ | 987 /* This function can GC */ |
936 Lisp_Object result = Qnil; | 988 Lisp_Object result = Qnil; |
937 | 989 |
938 RESET_PRINT_GENSYM; | 990 RESET_PRINT_NUMBER_TABLE; |
939 result = prin1_to_string (object, !(EQ(noescape, Qnil))); | 991 result = prin1_to_string (object, !(EQ(noescape, Qnil))); |
940 RESET_PRINT_GENSYM; | 992 RESET_PRINT_NUMBER_TABLE; |
941 | 993 |
942 return result; | 994 return result; |
943 } | 995 } |
944 | 996 |
945 DEFUN ("princ", Fprinc, 1, 2, 0, /* | 997 DEFUN ("princ", Fprinc, 1, 2, 0, /* |
1413 for (tortoise = obj, len = 0; | 1465 for (tortoise = obj, len = 0; |
1414 CONSP (obj); | 1466 CONSP (obj); |
1415 obj = XCDR (obj), len++) | 1467 obj = XCDR (obj), len++) |
1416 { | 1468 { |
1417 if (len > 0) | 1469 if (len > 0) |
1418 write_ascstring (printcharfun, " "); | 1470 { |
1419 if (EQ (obj, tortoise) && len > 0) | 1471 write_ascstring (printcharfun, " "); |
1420 { | 1472 |
1421 if (print_readably) | 1473 /* Note that print_cons is the only object method that does any |
1422 printing_unreadable_object_fmt ("circular list"); | 1474 circularity checking itself, because a cons that is the cdr |
1423 else | 1475 of OBJ is not handed to print_internal in the ordinary course |
1424 write_ascstring (printcharfun, "... <circular list>"); | 1476 of events. All the other possibly-repeated structures always |
1425 break; | 1477 hand sub-objects to print_internal(). */ |
1426 } | 1478 if (print_circle && |
1427 if (len & 1) | 1479 INTP (Fgethash (obj, Vprint_number_table, Qnil))) |
1428 tortoise = XCDR (tortoise); | 1480 { |
1429 if (len > max) | 1481 write_ascstring (printcharfun, ". "); |
1430 { | 1482 print_internal (obj, printcharfun, escapeflag); |
1431 write_ascstring (printcharfun, "..."); | 1483 /* We have printed the list's tail, print_cons() is done. */ |
1432 break; | 1484 break; |
1433 } | 1485 } |
1486 | |
1487 if (EQ (obj, tortoise)) | |
1488 { | |
1489 if (print_readably) | |
1490 { | |
1491 printing_unreadable_object_fmt ("circular list"); | |
1492 } | |
1493 | |
1494 write_ascstring (printcharfun, "... <circular list>"); | |
1495 break; | |
1496 } | |
1497 | |
1498 if (len & 1) | |
1499 { | |
1500 tortoise = XCDR (tortoise); | |
1501 } | |
1502 | |
1503 if (len > max) | |
1504 { | |
1505 write_ascstring (printcharfun, "..."); | |
1506 break; | |
1507 } | |
1508 } | |
1509 | |
1434 print_internal (XCAR (obj), printcharfun, escapeflag); | 1510 print_internal (XCAR (obj), printcharfun, escapeflag); |
1435 } | 1511 } |
1436 } | 1512 } |
1513 | |
1437 if (!LISTP (obj)) | 1514 if (!LISTP (obj)) |
1438 { | 1515 { |
1439 write_ascstring (printcharfun, " . "); | 1516 write_ascstring (printcharfun, " . "); |
1440 print_internal (obj, printcharfun, escapeflag); | 1517 print_internal (obj, printcharfun, escapeflag); |
1441 } | 1518 } |
1519 | |
1442 UNGCPRO; | 1520 UNGCPRO; |
1443 | 1521 |
1444 write_ascstring (printcharfun, ")"); | 1522 write_ascstring (printcharfun, ")"); |
1445 return; | 1523 return; |
1446 } | 1524 } |
1636 } | 1714 } |
1637 write_fmt_string (printcharfun, | 1715 write_fmt_string (printcharfun, |
1638 "#<SERIOUS XEMACS BUG: %s Save your buffers immediately " | 1716 "#<SERIOUS XEMACS BUG: %s Save your buffers immediately " |
1639 "and please report this bug>", buf); | 1717 "and please report this bug>", buf); |
1640 } | 1718 } |
1641 | 1719 |
1720 /* Not static only because of print_preprocess_cons. */ | |
1721 Elemcount print_preprocess_inchash_eq (Lisp_Object, Lisp_Object, Elemcount *); | |
1722 | |
1723 Elemcount | |
1724 print_preprocess_inchash_eq (Lisp_Object obj, Lisp_Object table, | |
1725 Elemcount *seen_object_count) | |
1726 { | |
1727 htentry *hte = inchash_eq (obj, table, 1); | |
1728 Elemcount extracted; | |
1729 | |
1730 /* If the hash table had to be resized, hte is NULL. */ | |
1731 if (hte == NULL) | |
1732 { | |
1733 hte = find_htentry (obj, XHASH_TABLE (table)); | |
1734 } | |
1735 | |
1736 extracted = XINT (hte->value); | |
1737 if (1 == extracted) | |
1738 { | |
1739 *seen_object_count += 1; | |
1740 hte->value | |
1741 = make_int (1 | (*seen_object_count << PRINT_NUMBER_ORDINAL_SHIFT)); | |
1742 } | |
1743 else if ((extracted & PRINT_NUMBER_SEEN_MASK) == PRINT_NUMBER_SEEN_MASK) | |
1744 { | |
1745 /* Avoid the number overflowing the bit field. */ | |
1746 extracted = (extracted & ~PRINT_NUMBER_SEEN_MASK) | 2; | |
1747 hte->value = make_int (extracted); | |
1748 } | |
1749 | |
1750 return extracted & PRINT_NUMBER_SEEN_MASK; | |
1751 } | |
1752 | |
1753 /* Fill in Vprint_number_table according to the structure of OBJ. OBJ itself | |
1754 and all its elements will be added to Vprint_number_table recursively if | |
1755 its type has the print_preprocess method implemented. Objects with the | |
1756 print_preprocess method implemented include cons, vector, compiled | |
1757 function, hash table, char table, range table, and symbol. Symbol is an | |
1758 exceptional type in that it is impossible to construct a recursive symbol | |
1759 structure, but is here for the print-gensym feature. */ | |
1760 | |
1761 void | |
1762 print_preprocess (Lisp_Object object, Lisp_Object print_number_table, | |
1763 Elemcount *seen_object_count) | |
1764 { | |
1765 if (!LRECORDP (object) || !HAS_OBJECT_METH_P (object, print_preprocess)) | |
1766 { | |
1767 return; | |
1768 } | |
1769 | |
1770 if (SYMBOLP (object) && IN_OBARRAY (object)) | |
1771 { | |
1772 /* Handle symbols specially. We do this here rather than in symbols.c | |
1773 because we don't want to have all the other print_preprocess methods | |
1774 worry about print_preprocess_inchash_eq. */ | |
1775 return; | |
1776 } | |
1777 | |
1778 if (print_preprocess_inchash_eq (object, print_number_table, | |
1779 seen_object_count) > 1) | |
1780 { | |
1781 return; | |
1782 } | |
1783 | |
1784 OBJECT_METH (object, print_preprocess, (object, print_number_table, | |
1785 seen_object_count)); | |
1786 } | |
1787 | |
1788 typedef struct { Lisp_Object key; Elemcount count; } preprocess_sort_t; | |
1789 | |
1790 static int | |
1791 print_seen_once (Lisp_Object UNUSED (key), Lisp_Object value, | |
1792 void * UNUSED (extra_arg)) | |
1793 { | |
1794 return 1 == ((XINT (value) & PRINT_NUMBER_SEEN_MASK)); | |
1795 } | |
1796 | |
1797 static int | |
1798 print_nonsymbol_seen_once (Lisp_Object key, Lisp_Object value, | |
1799 void * UNUSED (extra_arg)) | |
1800 { | |
1801 /* print_continuous_numbering is used for symbols, so we don't delete them | |
1802 from the print info hash table. It's less useful for other objects at | |
1803 the moment, though. */ | |
1804 return !SYMBOLP (key) && (1 == ((XINT (value) & PRINT_NUMBER_SEEN_MASK))); | |
1805 } | |
1806 | |
1807 static int | |
1808 print_sort_get_numbers (Lisp_Object key, Lisp_Object value, void *extra_arg) | |
1809 { | |
1810 preprocess_sort_t **preprocess_sort_ptr = (preprocess_sort_t **) extra_arg; | |
1811 preprocess_sort_t *preprocess_sort = *preprocess_sort_ptr; | |
1812 | |
1813 *preprocess_sort_ptr += 1; | |
1814 preprocess_sort->key = key; | |
1815 preprocess_sort->count = XINT (value); | |
1816 | |
1817 return 0; | |
1818 } | |
1819 | |
1820 static int | |
1821 print_sort_compare_ordinals (const void *object1, const void *object2) | |
1822 { | |
1823 Elemcount a = ((preprocess_sort_t *) object1)->count | |
1824 & PRINT_NUMBER_ORDINAL_MASK; | |
1825 Elemcount b = ((preprocess_sort_t *) object2)->count | |
1826 & PRINT_NUMBER_ORDINAL_MASK; | |
1827 | |
1828 return a - b; | |
1829 } | |
1830 | |
1831 enum print_gensym_status | |
1832 { | |
1833 PRINT_GENSYM_DONE, | |
1834 PRINT_GENSYM_PRINT, | |
1835 PRINT_GENSYM_PRINT_AND_CLEANUP_TABLE, | |
1836 }; | |
1837 | |
1838 /* Check for any circular objects or repeated uninterned symbols. | |
1839 | |
1840 If OBJ is a repeated structure (or symbol) and it has been printed | |
1841 already, print it now in the #%d# format, and return 1, to indicate | |
1842 print_internal is done. | |
1843 | |
1844 If OBJ is a repeated structure and it has not yet been printed, print | |
1845 #%d= before the object, mark it as printed, and return zero, to indicate | |
1846 print_internal should continue as usual. | |
1847 | |
1848 If OBJ is not a repeated structure, do nothing, and return zero, to | |
1849 indicate print_internal should continue as usual. */ | |
1850 static enum print_gensym_status | |
1851 print_gensym_or_circle (Lisp_Object obj, Lisp_Object printcharfun) | |
1852 { | |
1853 Lisp_Object seen = Fgethash (obj, Vprint_number_table, Qnil); | |
1854 if (NILP (seen)) | |
1855 { | |
1856 Elemcount old_print_number_index = print_number_index; | |
1857 | |
1858 print_preprocess (obj, Vprint_number_table, &print_number_index); | |
1859 | |
1860 if (old_print_number_index != print_number_index) | |
1861 { | |
1862 Elemcount new_print_number_index, ii; | |
1863 | |
1864 /* We support up to 25 bits' worth of repeated objects, which is | |
1865 33 million or so, far more than we support in, say, a | |
1866 compiled-function constants vector. */ | |
1867 assert (print_number_index <= | |
1868 (PRINT_NUMBER_ORDINAL_MASK >> PRINT_NUMBER_ORDINAL_SHIFT)); | |
1869 | |
1870 /* If any objects have been seen once and once only, remove them | |
1871 from Vprint_number_table. This is a bit of an arbitrary | |
1872 decision; we could keep them around for the sake of | |
1873 print_continuous_numbering, but there's the reasonable worry | |
1874 about Vprint_number_table getting awkwardly large. */ | |
1875 elisp_map_remhash (print_continuous_numbering ? | |
1876 print_nonsymbol_seen_once : print_seen_once, | |
1877 Vprint_number_table, NULL); | |
1878 | |
1879 new_print_number_index | |
1880 = XINT (Fhash_table_count (Vprint_number_table)); | |
1881 | |
1882 if (new_print_number_index != print_number_index | |
1883 && new_print_number_index != old_print_number_index) | |
1884 { | |
1885 preprocess_sort_t *preprocess_sort | |
1886 = alloca_array (preprocess_sort_t, new_print_number_index); | |
1887 preprocess_sort_t *preprocess_sort_ptr = preprocess_sort; | |
1888 | |
1889 /* There are new objects in Vprint_number_table, but their | |
1890 ordinal values don't necessarily represent the order they | |
1891 were seen in, there will be gaps corresponding to the | |
1892 non-symbols that were seen only once. Correct this. */ | |
1893 elisp_maphash_unsafe (print_sort_get_numbers, Vprint_number_table, | |
1894 &preprocess_sort_ptr); | |
1895 | |
1896 qsort (preprocess_sort, new_print_number_index, | |
1897 sizeof (preprocess_sort_t), print_sort_compare_ordinals); | |
1898 | |
1899 for (ii = old_print_number_index; | |
1900 ii < new_print_number_index; | |
1901 ii++) | |
1902 { | |
1903 Fputhash (preprocess_sort[ii].key, | |
1904 make_int ((preprocess_sort[ii].count | |
1905 & ~PRINT_NUMBER_ORDINAL_MASK) | |
1906 | ((ii + 1) | |
1907 << PRINT_NUMBER_ORDINAL_SHIFT)), | |
1908 Vprint_number_table); | |
1909 } | |
1910 } | |
1911 | |
1912 print_number_index = new_print_number_index; | |
1913 | |
1914 /* The new objects may include OBJ; update SEEN to reflect | |
1915 this. */ | |
1916 seen = Fgethash (obj, Vprint_number_table, Qnil); | |
1917 if (INTP (seen)) | |
1918 { | |
1919 goto prefix_this; | |
1920 } | |
1921 } | |
1922 } | |
1923 else | |
1924 { | |
1925 prefix_this: | |
1926 if ((XINT (seen) & PRINT_NUMBER_SEEN_MASK) == 1 | |
1927 && !(print_continuous_numbering && SYMBOLP (obj))) | |
1928 { | |
1929 return PRINT_GENSYM_PRINT_AND_CLEANUP_TABLE; | |
1930 } | |
1931 else if (XINT (seen) & PRINT_NUMBER_PRINTED_MASK) | |
1932 { | |
1933 write_fmt_string (printcharfun, "#%d#", | |
1934 (XINT (seen) & PRINT_NUMBER_ORDINAL_MASK) | |
1935 >> PRINT_NUMBER_ORDINAL_SHIFT); | |
1936 | |
1937 /* We're finished printing this object. */ | |
1938 return PRINT_GENSYM_DONE; | |
1939 } | |
1940 else | |
1941 { | |
1942 write_fmt_string (printcharfun, "#%d=", | |
1943 (XINT (seen) & PRINT_NUMBER_ORDINAL_MASK) | |
1944 >> PRINT_NUMBER_ORDINAL_SHIFT); | |
1945 | |
1946 /* We set PRINT_NUMBER_PRINTED_MASK immediately here, so the | |
1947 object itself is written as #%d# when printing its contents. */ | |
1948 Fputhash (obj, make_int (XINT (seen) | PRINT_NUMBER_PRINTED_MASK), | |
1949 Vprint_number_table); | |
1950 | |
1951 /* This is the first time the object has been seen while | |
1952 printing the recursive object; we still have to go ahead | |
1953 and do the actual print. */ | |
1954 } | |
1955 } | |
1956 | |
1957 return PRINT_GENSYM_PRINT; | |
1958 } | |
1959 | |
1960 Lisp_Object | |
1961 nsubst_structures_descend (Lisp_Object new_, Lisp_Object old, | |
1962 Lisp_Object tree, | |
1963 Lisp_Object number_table, Boolint test_not_unboundp) | |
1964 { | |
1965 Lisp_Object seen; | |
1966 | |
1967 if (!LRECORDP (tree) || !HAS_OBJECT_METH_P (tree, nsubst_structures_descend)) | |
1968 { | |
1969 return tree; | |
1970 } | |
1971 | |
1972 seen = Fgethash (tree, number_table, Qnil); | |
1973 | |
1974 if (INTP (seen)) | |
1975 { | |
1976 if (XINT (seen) & PRINT_NUMBER_PRINTED_MASK) | |
1977 { | |
1978 return tree; | |
1979 } | |
1980 | |
1981 Fputhash (tree, make_int (XINT (seen) | PRINT_NUMBER_PRINTED_MASK), | |
1982 number_table); | |
1983 } | |
1984 | |
1985 OBJECT_METH (tree, nsubst_structures_descend, | |
1986 (new_, old, tree, number_table, test_not_unboundp)); | |
1987 | |
1988 return tree; | |
1989 } | |
1990 | |
1991 /* Descend TREE, replacing the Lisp object OLD each time it is encountered | |
1992 with the Lisp object NEW_. TREE can be recursive or circular, and this is | |
1993 handled correctly. */ | |
1994 Lisp_Object | |
1995 nsubst_structures (Lisp_Object new_, Lisp_Object old, Lisp_Object tree, | |
1996 check_test_func_t check_test, Boolint test_not_unboundp, | |
1997 Lisp_Object UNUSED (test), Lisp_Object UNUSED (key)) | |
1998 { | |
1999 Lisp_Object number_table, result; | |
2000 Elemcount ordinal = 0; | |
2001 struct gcpro gcpro1; | |
2002 | |
2003 if (check_test != check_eq_nokey || !LRECORDP (old)) | |
2004 { | |
2005 signal_error (Qunimplemented, | |
2006 ":descend-structures not yet finished, nsubst", | |
2007 Qunbound); | |
2008 } | |
2009 | |
2010 if (!LRECORDP (tree) || !HAS_OBJECT_METH_P (tree, nsubst_structures_descend)) | |
2011 { | |
2012 return tree; | |
2013 } | |
2014 | |
2015 number_table = make_lisp_hash_table (16, HASH_TABLE_NON_WEAK, Qeq); | |
2016 GCPRO1 (number_table); | |
2017 | |
2018 print_preprocess (tree, number_table, &ordinal); | |
2019 | |
2020 /* This function can GC by means of the hash table test functions, when | |
2021 replacing hash table entries. */ | |
2022 result = nsubst_structures_descend (new_, old, tree, number_table, | |
2023 test_not_unboundp); | |
2024 Fclrhash (number_table); | |
2025 | |
2026 RETURN_UNGCPRO (result); | |
2027 } | |
2028 | |
1642 void | 2029 void |
1643 print_internal (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) | 2030 print_internal (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) |
1644 { | 2031 { |
1645 /* This function can GC */ | 2032 /* This function can GC */ |
1646 int specdepth = 0; | 2033 int specdepth = 0; |
1647 struct gcpro gcpro1, gcpro2; | 2034 struct gcpro gcpro1, gcpro2; |
2035 Boolint cleanup_table = 0; | |
1648 | 2036 |
1649 QUIT; | 2037 QUIT; |
1650 | 2038 |
1651 #ifdef NO_PRINT_DURING_GC | 2039 #ifdef NO_PRINT_DURING_GC |
1652 /* Emacs won't print while GCing, but an external debugger might */ | 2040 /* Emacs won't print while GCing, but an external debugger might */ |
1681 debug_prin1. In that case, we have bound print_depth to 0 anyway. */ | 2069 debug_prin1. In that case, we have bound print_depth to 0 anyway. */ |
1682 if (!inhibit_non_essential_conversion_operations) | 2070 if (!inhibit_non_essential_conversion_operations) |
1683 { | 2071 { |
1684 specdepth = internal_bind_int (&print_depth, print_depth + 1); | 2072 specdepth = internal_bind_int (&print_depth, print_depth + 1); |
1685 | 2073 |
1686 if (print_depth > PRINT_CIRCLE) | 2074 if (print_depth > PRINT_CIRCLE_LIMIT) |
1687 signal_error (Qstack_overflow, | 2075 { |
1688 "Apparently circular structure being printed", Qunbound); | 2076 signal_error (Qstack_overflow, |
2077 "Apparently circular structure being printed", | |
2078 Qunbound); | |
2079 } | |
1689 } | 2080 } |
1690 | 2081 |
1691 switch (XTYPE (obj)) | 2082 switch (XTYPE (obj)) |
1692 { | 2083 { |
1693 case Lisp_Type_Int_Even: | 2084 case Lisp_Type_Int_Even: |
1886 } | 2277 } |
1887 #endif /* not NEW_GC */ | 2278 #endif /* not NEW_GC */ |
1888 } | 2279 } |
1889 } | 2280 } |
1890 | 2281 |
1891 /* Detect circularities and truncate them. | 2282 if (LRECORDP (obj) && |
1892 No need to offer any alternative--this is better than an error. */ | 2283 ((print_circle && HAS_OBJECT_METH_P (obj, print_preprocess)) || |
1893 if (CONSP (obj) || VECTORP (obj) || COMPILED_FUNCTIONP (obj)) | 2284 (print_gensym && SYMBOLP (obj) && !IN_OBARRAY (obj)))) |
1894 { | 2285 { |
2286 enum print_gensym_status status | |
2287 = print_gensym_or_circle (obj, printcharfun); | |
2288 | |
2289 cleanup_table = (PRINT_GENSYM_PRINT_AND_CLEANUP_TABLE == status); | |
2290 | |
2291 if (PRINT_GENSYM_DONE == status) | |
2292 { | |
2293 break; | |
2294 } | |
2295 } | |
2296 else if (!print_circle && | |
2297 /* Could this structure be recursive? */ | |
2298 LRECORDP (obj) | |
2299 && HAS_OBJECT_METH_P (obj, nsubst_structures_descend)) | |
2300 { | |
1895 int i; | 2301 int i; |
1896 for (i = 0; i < print_depth - 1; i++) | 2302 for (i = 0; i < print_depth - 1; i++) |
1897 if (EQ (obj, being_printed[i])) | 2303 if (EQ (obj, being_printed[i])) |
1898 { | 2304 { |
1899 Ascbyte buf[DECIMAL_PRINT_SIZE (long) + 1]; | 2305 Ascbyte buf[DECIMAL_PRINT_SIZE (long) + 1]; |
1935 BADNESS_INTEGER_OBJECT); | 2341 BADNESS_INTEGER_OBJECT); |
1936 break; | 2342 break; |
1937 } | 2343 } |
1938 } | 2344 } |
1939 | 2345 |
2346 if (cleanup_table) | |
2347 { | |
2348 /* If any objects have been seen once and once only, remove them from | |
2349 Vprint_number_table. This is a bit of an arbitrary decision; we | |
2350 could keep them around for the sake of print_continuous_numbering, | |
2351 but there's the reasonable worry about Vprint_number_table getting | |
2352 awkwardly large. */ | |
2353 elisp_map_remhash (print_continuous_numbering ? | |
2354 print_nonsymbol_seen_once : print_seen_once, | |
2355 Vprint_number_table, NULL); | |
2356 | |
2357 } | |
2358 | |
1940 if (!inhibit_non_essential_conversion_operations) | 2359 if (!inhibit_non_essential_conversion_operations) |
1941 unbind_to (specdepth); | 2360 unbind_to (specdepth); |
1942 UNGCPRO; | 2361 UNGCPRO; |
1943 } | 2362 } |
1944 | 2363 |
1966 { | 2385 { |
1967 /* This deals with GC-relocation */ | 2386 /* This deals with GC-relocation */ |
1968 output_string (printcharfun, 0, name, 0, size); | 2387 output_string (printcharfun, 0, name, 0, size); |
1969 return; | 2388 return; |
1970 } | 2389 } |
2390 | |
1971 GCPRO2 (obj, printcharfun); | 2391 GCPRO2 (obj, printcharfun); |
1972 | 2392 |
1973 /* If we print an uninterned symbol as part of a complex object and | 2393 if (print_gensym) |
1974 the flag print-gensym is non-nil, prefix it with #n= to read the | 2394 { |
1975 object back with the #n# reader syntax later if needed. */ | 2395 if (!IN_OBARRAY (obj)) |
1976 if (!NILP (Vprint_gensym) | 2396 { |
1977 /* #### Test whether this produces a noticeable slow-down for | 2397 write_ascstring (printcharfun, "#:"); |
1978 printing when print-gensym is non-nil. */ | 2398 } |
1979 && !EQ (obj, oblookup (Vobarray, | |
1980 XSTRING_DATA (symbol_name (XSYMBOL (obj))), | |
1981 XSTRING_LENGTH (symbol_name (XSYMBOL (obj)))))) | |
1982 { | |
1983 if (print_depth > 1) | |
1984 { | |
1985 Lisp_Object tem = Fassq (obj, Vprint_gensym_alist); | |
1986 if (CONSP (tem)) | |
1987 { | |
1988 write_ascstring (printcharfun, "#"); | |
1989 print_internal (XCDR (tem), printcharfun, escapeflag); | |
1990 write_ascstring (printcharfun, "#"); | |
1991 UNGCPRO; | |
1992 return; | |
1993 } | |
1994 else | |
1995 { | |
1996 if (CONSP (Vprint_gensym_alist)) | |
1997 { | |
1998 /* Vprint_gensym_alist is exposed to Lisp, so we | |
1999 have to be careful. */ | |
2000 CHECK_CONS (XCAR (Vprint_gensym_alist)); | |
2001 CHECK_INT (XCDR (XCAR (Vprint_gensym_alist))); | |
2002 tem = make_int (XINT (XCDR (XCAR (Vprint_gensym_alist))) + 1); | |
2003 } | |
2004 else | |
2005 tem = make_int (1); | |
2006 Vprint_gensym_alist = Fcons (Fcons (obj, tem), Vprint_gensym_alist); | |
2007 | |
2008 write_ascstring (printcharfun, "#"); | |
2009 print_internal (tem, printcharfun, escapeflag); | |
2010 write_ascstring (printcharfun, "="); | |
2011 } | |
2012 } | |
2013 write_ascstring (printcharfun, "#:"); | |
2014 } | 2399 } |
2015 | 2400 |
2016 /* Does it look like an integer or a float? */ | 2401 /* Does it look like an integer or a float? */ |
2017 { | 2402 { |
2018 Ibyte *data = XSTRING_DATA (name); | 2403 Ibyte *data = XSTRING_DATA (name); |
2686 lists of the form (quote object) will be written as the equivalent 'object. | 3071 lists of the form (quote object) will be written as the equivalent 'object. |
2687 Do not SET this variable; bind it instead. | 3072 Do not SET this variable; bind it instead. |
2688 */ ); | 3073 */ ); |
2689 print_readably = 0; | 3074 print_readably = 0; |
2690 | 3075 |
2691 /* #### I think this should default to t. But we'd better wait | 3076 DEFVAR_BOOL ("print-gensym", &print_gensym /* |
2692 until we see that it works out. */ | |
2693 DEFVAR_LISP ("print-gensym", &Vprint_gensym /* | |
2694 If non-nil, then uninterned symbols will be printed specially. | 3077 If non-nil, then uninterned symbols will be printed specially. |
2695 Uninterned symbols are those which are not present in `obarray', that is, | 3078 Uninterned symbols are those which are not present in `obarray', that is, |
2696 those which were made with `make-symbol' or by calling `intern' with a | 3079 those which were made with `make-symbol' or by calling `intern' with a |
2697 second argument. | 3080 second argument. |
2698 | 3081 |
2701 and returning an existing one. Beware: the #: syntax creates a new | 3084 and returning an existing one. Beware: the #: syntax creates a new |
2702 symbol each time it is seen, so if you print an object which contains | 3085 symbol each time it is seen, so if you print an object which contains |
2703 two pointers to the same uninterned symbol, `read' will not duplicate | 3086 two pointers to the same uninterned symbol, `read' will not duplicate |
2704 that structure. | 3087 that structure. |
2705 | 3088 |
2706 If the value of `print-gensym' is a cons cell, then in addition | 3089 If the value of `print-continuous-numbering' is non-nil, the table used by |
2707 refrain from clearing `print-gensym-alist' on entry to and exit from | 3090 `print-gensym' and `print-circle' (which see) will not be reset on entry to |
2708 printing functions, so that the use of #...# and #...= can carry over | 3091 and exit from printing functions, so that the use of #...# and #...= can |
2709 for several separately printed objects. | 3092 carry over for several separately printed objects. |
2710 */ ); | 3093 */ ); |
2711 Vprint_gensym = Qnil; | 3094 print_gensym = 1; |
2712 | 3095 |
2713 DEFVAR_LISP ("print-gensym-alist", &Vprint_gensym_alist /* | 3096 DEFVAR_BOOL ("print-circle", &print_circle /* |
2714 Association list of elements (GENSYM . N) to guide use of #N# and #N=. | 3097 Non-nil means print recursive structures using #N= and #N# syntax. |
2715 In each element, GENSYM is an uninterned symbol that has been associated | 3098 |
2716 with #N= for the specified value of N. | 3099 If nil, XEmacs detects recursive structures and truncates them in an |
2717 */ ); | 3100 unreadable fashion. |
2718 Vprint_gensym_alist = Qnil; | 3101 |
3102 If non-nil, shared substructures anywhere in the structure are printed | |
3103 with `#N=' before the first occurrence (in the order of the print | |
3104 representation) and `#N#' in place of each subsequent occurrence, | |
3105 where N is a positive decimal integer. | |
3106 | |
3107 If the value of `print-continuous-numbering' is non-nil, the table used by | |
3108 `print-gensym' (which see) and `print-circle' will not be reset on entry to | |
3109 and exit from printing functions, so that the use of #...# and #...= can | |
3110 carry over for several separately printed objects. | |
3111 */); | |
3112 print_circle = 0; | |
3113 | |
3114 DEFVAR_BOOL_MAGIC ("print-continuous-numbering", | |
3115 &print_continuous_numbering /* | |
3116 Non-nil means number continuously across print calls, mostly for symbols. | |
3117 This affects the numbers printed for #N= labels and #M# references. | |
3118 See also `print-circle' and `print-gensym'. | |
3119 This variable should not be set with `setq'; bind it with a `let' instead. | |
3120 */ , | |
3121 print_continuous_numbering_changed); | |
3122 print_continuous_numbering = 0; | |
3123 | |
3124 staticpro (&Vprint_number_table); | |
3125 Vprint_number_table = make_lisp_hash_table (16, HASH_TABLE_KEY_WEAK, Qeq); | |
2719 | 3126 |
2720 DEFVAR_LISP ("print-message-label", &Vprint_message_label /* | 3127 DEFVAR_LISP ("print-message-label", &Vprint_message_label /* |
2721 Label for minibuffer messages created with `print'. This should | 3128 Label for minibuffer messages created with `print'. This should |
2722 generally be bound with `let' rather than set. (See `display-message'.) | 3129 generally be bound with `let' rather than set. (See `display-message'.) |
2723 */ ); | 3130 */ ); |