summaryrefslogtreecommitdiff
path: root/libguile/read.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2011-04-11 12:48:06 +0200
committerAndy Wingo <wingo@pobox.com>2011-04-11 12:48:06 +0200
commitd9527cfafdad1046770437a7a59d3745e7243c67 (patch)
treee36c0591b263fdefde42e0811f2f29a88d02f7eb /libguile/read.c
parent15671c6e7fd86160b415b5373b2c1539e23556f3 (diff)
downloadguile-d9527cfafdad1046770437a7a59d3745e7243c67.tar.gz
read-extended-symbol handles backslash better, including r6rs hex escapes
* libguile/read.c (scm_read_extended_symbol): Interpret '\' as an escape character. Due to some historical oddities we have to support '\' before any character, but since we never emitted '\' in front of "normal" characters like 'x' we can interpret "\x..;" to be an R6RS hex escape. * test-suite/tests/reader.test ("#{}#"): Add tests.
Diffstat (limited to 'libguile/read.c')
-rw-r--r--libguile/read.c55
1 files changed, 47 insertions, 8 deletions
diff --git a/libguile/read.c b/libguile/read.c
index a05a86d40..4b6828b8a 100644
--- a/libguile/read.c
+++ b/libguile/read.c
@@ -1230,7 +1230,7 @@ scm_read_extended_symbol (scm_t_wchar chr, SCM port)
#{This is all a symbol name}#
So here, CHR is expected to be `{'. */
- int saw_brace = 0, finished = 0;
+ int saw_brace = 0;
size_t len = 0;
SCM buf = scm_i_make_string (1024, NULL, 0);
@@ -1242,20 +1242,57 @@ scm_read_extended_symbol (scm_t_wchar chr, SCM port)
{
if (chr == '#')
{
- finished = 1;
break;
}
else
{
saw_brace = 0;
scm_i_string_set_x (buf, len++, '}');
- scm_i_string_set_x (buf, len++, chr);
}
}
- else if (chr == '}')
+
+ if (chr == '}')
saw_brace = 1;
+ else if (chr == '\\')
+ {
+ /* It used to be that print.c would print extended-read-syntax
+ symbols with backslashes before "non-standard" chars, but
+ this routine wouldn't do anything with those escapes.
+ Bummer. What we've done is to change print.c to output
+ R6RS hex escapes for those characters, relying on the fact
+ that the extended read syntax would never put a `\' before
+ an `x'. For now, we just ignore other instances of
+ backslash in the string. */
+ switch ((chr = scm_getc (port)))
+ {
+ case EOF:
+ goto done;
+ case 'x':
+ {
+ scm_t_wchar c;
+
+ SCM_READ_HEX_ESCAPE (10, ';');
+ scm_i_string_set_x (buf, len++, c);
+ break;
+
+ str_eof:
+ chr = EOF;
+ goto done;
+
+ bad_escaped:
+ scm_i_string_stop_writing ();
+ scm_i_input_error ("scm_read_extended_symbol", port,
+ "illegal character in escape sequence: ~S",
+ scm_list_1 (SCM_MAKE_CHAR (c)));
+ break;
+ }
+ default:
+ scm_i_string_set_x (buf, len++, chr);
+ break;
+ }
+ }
else
- scm_i_string_set_x (buf, len++, chr);
+ scm_i_string_set_x (buf, len++, chr);
if (len >= scm_i_string_length (buf) - 2)
{
@@ -1267,11 +1304,13 @@ scm_read_extended_symbol (scm_t_wchar chr, SCM port)
len = 0;
buf = scm_i_string_start_writing (buf);
}
-
- if (finished)
- break;
}
+
+ done:
scm_i_string_stop_writing ();
+ if (chr == EOF)
+ scm_i_input_error ("scm_read_extended_symbol", port,
+ "end of file while reading symbol", SCM_EOL);
return (scm_string_to_symbol (scm_c_substring (buf, 0, len)));
}