~ chicken-core (chicken-5) 55ad083b47dc281ed31ce218433d847cc6eeba59


commit 55ad083b47dc281ed31ce218433d847cc6eeba59
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Wed Aug 18 05:43:31 2010 -0400
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Wed Aug 18 05:43:31 2010 -0400

    generalized symbol escape syntax

diff --git a/library.scm b/library.scm
index ae11f74b..0025ba58 100644
--- a/library.scm
+++ b/library.scm
@@ -2382,24 +2382,37 @@ EOF
 	    (r-token) )
 	  
 	  (define (r-symbol)
-	    (let ((s (resolve-symbol
-		      (if (char=? (##sys#peek-char-0 port) #\|)
-			  (r-xtoken)
-			  (r-token) ) ) ) )
+	    (let ((s (resolve-symbol (r-xtoken))))
 	      (info 'symbol-info s (##sys#port-line port)) ) )
 
 	  (define (r-xtoken)
-	    (if (char=? #\| (read-unreserved-char-0 port))
-		(let loop ((c (##sys#read-char-0 port)) (lst '()))
-		  (cond ((eof-object? c)
-			 (##sys#read-error port "unexpected end of `| ... |' symbol"))
-			((char=? c #\\)
-			 (let ((c (##sys#read-char-0 port)))
-			   (loop (##sys#read-char-0 port) (cons c lst)) ) )
-			((char=? c #\|)
-			 (##sys#reverse-list->string lst) )
-			(else (loop (##sys#read-char-0 port) (cons c lst))) ) )
-		(##sys#read-error port "missing \'|\'") ) )
+	    (let loop ((esc #f) (lst '()))
+	      (let ((c (##sys#peek-char-0 port)))
+		(cond ((eof-object? c) 
+		       (if esc
+			   (##sys#read-error 
+			    port 
+			    "unexpected end of file while reading token delimited by `| ... |'")
+			   (##sys#reverse-list->string lst)))
+		      ((and (not esc)
+			    (or (char-whitespace? c)
+				(memq c terminating-characters)))
+		       (##sys#reverse-list->string lst))
+		      (else
+		       (let ((c ((if esc read-unreserved-char-0 ##sys#read-char-0) port)))
+			 (case c
+			   ((#\|) (loop (not esc) lst))
+			   ((#\\)
+			    (let ((c (##sys#read-char-0 port)))
+			      (if (eof-object? c)
+				  (##sys#read-error
+				   port
+				   "unexpected end of file while reading escaped character")
+				  (loop esc (cons c lst)))))
+			   (else 
+			    (loop 
+			     esc 
+			     (cons (if (or esc csp) c (char-downcase c)) lst))))))))))
 	  
 	  (define (r-char)
 	    ;; Code contributed by Alex Shinn
@@ -2465,7 +2478,10 @@ EOF
 			 (set! tok (##sys#substring tok 0 namespace-max-id-len)) )
 		       (##sys#setbyte p 0 i)
 		       (##sys#intern-symbol
-			(string-append p (##sys#substring tok 0 i) (##sys#substring tok (fx+ i 1) toklen)) ) ]
+			(string-append
+			 p 
+			 (##sys#substring tok 0 i)
+			 (##sys#substring tok (fx+ i 1) toklen)) ) ]
 		      [else (loop (fx+ i 1))] ) ) ) )
 
 	  (define (resolve-symbol tok)
@@ -2594,10 +2610,12 @@ EOF
 						    (let ((a (assq (string->symbol tok) read-marks)))
 						      (if a
 							  ((##sys#slot a 1) port)
-							  (##sys#read-error port "invalid `#!' token" tok) ) ) ] ) ) ) ) ) )
+							  (##sys#read-error
+							   port
+							   "invalid `#!' token" tok) ) ) ] ) ) ) ) ) )
 				 (else (##sys#user-read-hook dchar port)) ) ) ) ) ) )
-		  ((#\( #;#\)) (r-list #\( #\)))
-		  ((#;#\( #\)) (##sys#read-char-0 port) (container c))
+		  ((#\() (r-list #\( #\)))
+		  ((#\)) (##sys#read-char-0 port) (container c))
 		  ((#\") (r-string #\"))
 		  ((#\.) (r-number #f))
 		  ((#\- #\+) (r-number #f))
@@ -2608,9 +2626,9 @@ EOF
 			  (reserved-character c))
 			 (else
 			  (case c
-			    ((#\[ #;#\]) (r-list #\[ #\]))
-			    ((#\{ #;#\}) (r-list #\{ #\}))
-			    ((#;#\[ #\] #;#\{ #\}) (##sys#read-char-0 port) (container c))
+			    ((#\[) (r-list #\[ #\]))
+			    ((#\{) (r-list #\{ #\}))
+			    ((#\] #\}) (##sys#read-char-0 port) (container c))
 			    (else (r-symbol) ) ) ) ) ) ) ) ) )
 	
 	(readrec) ) ) ) )
diff --git a/manual/Non-standard read syntax b/manual/Non-standard read syntax
index d8e57e88..85095ae4 100644
--- a/manual/Non-standard read syntax	
+++ b/manual/Non-standard read syntax	
@@ -4,6 +4,17 @@
 
 == Non-standard read syntax
 
+=== Escapes in symbols
+
+{{| ... |}} may be used to escape a sequence of characters when reading a symbol.
+{{\X}} escapes a single character in a symbols name:
+
+  (symbol->string '|abc def|)       =>   "abc def"
+  (symbol->string '|abc||def|)      =>   "abcdef"
+  (symbol->string '|abc|xyz|def|)   =>   "abcxyzdef"
+  (symbol->string '|abc\|def|)      =>   "abc|def"
+  (symbol->string 'abc\ def)        =>   "abc def"
+
 === Multiline Block Comment
 
  #| ... |# 
diff --git a/tests/library-tests.scm b/tests/library-tests.scm
index ee851334..b5494c52 100644
--- a/tests/library-tests.scm
+++ b/tests/library-tests.scm
@@ -79,3 +79,24 @@
 	    (lambda ()
 	      (write (string->symbol "3"))))
 	read)))
+
+
+;;; escaped symbol syntax
+
+(assert (string=? "abc" (symbol->string '|abc|)))
+(assert (string=? "abcdef" (symbol->string '|abc||def|)))
+(assert (string=? "abcxyzdef" (symbol->string '|abc|xyz|def|)))
+(assert (string=? "abc|def" (symbol->string '|abc\|def|)))
+(assert (string=? "abc|def" (symbol->string '|abc\|def|)))
+(assert (string=? "abc" (symbol->string '|abc:|))) ; keyword
+(assert (string=? "abc" (symbol->string '|abc|:))) ; keyword
+(assert (string=? ":abc" (symbol->string ':|abc|)))
+(assert (string=? ":abc" (symbol->string '|:abc|)))
+(assert (string=? "abc" (symbol->string 'abc)))
+(assert (string=? "a c" (symbol->string 'a\ c)))
+(assert (string=? "aBc" (symbol->string 'aBc)))
+
+(parameterize ((case-sensitive #f))
+  (assert (string=? "abc" (symbol->string (with-input-from-string "aBc" read))))
+  (assert (string=? "aBc" (symbol->string (with-input-from-string "|aBc|" read))))
+  (assert (string=? "aBc" (symbol->string (with-input-from-string "a\\Bc" read)))))
Trap