diff options
| author | Teodor Zlatanov | 2009-08-05 09:19:21 +0000 |
|---|---|---|
| committer | Teodor Zlatanov | 2009-08-05 09:19:21 +0000 |
| commit | f19a0f5b11e41baf46ce11fd447744ceb97ef754 (patch) | |
| tree | d770ff782b6b974389b8188b81b898133ddfca51 | |
| parent | 74edaf1f3e6b0ff6669d481162cdd62828997f17 (diff) | |
| download | emacs-f19a0f5b11e41baf46ce11fd447744ceb97ef754.tar.gz emacs-f19a0f5b11e41baf46ce11fd447744ceb97ef754.zip | |
* lread.c (read1, syms_of_lread): Read hashtables back from the
readable format.
* print.c (print_preprocess, print_object): Print hashtables fully
and readably.
(syms_of_print): Provide 'hashtable-print-readable.
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/lread.c | 95 | ||||
| -rw-r--r-- | src/print.c | 66 |
3 files changed, 170 insertions, 0 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index a33144b7a33..0a0973635dd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2009-08-05 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 2 | |||
| 3 | * lread.c (read1, syms_of_lread): Read hashtables back from the | ||
| 4 | readable format. | ||
| 5 | |||
| 6 | * print.c (print_preprocess, print_object): Print hashtables fully | ||
| 7 | and readably. | ||
| 8 | (syms_of_print): Provide 'hashtable-print-readable. | ||
| 9 | |||
| 1 | 2009-08-02 Adrian Robert <Adrian.B.Robert@gmail.com> | 10 | 2009-08-02 Adrian Robert <Adrian.B.Robert@gmail.com> |
| 2 | 11 | ||
| 3 | * nsfont.m (ns_descriptor_to_entity): Handle case when descriptor has | 12 | * nsfont.m (ns_descriptor_to_entity): Handle case when descriptor has |
diff --git a/src/lread.c b/src/lread.c index 0fb93031ad4..193bd6ae668 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -80,6 +80,14 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 80 | extern int errno; | 80 | extern int errno; |
| 81 | #endif | 81 | #endif |
| 82 | 82 | ||
| 83 | /* hash table read constants */ | ||
| 84 | Lisp_Object Qhash_table, Qdata; | ||
| 85 | Lisp_Object Qtest, Qsize; | ||
| 86 | Lisp_Object Qweakness; | ||
| 87 | Lisp_Object Qrehash_size; | ||
| 88 | Lisp_Object Qrehash_threshold; | ||
| 89 | extern Lisp_Object QCtest, QCsize, QCrehash_size, QCrehash_threshold, QCweakness; | ||
| 90 | |||
| 83 | Lisp_Object Qread_char, Qget_file_char, Qstandard_input, Qcurrent_load_list; | 91 | Lisp_Object Qread_char, Qget_file_char, Qstandard_input, Qcurrent_load_list; |
| 84 | Lisp_Object Qvariable_documentation, Vvalues, Vstandard_input, Vafter_load_alist; | 92 | Lisp_Object Qvariable_documentation, Vvalues, Vstandard_input, Vafter_load_alist; |
| 85 | Lisp_Object Qascii_character, Qload, Qload_file_name; | 93 | Lisp_Object Qascii_character, Qload, Qload_file_name; |
| @@ -2346,6 +2354,78 @@ read1 (readcharfun, pch, first_in_list) | |||
| 2346 | 2354 | ||
| 2347 | case '#': | 2355 | case '#': |
| 2348 | c = READCHAR; | 2356 | c = READCHAR; |
| 2357 | if (c == 's') | ||
| 2358 | { | ||
| 2359 | c = READCHAR; | ||
| 2360 | if (c == '(') | ||
| 2361 | { | ||
| 2362 | /* Accept extended format for hashtables (extensible to | ||
| 2363 | other types), e.g. | ||
| 2364 | #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */ | ||
| 2365 | Lisp_Object tmp = read_list (0, readcharfun); | ||
| 2366 | Lisp_Object head = CAR_SAFE (tmp); | ||
| 2367 | Lisp_Object data = Qnil; | ||
| 2368 | Lisp_Object val = Qnil; | ||
| 2369 | /* The size is 2 * number of allowed keywords to | ||
| 2370 | make-hash-table. */ | ||
| 2371 | Lisp_Object params[10]; | ||
| 2372 | Lisp_Object ht; | ||
| 2373 | Lisp_Object key = Qnil; | ||
| 2374 | int param_count = 0; | ||
| 2375 | int i; | ||
| 2376 | |||
| 2377 | if (!EQ (head, Qhash_table)) | ||
| 2378 | error ("Invalid extended read marker at head of #s list " | ||
| 2379 | "(only hash-table allowed)"); | ||
| 2380 | |||
| 2381 | tmp = CDR_SAFE (tmp); | ||
| 2382 | |||
| 2383 | /* This is repetitive but fast and simple. */ | ||
| 2384 | params[param_count] = QCsize; | ||
| 2385 | params[param_count+1] = Fplist_get (tmp, Qsize); | ||
| 2386 | if (!NILP (params[param_count+1])) | ||
| 2387 | param_count+=2; | ||
| 2388 | |||
| 2389 | params[param_count] = QCtest; | ||
| 2390 | params[param_count+1] = Fplist_get (tmp, Qtest); | ||
| 2391 | if (!NILP (params[param_count+1])) | ||
| 2392 | param_count+=2; | ||
| 2393 | |||
| 2394 | params[param_count] = QCweakness; | ||
| 2395 | params[param_count+1] = Fplist_get (tmp, Qweakness); | ||
| 2396 | if (!NILP (params[param_count+1])) | ||
| 2397 | param_count+=2; | ||
| 2398 | |||
| 2399 | params[param_count] = QCrehash_size; | ||
| 2400 | params[param_count+1] = Fplist_get (tmp, Qrehash_size); | ||
| 2401 | if (!NILP (params[param_count+1])) | ||
| 2402 | param_count+=2; | ||
| 2403 | |||
| 2404 | params[param_count] = QCrehash_threshold; | ||
| 2405 | params[param_count+1] = Fplist_get (tmp, Qrehash_threshold); | ||
| 2406 | if (!NILP (params[param_count+1])) | ||
| 2407 | param_count+=2; | ||
| 2408 | |||
| 2409 | /* This is the hashtable data. */ | ||
| 2410 | data = Fplist_get (tmp, Qdata); | ||
| 2411 | |||
| 2412 | /* Now use params to make a new hashtable and fill it. */ | ||
| 2413 | ht = Fmake_hash_table (param_count, params); | ||
| 2414 | |||
| 2415 | while (CONSP (data)) | ||
| 2416 | { | ||
| 2417 | key = XCAR (data); | ||
| 2418 | data = XCDR (data); | ||
| 2419 | if (!CONSP (data)) | ||
| 2420 | error ("Odd number of elements in hashtable data"); | ||
| 2421 | val = XCAR (data); | ||
| 2422 | data = XCDR (data); | ||
| 2423 | Fputhash (key, val, ht); | ||
| 2424 | } | ||
| 2425 | |||
| 2426 | return ht; | ||
| 2427 | } | ||
| 2428 | } | ||
| 2349 | if (c == '^') | 2429 | if (c == '^') |
| 2350 | { | 2430 | { |
| 2351 | c = READCHAR; | 2431 | c = READCHAR; |
| @@ -4448,6 +4528,21 @@ to load. See also `load-dangerous-libraries'. */); | |||
| 4448 | 4528 | ||
| 4449 | Vloads_in_progress = Qnil; | 4529 | Vloads_in_progress = Qnil; |
| 4450 | staticpro (&Vloads_in_progress); | 4530 | staticpro (&Vloads_in_progress); |
| 4531 | |||
| 4532 | Qhash_table = intern ("hash-table"); | ||
| 4533 | staticpro (&Qhash_table); | ||
| 4534 | Qdata = intern ("data"); | ||
| 4535 | staticpro (&Qdata); | ||
| 4536 | Qtest = intern ("test"); | ||
| 4537 | staticpro (&Qtest); | ||
| 4538 | Qsize = intern ("size"); | ||
| 4539 | staticpro (&Qsize); | ||
| 4540 | Qweakness = intern ("weakness"); | ||
| 4541 | staticpro (&Qweakness); | ||
| 4542 | Qrehash_size = intern ("rehash-size"); | ||
| 4543 | staticpro (&Qrehash_size); | ||
| 4544 | Qrehash_threshold = intern ("rehash-threshold"); | ||
| 4545 | staticpro (&Qrehash_threshold); | ||
| 4451 | } | 4546 | } |
| 4452 | 4547 | ||
| 4453 | /* arch-tag: a0d02733-0f96-4844-a659-9fd53c4f414d | 4548 | /* arch-tag: a0d02733-0f96-4844-a659-9fd53c4f414d |
diff --git a/src/print.c b/src/print.c index e78f593c7b5..ce63b63acd3 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -1341,6 +1341,7 @@ print_preprocess (obj) | |||
| 1341 | loop: | 1341 | loop: |
| 1342 | if (STRINGP (obj) || CONSP (obj) || VECTORP (obj) | 1342 | if (STRINGP (obj) || CONSP (obj) || VECTORP (obj) |
| 1343 | || COMPILEDP (obj) || CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) | 1343 | || COMPILEDP (obj) || CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) |
| 1344 | || HASH_TABLE_P (obj) | ||
| 1344 | || (! NILP (Vprint_gensym) | 1345 | || (! NILP (Vprint_gensym) |
| 1345 | && SYMBOLP (obj) | 1346 | && SYMBOLP (obj) |
| 1346 | && !SYMBOL_INTERNED_P (obj))) | 1347 | && !SYMBOL_INTERNED_P (obj))) |
| @@ -1536,6 +1537,7 @@ print_object (obj, printcharfun, escapeflag) | |||
| 1536 | /* Detect circularities and truncate them. */ | 1537 | /* Detect circularities and truncate them. */ |
| 1537 | if (STRINGP (obj) || CONSP (obj) || VECTORP (obj) | 1538 | if (STRINGP (obj) || CONSP (obj) || VECTORP (obj) |
| 1538 | || COMPILEDP (obj) || CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) | 1539 | || COMPILEDP (obj) || CHAR_TABLE_P (obj) || SUB_CHAR_TABLE_P (obj) |
| 1540 | || HASH_TABLE_P (obj) | ||
| 1539 | || (! NILP (Vprint_gensym) | 1541 | || (! NILP (Vprint_gensym) |
| 1540 | && SYMBOLP (obj) | 1542 | && SYMBOLP (obj) |
| 1541 | && !SYMBOL_INTERNED_P (obj))) | 1543 | && !SYMBOL_INTERNED_P (obj))) |
| @@ -2031,6 +2033,7 @@ print_object (obj, printcharfun, escapeflag) | |||
| 2031 | else if (HASH_TABLE_P (obj)) | 2033 | else if (HASH_TABLE_P (obj)) |
| 2032 | { | 2034 | { |
| 2033 | struct Lisp_Hash_Table *h = XHASH_TABLE (obj); | 2035 | struct Lisp_Hash_Table *h = XHASH_TABLE (obj); |
| 2036 | #if 0 | ||
| 2034 | strout ("#<hash-table", -1, -1, printcharfun, 0); | 2037 | strout ("#<hash-table", -1, -1, printcharfun, 0); |
| 2035 | if (SYMBOLP (h->test)) | 2038 | if (SYMBOLP (h->test)) |
| 2036 | { | 2039 | { |
| @@ -2047,6 +2050,67 @@ print_object (obj, printcharfun, escapeflag) | |||
| 2047 | sprintf (buf, " 0x%lx", (unsigned long) h); | 2050 | sprintf (buf, " 0x%lx", (unsigned long) h); |
| 2048 | strout (buf, -1, -1, printcharfun, 0); | 2051 | strout (buf, -1, -1, printcharfun, 0); |
| 2049 | PRINTCHAR ('>'); | 2052 | PRINTCHAR ('>'); |
| 2053 | #endif | ||
| 2054 | /* Implement a readable output, e.g.: | ||
| 2055 | #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */ | ||
| 2056 | /* Always print the size. */ | ||
| 2057 | sprintf (buf, "#s(hash-table size %ld", | ||
| 2058 | (long) XVECTOR (h->next)->size); | ||
| 2059 | strout (buf, -1, -1, printcharfun, 0); | ||
| 2060 | |||
| 2061 | if (!NILP (h->test)) | ||
| 2062 | { | ||
| 2063 | strout (" test ", -1, -1, printcharfun, 0); | ||
| 2064 | print_object (h->test, printcharfun, 0); | ||
| 2065 | } | ||
| 2066 | |||
| 2067 | if (!NILP (h->weak)) | ||
| 2068 | { | ||
| 2069 | strout (" weakness ", -1, -1, printcharfun, 0); | ||
| 2070 | print_object (h->weak, printcharfun, 0); | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | if (!NILP (h->rehash_size)) | ||
| 2074 | { | ||
| 2075 | strout (" rehash-size ", -1, -1, printcharfun, 0); | ||
| 2076 | print_object (h->rehash_size, printcharfun, 0); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | if (!NILP (h->rehash_threshold)) | ||
| 2080 | { | ||
| 2081 | strout (" rehash-threshold ", -1, -1, printcharfun, 0); | ||
| 2082 | print_object (h->rehash_threshold, printcharfun, 0); | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | strout (" data ", -1, -1, printcharfun, 0); | ||
| 2086 | |||
| 2087 | /* Print the data here as a plist. */ | ||
| 2088 | int i; | ||
| 2089 | |||
| 2090 | int real_size = HASH_TABLE_SIZE (h); | ||
| 2091 | int size = real_size; | ||
| 2092 | |||
| 2093 | /* Don't print more elements than the specified maximum. */ | ||
| 2094 | if (NATNUMP (Vprint_length) | ||
| 2095 | && XFASTINT (Vprint_length) < size) | ||
| 2096 | size = XFASTINT (Vprint_length); | ||
| 2097 | |||
| 2098 | PRINTCHAR ('('); | ||
| 2099 | for (i = 0; i < size; i++) | ||
| 2100 | if (!NILP (HASH_HASH (h, i))) | ||
| 2101 | { | ||
| 2102 | if (i) PRINTCHAR (' '); | ||
| 2103 | print_object (HASH_KEY (h, i), printcharfun, 0); | ||
| 2104 | PRINTCHAR (' '); | ||
| 2105 | print_object (HASH_VALUE (h, i), printcharfun, 0); | ||
| 2106 | } | ||
| 2107 | |||
| 2108 | if (size < real_size) | ||
| 2109 | strout (" ...", 4, 4, printcharfun, 0); | ||
| 2110 | |||
| 2111 | PRINTCHAR (')'); | ||
| 2112 | PRINTCHAR (')'); | ||
| 2113 | |||
| 2050 | } | 2114 | } |
| 2051 | else if (BUFFERP (obj)) | 2115 | else if (BUFFERP (obj)) |
| 2052 | { | 2116 | { |
| @@ -2354,6 +2418,8 @@ that represents the number without losing information. */); | |||
| 2354 | Qfloat_output_format = intern ("float-output-format"); | 2418 | Qfloat_output_format = intern ("float-output-format"); |
| 2355 | staticpro (&Qfloat_output_format); | 2419 | staticpro (&Qfloat_output_format); |
| 2356 | 2420 | ||
| 2421 | Fprovide (intern ("hashtable-print-readable"), Qnil); | ||
| 2422 | |||
| 2357 | DEFVAR_LISP ("print-length", &Vprint_length, | 2423 | DEFVAR_LISP ("print-length", &Vprint_length, |
| 2358 | doc: /* Maximum length of list to print before abbreviating. | 2424 | doc: /* Maximum length of list to print before abbreviating. |
| 2359 | A value of nil means no limit. See also `eval-expression-print-length'. */); | 2425 | A value of nil means no limit. See also `eval-expression-print-length'. */); |