diff src/chartab.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 6506fcb40fcf
children 309e5631e4c8
line wrap: on
line diff
--- a/src/chartab.c	Sun Aug 28 10:34:54 2011 +0100
+++ b/src/chartab.c	Sun Sep 04 19:51:35 2011 +0100
@@ -94,6 +94,122 @@
 /*                         Char Table object                            */
 /************************************************************************/
 
+static int
+print_preprocess_mapper (struct chartab_range * UNUSED (range),
+                         Lisp_Object UNUSED (table), Lisp_Object val,
+                         void *extra_arg)
+{
+  print_preprocess (val, ((preprocess_info_t *) extra_arg)->table,
+                    ((preprocess_info_t *) extra_arg)->count);
+  return 0;
+}
+
+static void
+char_table_print_preprocess (Lisp_Object object, Lisp_Object print_number_table,
+                             Elemcount *seen_object_count)
+{
+  struct chartab_range ctr = { CHARTAB_RANGE_ALL, 0, Qnil, 0 };
+  preprocess_info_t preprocess_info = { print_number_table, seen_object_count };
+  map_char_table (object, &ctr, print_preprocess_mapper, &preprocess_info);
+}
+
+static void decode_char_table_range (Lisp_Object range,
+                                     struct chartab_range *outrange);
+
+static int
+nsubst_structures_mapper (struct chartab_range * range, Lisp_Object table,
+                          Lisp_Object value, void *extra_arg)
+{
+  Lisp_Object number_table
+    = ((nsubst_structures_info_t *) extra_arg)->number_table;
+  Lisp_Object new_ = ((nsubst_structures_info_t *) extra_arg)->new_;
+  Lisp_Object old = ((nsubst_structures_info_t *) extra_arg)->old;
+  Boolint test_not_unboundp
+    = ((nsubst_structures_info_t *) extra_arg)->test_not_unboundp;
+  struct chartab_range changed = { range->type, range->ch, range->charset,
+                                   range->row };
+
+  switch (range->type)
+    {
+    case CHARTAB_RANGE_ALL:
+      {
+        if (EQ (old, Qt) == test_not_unboundp)
+          {
+            decode_char_table_range (new_, &changed);
+
+            put_char_table (table, range, Qunbound);
+            put_char_table (table, &changed, value);
+          }
+        break;
+      }
+    case CHARTAB_RANGE_CHARSET:
+      {
+        if (EQ (old, range->charset) == test_not_unboundp)
+          {
+            CHECK_CHARSET (new_);
+            changed.charset = new_;
+
+            put_char_table (table, range, Qunbound);
+            put_char_table (table, &changed, value);
+          }
+        else assert (!HAS_OBJECT_METH_P (range->charset,
+                                         nsubst_structures_descend));
+        break;
+      }
+    case CHARTAB_RANGE_ROW:
+      {
+        if (EQ (old, make_int (range->row)) == test_not_unboundp)
+          {
+            CHECK_INT (new_);
+            changed.row = XINT (new_);
+
+            put_char_table (table, range, Qunbound);
+            put_char_table (table, &changed, value);
+          }
+        break;
+      }
+    case CHARTAB_RANGE_CHAR:
+      {
+        if (EQ (old, make_char (range->ch)) == test_not_unboundp)
+          {
+            CHECK_CHAR (new_);
+            changed.ch = XCHAR (new_);
+
+            put_char_table (table, range, Qunbound);
+            put_char_table (table, &changed, value);
+          }
+        break;
+      }
+    }
+
+  if (EQ (old, value) == test_not_unboundp)
+    {
+      put_char_table (table, &changed, new_);
+    }
+  else if (LRECORDP (value) &&
+           HAS_OBJECT_METH_P (value, nsubst_structures_descend))
+    {
+      nsubst_structures_descend (new_, old, value, number_table,
+                                 test_not_unboundp);
+    }
+
+  return 0;
+}
+
+static void
+char_table_nsubst_structures_descend (Lisp_Object new_, Lisp_Object old,
+                                      Lisp_Object object,
+                                      Lisp_Object number_table,
+                                      Boolint test_not_unboundp)
+{
+  struct chartab_range ctr = { CHARTAB_RANGE_ALL, 0, Qnil, 0 };
+  nsubst_structures_info_t nsubst_structures_info
+    = { number_table, new_, old, object, test_not_unboundp };
+
+  map_char_table (object, &ctr, nsubst_structures_mapper,
+                  &nsubst_structures_info);
+}
+
 #ifdef MULE
 
 static Lisp_Object
@@ -1890,6 +2006,13 @@
 
 
 void
+chartab_objects_create (void)
+{
+  OBJECT_HAS_METHOD (char_table, print_preprocess);
+  OBJECT_HAS_METHOD (char_table, nsubst_structures_descend);
+}
+
+void
 syms_of_chartab (void)
 {
   INIT_LISP_OBJECT (char_table);