mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-12 06:41:13 +02:00
Add support for R6RS/SRFI-30 nested block comments.
Suggested by Andreas Rottmann <a.rottmann@gmx.at>. * libguile/read.c (flush_ws, scm_read_sharp): Add support for R6RS/SRFI-30 block comments. (scm_read_r6rs_block_comment): New function. * test-suite/tests/reader.test (exception:unterminated-block-comment): Adjust to match both block comment styles. ("reading")["R6RS/SRFI-30 block comment", "R6RS/SRFI-30 nested block comment", "R6RS/SRFI-30 block comment syntax overridden"]: New tests. ("exceptions")["R6RS/SRFI-30 unterminated nested block comment"]: New test. * doc/ref/api-evaluation.texi (Block Comments): Mention SRFI-30/R6RS block comments. * doc/ref/srfi-modules.texi (SRFI-30): New node.
This commit is contained in:
parent
cbeb479c6e
commit
620c89651a
4 changed files with 117 additions and 8 deletions
|
@ -230,6 +230,21 @@ Thus a Guile script often starts like this.
|
||||||
More details on Guile scripting can be found in the scripting section
|
More details on Guile scripting can be found in the scripting section
|
||||||
(@pxref{Guile Scripting}).
|
(@pxref{Guile Scripting}).
|
||||||
|
|
||||||
|
@cindex R6RS block comments
|
||||||
|
@cindex SRFI-30 block comments
|
||||||
|
Similarly, Guile (starting from version 2.0) supports nested block
|
||||||
|
comments as specified by R6RS and
|
||||||
|
@url{http://srfi.schemers.org/srfi-30/srfi-30.html, SRFI-30}:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(+ #| this is a #| nested |# block comment |# 2)
|
||||||
|
@result{} 3
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
For backward compatibility, this syntax can be overridden with
|
||||||
|
@code{read-hash-extend} (@pxref{Reader Extensions,
|
||||||
|
@code{read-hash-extend}}).
|
||||||
|
|
||||||
There is one special case where the contents of a comment can actually
|
There is one special case where the contents of a comment can actually
|
||||||
affect the interpretation of code. When a character encoding
|
affect the interpretation of code. When a character encoding
|
||||||
declaration, such as @code{coding: utf-8} appears in one of the first
|
declaration, such as @code{coding: utf-8} appears in one of the first
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@c -*-texinfo-*-
|
@c -*-texinfo-*-
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
@c This is part of the GNU Guile Reference Manual.
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009
|
||||||
@c Free Software Foundation, Inc.
|
@c Free Software Foundation, Inc.
|
||||||
@c See the file guile.texi for copying conditions.
|
@c See the file guile.texi for copying conditions.
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ get the relevant SRFI documents from the SRFI home page
|
||||||
* SRFI-18:: Multithreading support
|
* SRFI-18:: Multithreading support
|
||||||
* SRFI-19:: Time/Date library.
|
* SRFI-19:: Time/Date library.
|
||||||
* SRFI-26:: Specializing parameters
|
* SRFI-26:: Specializing parameters
|
||||||
|
* SRFI-30:: Nested multi-line block comments
|
||||||
* SRFI-31:: A special form `rec' for recursive evaluation
|
* SRFI-31:: A special form `rec' for recursive evaluation
|
||||||
* SRFI-34:: Exception handling.
|
* SRFI-34:: Exception handling.
|
||||||
* SRFI-35:: Conditions.
|
* SRFI-35:: Conditions.
|
||||||
|
@ -2712,6 +2713,13 @@ or similar is typical.
|
||||||
@end example
|
@end example
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@node SRFI-30
|
||||||
|
@subsection SRFI-30 - Nested Multi-line Comments
|
||||||
|
@cindex SRFI-30
|
||||||
|
|
||||||
|
Starting from version 2.0, Guile's @code{read} supports SRFI-30/R6RS
|
||||||
|
nested multi-line comments by default, @ref{Block Comments}.
|
||||||
|
|
||||||
@node SRFI-31
|
@node SRFI-31
|
||||||
@subsection SRFI-31 - A special form `rec' for recursive evaluation
|
@subsection SRFI-31 - A special form `rec' for recursive evaluation
|
||||||
@cindex SRFI-31
|
@cindex SRFI-31
|
||||||
|
|
|
@ -181,8 +181,10 @@ static SCM *scm_read_hash_procedures;
|
||||||
|| ((_chr) == 'd') || ((_chr) == 'l'))
|
|| ((_chr) == 'd') || ((_chr) == 'l'))
|
||||||
|
|
||||||
/* Read an SCSH block comment. */
|
/* Read an SCSH block comment. */
|
||||||
static inline SCM scm_read_scsh_block_comment (int chr, SCM port);
|
static inline SCM scm_read_scsh_block_comment (scm_t_wchar, SCM);
|
||||||
static SCM scm_read_commented_expression (int chr, SCM port);
|
static SCM scm_read_r6rs_block_comment (scm_t_wchar, SCM);
|
||||||
|
static SCM scm_read_commented_expression (scm_t_wchar, SCM);
|
||||||
|
static SCM scm_get_hash_procedure (int);
|
||||||
|
|
||||||
/* Read from PORT until a delimiter (e.g., a whitespace) is read. Return
|
/* Read from PORT until a delimiter (e.g., a whitespace) is read. Return
|
||||||
zero if the whole token fits in BUF, non-zero otherwise. */
|
zero if the whole token fits in BUF, non-zero otherwise. */
|
||||||
|
@ -289,6 +291,13 @@ flush_ws (SCM port, const char *eoferr)
|
||||||
case ';':
|
case ';':
|
||||||
scm_read_commented_expression (c, port);
|
scm_read_commented_expression (c, port);
|
||||||
break;
|
break;
|
||||||
|
case '|':
|
||||||
|
if (scm_is_false (scm_get_hash_procedure (c)))
|
||||||
|
{
|
||||||
|
scm_read_r6rs_block_comment (c, port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
scm_ungetc (c, port);
|
scm_ungetc (c, port);
|
||||||
return '#';
|
return '#';
|
||||||
|
@ -313,7 +322,6 @@ flush_ws (SCM port, const char *eoferr)
|
||||||
|
|
||||||
static SCM scm_read_expression (SCM port);
|
static SCM scm_read_expression (SCM port);
|
||||||
static SCM scm_read_sharp (int chr, SCM port);
|
static SCM scm_read_sharp (int chr, SCM port);
|
||||||
static SCM scm_get_hash_procedure (int c);
|
|
||||||
static SCM recsexpr (SCM obj, long line, int column, SCM filename);
|
static SCM recsexpr (SCM obj, long line, int column, SCM filename);
|
||||||
|
|
||||||
|
|
||||||
|
@ -990,6 +998,45 @@ scm_read_scsh_block_comment (scm_t_wchar chr, SCM port)
|
||||||
return SCM_UNSPECIFIED;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SCM
|
||||||
|
scm_read_r6rs_block_comment (scm_t_wchar chr, SCM port)
|
||||||
|
{
|
||||||
|
/* Unlike SCSH-style block comments, SRFI-30/R6RS block comments may be
|
||||||
|
nested. So care must be taken. */
|
||||||
|
int nesting_level = 1;
|
||||||
|
int opening_seen = 0, closing_seen = 0;
|
||||||
|
|
||||||
|
while (nesting_level > 0)
|
||||||
|
{
|
||||||
|
int c = scm_getc (port);
|
||||||
|
|
||||||
|
if (c == EOF)
|
||||||
|
scm_i_input_error (__FUNCTION__, port,
|
||||||
|
"unterminated `#| ... |#' comment", SCM_EOL);
|
||||||
|
|
||||||
|
if (opening_seen)
|
||||||
|
{
|
||||||
|
if (c == '|')
|
||||||
|
nesting_level++;
|
||||||
|
opening_seen = 0;
|
||||||
|
}
|
||||||
|
else if (closing_seen)
|
||||||
|
{
|
||||||
|
if (c == '#')
|
||||||
|
nesting_level--;
|
||||||
|
closing_seen = 0;
|
||||||
|
}
|
||||||
|
else if (c == '|')
|
||||||
|
closing_seen = 1;
|
||||||
|
else if (c == '#')
|
||||||
|
opening_seen = 1;
|
||||||
|
else
|
||||||
|
opening_seen = closing_seen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCM_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
static SCM
|
static SCM
|
||||||
scm_read_commented_expression (scm_t_wchar chr, SCM port)
|
scm_read_commented_expression (scm_t_wchar chr, SCM port)
|
||||||
{
|
{
|
||||||
|
@ -1173,8 +1220,19 @@ scm_read_sharp (scm_t_wchar chr, SCM port)
|
||||||
default:
|
default:
|
||||||
result = scm_read_sharp_extension (chr, port);
|
result = scm_read_sharp_extension (chr, port);
|
||||||
if (scm_is_eq (result, SCM_UNSPECIFIED))
|
if (scm_is_eq (result, SCM_UNSPECIFIED))
|
||||||
scm_i_input_error (FUNC_NAME, port, "Unknown # object: ~S",
|
{
|
||||||
scm_list_1 (SCM_MAKE_CHAR (chr)));
|
/* To remain compatible with 1.8 and earlier, the following
|
||||||
|
characters have lower precedence than `read-hash-extend'
|
||||||
|
characters. */
|
||||||
|
switch (chr)
|
||||||
|
{
|
||||||
|
case '|':
|
||||||
|
return scm_read_r6rs_block_comment (chr, port);
|
||||||
|
default:
|
||||||
|
scm_i_input_error (FUNC_NAME, port, "Unknown # object: ~S",
|
||||||
|
scm_list_1 (SCM_MAKE_CHAR (chr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;;; reader.test --- Exercise the reader. -*- Scheme -*-
|
;;;; reader.test --- Exercise the reader. -*- Scheme -*-
|
||||||
;;;;
|
;;;;
|
||||||
;;;; Copyright (C) 1999, 2001, 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
|
;;;; Copyright (C) 1999, 2001, 2002, 2003, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||||
;;;; Jim Blandy <jimb@red-bean.com>
|
;;;; Jim Blandy <jimb@red-bean.com>
|
||||||
;;;;
|
;;;;
|
||||||
;;;; This library is free software; you can redistribute it and/or
|
;;;; This library is free software; you can redistribute it and/or
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
(define-module (test-suite reader)
|
(define-module (test-suite reader)
|
||||||
|
:use-module (srfi srfi-1)
|
||||||
:use-module (test-suite lib))
|
:use-module (test-suite lib))
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@
|
||||||
(define exception:unexpected-rparen
|
(define exception:unexpected-rparen
|
||||||
(cons 'read-error "unexpected \")\"$"))
|
(cons 'read-error "unexpected \")\"$"))
|
||||||
(define exception:unterminated-block-comment
|
(define exception:unterminated-block-comment
|
||||||
(cons 'read-error "unterminated `#! ... !#' comment$"))
|
(cons 'read-error "unterminated `#. \\.\\.\\. .#' comment$"))
|
||||||
(define exception:unknown-character-name
|
(define exception:unknown-character-name
|
||||||
(cons 'read-error "unknown character name .*$"))
|
(cons 'read-error "unknown character name .*$"))
|
||||||
(define exception:unknown-sharp-object
|
(define exception:unknown-sharp-object
|
||||||
|
@ -83,6 +84,30 @@
|
||||||
(equal? '(+ 2)
|
(equal? '(+ 2)
|
||||||
(read-string "(+ 2 #! a comment\n!#\n) ")))
|
(read-string "(+ 2 #! a comment\n!#\n) ")))
|
||||||
|
|
||||||
|
(pass-if "R6RS/SRFI-30 block comment"
|
||||||
|
(equal? '(+ 1 2 3)
|
||||||
|
(read-string "(+ 1 #| this is a\ncomment |# 2 3)")))
|
||||||
|
|
||||||
|
(pass-if "R6RS/SRFI-30 nested block comment"
|
||||||
|
(equal? '(a b c)
|
||||||
|
(read-string "(a b c #| d #| e |# f |#)")))
|
||||||
|
|
||||||
|
(pass-if "R6RS/SRFI-30 block comment syntax overridden"
|
||||||
|
;; To be compatible with 1.8 and earlier, we should be able to override
|
||||||
|
;; this syntax.
|
||||||
|
(let ((rhp read-hash-procedures))
|
||||||
|
(dynamic-wind
|
||||||
|
(lambda ()
|
||||||
|
(read-hash-extend #\| (lambda args 'not)))
|
||||||
|
(lambda ()
|
||||||
|
(fold (lambda (x y result)
|
||||||
|
(and result (eq? x y)))
|
||||||
|
#t
|
||||||
|
(read-string "(this is #| a comment)")
|
||||||
|
`(this is not a comment)))
|
||||||
|
(lambda ()
|
||||||
|
(set! read-hash-procedures rhp)))))
|
||||||
|
|
||||||
(pass-if "unprintable symbol"
|
(pass-if "unprintable symbol"
|
||||||
;; The reader tolerates unprintable characters for symbols.
|
;; The reader tolerates unprintable characters for symbols.
|
||||||
(equal? (string->symbol "\001\002\003")
|
(equal? (string->symbol "\001\002\003")
|
||||||
|
@ -131,6 +156,9 @@
|
||||||
(pass-if-exception "unterminated block comment"
|
(pass-if-exception "unterminated block comment"
|
||||||
exception:unterminated-block-comment
|
exception:unterminated-block-comment
|
||||||
(read-string "(+ 1 #! comment\n..."))
|
(read-string "(+ 1 #! comment\n..."))
|
||||||
|
(pass-if-exception "R6RS/SRFI-30 unterminated nested block comment"
|
||||||
|
exception:unterminated-block-comment
|
||||||
|
(read-string "(foo #| bar #| |#)"))
|
||||||
(pass-if-exception "unknown character name"
|
(pass-if-exception "unknown character name"
|
||||||
exception:unknown-character-name
|
exception:unknown-character-name
|
||||||
(read-string "#\\theunknowncharacter"))
|
(read-string "#\\theunknowncharacter"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue