diff --git a/NEWS b/NEWS index e887ec447..8d2ec86fb 100644 --- a/NEWS +++ b/NEWS @@ -738,6 +738,26 @@ longer installed to the libdir. This change should be transparent to users, but packagers may be interested. + +Changes in 2.0.12 (since 2.0.11): + +[Note: these changes come to 2.2 via 2.0 branch, but 2.0.12 hasn't been +released yet at the time of this writing.] + +* Notable changes + +** The #!r6rs directive now influences read syntax + +The #!r6rs directive now changes the per-port reader options to make +Guile's reader conform more closely to the R6RS syntax. In particular: + +- It makes the reader case sensitive. +- It disables the recognition of keyword syntax in conflict with the + R6RS (and R5RS). +- It enables the `square-brackets', `hungry-eol-escapes' and + `r6rs-hex-escapes' reader options. + + Changes in 2.0.11 (since 2.0.10): diff --git a/libguile/read.c b/libguile/read.c index afad5975a..c724fbbc8 100644 --- a/libguile/read.c +++ b/libguile/read.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-1997, 1999-2001, 2003, 2004, 2006-2012, 2014 +/* Copyright (C) 1995-1997, 1999-2001, 2003, 2004, 2006-2012, 2014, 2015 * Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or @@ -1430,6 +1430,12 @@ static void set_port_square_brackets_p (SCM port, scm_t_read_opts *opts, int value); static void set_port_curly_infix_p (SCM port, scm_t_read_opts *opts, int value); +static void set_port_r6rs_hex_escapes_p (SCM port, scm_t_read_opts *opts, + int value); +static void set_port_hungry_eol_escapes_p (SCM port, scm_t_read_opts *opts, + int value); +static void set_port_keyword_style (SCM port, scm_t_read_opts *opts, + enum t_keyword_style value); static SCM scm_read_shebang (scm_t_wchar chr, SCM port, scm_t_read_opts *opts) @@ -1451,7 +1457,13 @@ scm_read_shebang (scm_t_wchar chr, SCM port, scm_t_read_opts *opts) scm_ungetc (c, port); name[i] = '\0'; if (0 == strcmp ("r6rs", name)) - ; /* Silently ignore */ + { + set_port_case_insensitive_p (port, opts, 0); + set_port_r6rs_hex_escapes_p (port, opts, 1); + set_port_square_brackets_p (port, opts, 1); + set_port_keyword_style (port, opts, KEYWORD_STYLE_HASH_PREFIX); + set_port_hungry_eol_escapes_p (port, opts, 1); + } else if (0 == strcmp ("fold-case", name)) set_port_case_insensitive_p (port, opts, 1); else if (0 == strcmp ("no-fold-case", name)) @@ -2299,6 +2311,30 @@ set_port_curly_infix_p (SCM port, scm_t_read_opts *opts, int value) set_port_read_option (port, READ_OPTION_CURLY_INFIX_P, value); } +/* Set OPTS and PORT's r6rs_hex_escapes_p option according to VALUE. */ +static void +set_port_r6rs_hex_escapes_p (SCM port, scm_t_read_opts *opts, int value) +{ + value = !!value; + opts->r6rs_escapes_p = value; + set_port_read_option (port, READ_OPTION_R6RS_ESCAPES_P, value); +} + +static void +set_port_hungry_eol_escapes_p (SCM port, scm_t_read_opts *opts, int value) +{ + value = !!value; + opts->hungry_eol_escapes_p = value; + set_port_read_option (port, READ_OPTION_HUNGRY_EOL_ESCAPES_P, value); +} + +static void +set_port_keyword_style (SCM port, scm_t_read_opts *opts, enum t_keyword_style value) +{ + opts->keyword_style = value; + set_port_read_option (port, READ_OPTION_KEYWORD_STYLE, value); +} + /* Initialize OPTS based on PORT's read options and the global read options. */ static void diff --git a/test-suite/tests/reader.test b/test-suite/tests/reader.test index 5eb368d9b..a931f0416 100644 --- a/test-suite/tests/reader.test +++ b/test-suite/tests/reader.test @@ -60,6 +60,11 @@ (lambda () (read-options saved-options))))) +(define (read-string-as-list s) + (with-input-from-string s + (lambda () + (unfold eof-object? values (lambda (x) (read)) (read))))) + (with-test-prefix "reading" (pass-if "0" @@ -432,14 +437,42 @@ (equal? '(guile GuiLe gUIle) (with-read-options '(case-insensitive) (lambda () - (with-input-from-string "GUIle #!no-fold-case GuiLe gUIle" - (lambda () - (list (read) (read) (read)))))))) + (read-string-as-list "GUIle #!no-fold-case GuiLe gUIle"))))) (pass-if "case-insensitive" (equal? '(GUIle guile guile) - (with-input-from-string "GUIle #!fold-case GuiLe gUIle" - (lambda () - (list (read) (read) (read))))))) + (read-string-as-list "GUIle #!fold-case GuiLe gUIle"))) + (with-test-prefix "r6rs" + (pass-if-equal "case sensitive" + '(guile GuiLe gUIle) + (with-read-options '(case-insensitive) + (lambda () + (read-string-as-list "GUIle #!r6rs GuiLe gUIle")))) + (pass-if-equal "square brackets" + '((a b c) (foo 42 bar) (x . y)) + (read-string-as-list "(a b c) #!r6rs [foo 42 bar] [x . y]")) + (pass-if-equal "hex string escapes" + '("native\x7fsyntax" + "\0" + "ascii\x7fcontrol" + "U\u0100BMP" + "U\U010402SMP") + (read-string-as-list (string-append "\"native\\x7fsyntax\" " + "#!r6rs " + "\"\\x0;\" " + "\"ascii\\x7f;control\" " + "\"U\\x100;BMP\" " + "\"U\\x10402;SMP\""))) + (with-test-prefix "keyword style" + (pass-if-equal "postfix disabled" + '(#:regular #:postfix postfix: #:regular2) + (with-read-options '(keywords postfix) + (lambda () + (read-string-as-list "#:regular postfix: #!r6rs postfix: #:regular2")))) + (pass-if-equal "prefix disabled" + '(#:regular #:prefix :prefix #:regular2) + (with-read-options '(keywords prefix) + (lambda () + (read-string-as-list "#:regular :prefix #!r6rs :prefix #:regular2"))))))) (with-test-prefix "#;" (for-each