]> birchwood-abbey.net Git - mit-scheme.git/commitdiff
Fix bug #62618.
authorChris Hanson <org/chris-hanson/cph>
Sat, 10 Dec 2022 09:53:08 +0000 (01:53 -0800)
committerChris Hanson <org/chris-hanson/cph>
Sat, 10 Dec 2022 09:53:08 +0000 (01:53 -0800)
Don't automatically normalize strings to NFC.  Add a note to the reference
manual stating that it's the programmer's responsibility to normalize when
needed.

20 files changed:
doc/ref-manual/strings.texi
src/libraries/srfi-140-impl.scm
src/runtime/bytevector.scm
src/runtime/html-form-codec.scm
src/runtime/http-io.scm
src/runtime/input-port.scm
src/runtime/reader.scm
src/runtime/regexp-recursive.scm
src/runtime/regexp.scm
src/runtime/regsexp.scm
src/runtime/rfc2822-headers.scm
src/runtime/rgxcmp.scm
src/runtime/string-io.scm
src/runtime/string.scm
src/runtime/symbol.scm
src/ssp/mod-lisp.scm
src/xml/xml-parser.scm
src/xml/xml-struct.scm
tests/runtime/test-srfi-115.scm
tests/runtime/test-string.scm

index 40ea0e4bb290f1e8b89d8b3fc7130efa047ef077..eee683160a5defa6ceb582320821f3277c8e6dbd 100644 (file)
@@ -434,10 +434,8 @@ these sequences are semantically identical and should be treated
 equivalently for all purposes.  If two such sequences are normalized to
 the same form, the resulting normalized sequences will be identical.
 
-By default, most procedures that return strings return them in
-@acronym{NFC}.  Notable exceptions are @code{list->string},
-@code{vector->string}, and the @code{utfX->string} procedures, which
-do no normalization, and of course @code{string->nfd}.
+By default, most procedures that return strings do not normalize, so it
+is up to the programmer to normalize as needed.
 
 Generally speaking, @acronym{NFC} is preferred for most purposes, as
 it is the minimal-length sequence for the variants.  Consult the
@@ -647,15 +645,14 @@ created.
 @end itemize
 
 The ``result'' arguments control the form of the returned string.  The
-arguments @code{immutable} and @code{mutable} are straightforward,
-specifying the mutability of the returned string.  For these
-arguments, the returned string contains exactly the same characters,
-in the same order, as were appended to the builder.
-
-However, calling with the argument @code{nfc}, or with no arguments,
-returns an immutable string in Unicode Normalization Form C, exactly
-as if @code{string->nfc} were called on one of the other two result
-strings.
+arguments @code{immutable} (or no argument) and @code{mutable} are
+straightforward, specifying the mutability of the returned string.
+For these arguments, the returned string contains exactly the same
+characters, in the same order, as were appended to the builder.
+
+However, calling with the argument @code{nfc}, returns an immutable
+string in Unicode Normalization Form C, exactly as if
+@code{string->nfc} were called on one of the other two result strings.
 @end deffn
 
 @deffn procedure string-joiner infix prefix suffix
index 1c0b31e9e796f6dd80b6db3a5425434ba98b7112..0244a4007a2492f5a8ad03214d26eb3f3221e632 100644 (file)
@@ -70,7 +70,7 @@ USA.
 (define (string-tabulate proc n)
   (let ((builder (string-builder n)))
     (do ((i 0 (fx+ i 1)))
-       ((not (fx<? i n)) (builder))
+       ((not (fx<? i n)) (builder 'immutable))
       (builder (proc i)))))
 
 ;; TODO: move this into string.scm and make it fast.
@@ -96,7 +96,7 @@ USA.
               (loop (successor seed)))
              ((not (default-object? make-final))
               (builder (make-final seed)))))
-      (builder))))
+      (builder 'immutable))))
 
 (define string-unfold
   (unfolder string-builder))
@@ -142,7 +142,7 @@ USA.
          (builder (string-slice string1 0 start1))
          (builder (string-slice string2 start2 end2))
          (builder (string-slice string1 end1 len1))
-         (builder))))))
+         (builder 'immutable))))))
 \f
 (define (string-prefix-length string1 string2
                              #!optional start1 end1 start2 end2)
@@ -308,7 +308,7 @@ USA.
       (do ((index start (fx+ index 1)))
          ((not (fx<? index end)))
        (builder (proc index)))
-      (builder))))
+      (builder 'immutable))))
 
 (define (string-for-each-index proc string #!optional start end)
   (let* ((end (fix:end-index end (string-length string) 'string-for-each-index))
@@ -336,7 +336,7 @@ USA.
          ((not (fx<? index end)))
        (if (pred (string-ref string index))
            (builder (string-ref string index))))
-      (builder))))
+      (builder 'immutable))))
 
 (define (string-remove pred string #!optional start end)
   (let* ((end (fix:end-index end (string-length string) 'string-remove))
@@ -346,7 +346,7 @@ USA.
          ((not (fx<? index end)))
        (if (not (pred (string-ref string index)))
            (builder (string-ref string index))))
-      (builder))))
+      (builder 'immutable))))
 
 (define (string-repeat kernel n)
   (guarantee non-negative-fixnum? n 'string-repeat)
@@ -354,7 +354,7 @@ USA.
     (do ((i 0 (fx+ i 1)))
        ((not (fx<? i n)))
       (builder kernel))
-    (builder)))
+    (builder 'immutable)))
 
 (define (xsubstring string #!optional from to start end)
   (let* ((end (fix:end-index end (string-length string) 'xsubstring))
@@ -379,7 +379,7 @@ USA.
            (do ((i from (+ i 1)))
                ((not (< i to)))
              (builder (string-ref string (+ start (modulo i n)))))
-           (builder))))))
+           (builder 'immutable))))))
 \f
 (define (string-split string delimiter #!optional grammar limit start end)
   (let* ((end (fix:end-index end (string-length string) 'string-split))
index 8c0475ae940a86bfc41720f82fca92e4995699bc..f149d3152c52dd1ddd5fe0208bca5c84a26b6b35 100644 (file)
@@ -418,7 +418,7 @@ USA.
                  (loop index*)))
              (if (fix:< index end)
                  (builder (truncated index))))))
-      (builder))))
+      (builder 'immutable))))
 
 (define utf8->string)
 (define utf16be->string)
@@ -503,7 +503,7 @@ USA.
     (do ((i start (fix:+ i 1)))
        ((not (fix:< i end)))
       (builder (integer->char (bytevector-u8-ref bytes i))))
-    (builder)))
+    (builder 'immutable)))
 \f
 (define (bytevector->hexadecimal bytes)
   (define-integrable (hex-char k)
@@ -515,7 +515,7 @@ USA.
        ((not (fix:< i n)))
       (builder (hex-char (fix:lsh (bytevector-u8-ref bytes i) -4)))
       (builder (hex-char (bytevector-u8-ref bytes i))))
-    (builder)))
+    (builder 'immutable)))
 
 (define (hexadecimal->bytevector string)
   (guarantee string? string 'hexadecimal->bytevector)
index dc3c119ac58a20208e3a6365922855c1d67ff264..d0f4315b037b3bbc69aa847c7633d07fd3b8d1ca 100644 (file)
@@ -98,7 +98,7 @@ USA.
                 (loop))
                (else
                 (error "Illegal character in HTML form data:" char))))))
-    (builder)))
+    (builder 'immutable)))
 \f
 ;;;; Encoder
 
@@ -143,7 +143,7 @@ USA.
               ((not (pair? data)))
             (write-char #\&)
             (write-datum (car data)))))
-     (builder)))
+     (builder 'immutable)))
 
 (define-deferred char-set:unreserved
   (char-set-difference char-set:ascii
index 431cc0e521e2d52199da30a1c8d89c0f4bedde43..a19565227d96ebaa5565838c94d0e61de62403ee 100644 (file)
@@ -217,7 +217,7 @@ USA.
            (cond ((eof-object? byte)
                   (if (builder 'empty?)
                       byte
-                      (builder)))
+                      (builder 'immutable)))
                  ((fix:= 13 byte)
                   (let ((line (builder)))
                     (if (fix:= 10 (peek-u8 port))
index 0948f34720f8cac7f4fab772a963f74338ff38d4..f918e992cfb4d0df89806b89167400f1c4575737 100644 (file)
@@ -64,7 +64,7 @@ USA.
                       char
                       (builder)))
                  ((char=? char #\newline)
-                  (builder))
+                  (builder 'immutable))
                  (else
                   (builder char)
                   (loop)))))))))
@@ -82,7 +82,7 @@ USA.
                       (builder)))
                  ((char-in-set? char delimiters)
                   (input-port/unread-char port char)
-                  (builder))
+                  (builder 'immutable))
                  (else
                   (builder char)
                   (loop)))))))))
index ef3ee2cf1f509db6f43e46045895dcd3bf73794d..60499ad255ac0ffeb241b22825fdf9e02aeb9b85 100644 (file)
@@ -378,7 +378,9 @@ USA.
        (string-builder)))
 
 (define (finish-attributes-comment builder db)
-  (let ((attributes (and builder (parse-file-attributes-string (builder)))))
+  (let ((attributes
+        (and builder
+             (parse-file-attributes-string (builder 'immutable)))))
     (if attributes
        (begin
          (process-file-attributes attributes db)
@@ -491,7 +493,7 @@ USA.
          (begin
            (builder (%read-char db))
            (loop))))
-    (builder)))
+    (builder 'immutable)))
 
 (define (%atom-end? db)
   (let ((char (%peek-char db)))
@@ -722,7 +724,7 @@ USA.
        (integer->char (fix:+ (fix:lsh (fix:+ (fix:lsh d1 3) d2) 3) d3))))
 
     (loop)
-    (builder)))
+    (builder 'immutable)))
 \f
 (define (handler:false db ctx char1 char2)
   ctx char1
@@ -780,7 +782,7 @@ USA.
                            (%read-char/no-eof db)
                            char)))
                     (loop))))
-            (name->char (builder)
+            (name->char (builder 'immutable)
                         (eq? #t (db-fold-case? db))))))))
 \f
 (define (handler:named-constant db ctx char1 char2)
@@ -811,7 +813,7 @@ USA.
             (begin
               (builder char)
               (loop)))))
-     (builder))))
+     (builder 'immutable))))
 \f
 ;;;; Datum labels
 
index 4d90ab71da2fa0c79855e7a29d973e1dfada3635..6f6d7dbe52195dfc7c6eddb21a209d6ee9e97061 100644 (file)
@@ -285,7 +285,7 @@ USA.
     (do ((position start-position (next-position position)))
        ((same-positions? position end-position))
       (builder (next-char position)))
-    (builder)))
+    (builder 'immutable)))
 
 (define (make-source-position source)
   (let ((marker (list 'source-position)))
index 5657f7ef1ae9a71026202bdb47b6a9b0bdf62f9a..6fd245b211e967f4c1e00f38b46983c3eb4ca256 100644 (file)
@@ -200,6 +200,6 @@ USA.
                            (builder range)))
                      (loop (cdr ranges)))))
              (builder #\])
-             (builder))
+             (builder 'immutable))
            (re-quote-string (string (car chars))))
        "")))
\ No newline at end of file
index 4345eea0f0c91ab3eff6c5bd8bd49a702c9daba8..fc4b5b0c961b5496e6e56eafc9fb1b228814c497 100644 (file)
@@ -284,7 +284,7 @@ USA.
       (guarantee regsexp-match? match 'regsexp-replacer)
       (let ((builder (string-builder)))
        (replacer builder match)
-       (builder)))))
+       (builder 'immutable)))))
 
 (define (%regsexp-replacer replacement caller)
   (let loop ((r replacement))
@@ -345,13 +345,13 @@ USA.
                   (builder (car exprs))
                   (optimize-alt (cdr exprs) builder))
                 (if builder
-                    (cons (builder)
+                    (cons (builder 'immutable)
                           (cons (car exprs)
                                 (optimize-alt (cdr exprs) #f)))
                     (cons (car exprs)
                           (optimize-alt (cdr exprs) #f))))
             (if builder
-                (list (builder))
+                (list (builder 'immutable))
                 '())))
 
       (define (dispatch)
index a261abcaa2a76218e80f4f65248fed40900d627e..42f181254bef28e2569fd3ad14b59200c49b63f0 100644 (file)
@@ -189,7 +189,7 @@ USA.
            (cond ((eof-object? byte)
                   (if (builder 'empty?)
                       byte
-                      (builder)))
+                      (builder 'immutable)))
                  ((fix:= 13 byte)
                   (let ((byte (peek-u8 port)))
                     (cond ((eof-object? byte)
@@ -200,7 +200,7 @@ USA.
                           (else
                            (parse-error port "Invalid line ending:"
                                         'read-ascii-line))))
-                  (builder))
+                  (builder 'immutable))
                  ((fix:= 10 byte)
                   (parse-error port "Invalid line ending:" 'read-ascii-line))
                  ((and (fix:<= 32 byte) (fix:<= byte 126))
index 5ce3f4a9c3c98673b0b31ed6a03d2ac99b6972be..f1745423790369b3aeda197cf97109858388f446 100644 (file)
@@ -241,7 +241,7 @@ USA.
                           (builder #\\))
                       (builder char))
                     string)
-    (builder)))
+    (builder 'immutable)))
 \f
 ;;;; Pattern Compiler
 
@@ -793,7 +793,7 @@ USA.
           (do ((i 0 (fix:+ i 1)))
               ((not (fix:< i 1)))
             (sbuilder (integer->char (get-byte))))
-          (write (sbuilder) output)
+          (write (sbuilder 'immutable) output)
           (fix:+ 1 n)))
        ((jump on-failure-jump maybe-finalize-jump dummy-failure-jump)
         (write-char #\space output)
index 38bc09feb801de0196da74b1e3c2e32743c04229..257c17414b7123ca884c41c24bd852eb5fce3976 100644 (file)
@@ -213,7 +213,7 @@ USA.
 (define (string-out/extract-output! port)
   (let* ((os (textual-port-state port))
         (builder (ostate-builder os))
-        (output (builder)))
+        (output (builder 'immutable)))
     (builder 'reset!)
     (set-ostate-column! os 0)
     output))
index b79870915223ab4640e98bfc4d0a174d3ea489d0..ac5034a58e4b5ac5d03af3cd0c11ec64bae5b5b0 100644 (file)
@@ -607,8 +607,8 @@ USA.
               (vector-for-each append-char! object))
              (else
               (case object
-                ((#!default nfc) (build build-string:nfc))
-                ((immutable) (build build-string:immutable))
+                ((#!default immutable) (build build-string:immutable))
+                ((nfc) (build build-string:nfc))
                 ((mutable) (build build-string:mutable))
                 ((legacy) (build build-string:legacy))
                 ((empty? count max-cp reset!) ((builder object)))
@@ -706,8 +706,8 @@ USA.
                   if= if< if>))
 
 (define (string-compare-ci string1 string2 if= if< if>)
-  (%string-compare (string-foldcase string1)
-                  (string-foldcase string2)
+  (%string-compare (%foldcase->nfc string1)
+                  (%foldcase->nfc string2)
                   if= if< if>))
 
 ;; Non-Unicode implementation, acceptable to R7RS.
@@ -726,6 +726,9 @@ USA.
                  ((fix:< end2 end1) (if>))
                  (else (if=))))))))
 
+(define-integrable (%foldcase->nfc string)
+  (string->nfc (string-foldcase string)))
+
 (define-integrable (true) #t)
 (define-integrable (false) #f)
 
@@ -756,11 +759,11 @@ USA.
 (define string>? (string-comparison-maker string->nfc %string>?))
 (define string>=? (string-comparison-maker string->nfc %string>=?))
 
-(define string-ci=? (string-comparison-maker string-foldcase %string=?))
-(define string-ci<? (string-comparison-maker string-foldcase %string<?))
-(define string-ci<=? (string-comparison-maker string-foldcase %string<=?))
-(define string-ci>? (string-comparison-maker string-foldcase %string>?))
-(define string-ci>=? (string-comparison-maker string-foldcase %string>=?))
+(define string-ci=? (string-comparison-maker %foldcase->nfc %string=?))
+(define string-ci<? (string-comparison-maker %foldcase->nfc %string<?))
+(define string-ci<=? (string-comparison-maker %foldcase->nfc %string<=?))
+(define string-ci>? (string-comparison-maker %foldcase->nfc %string>?))
+(define string-ci>=? (string-comparison-maker %foldcase->nfc %string>=?))
 \f
 ;;;; Match
 
@@ -791,8 +794,8 @@ USA.
                   (string->nfc (string-slice string start end))))
 
 (define (string-prefix-ci? prefix string #!optional start end)
-  (%string-prefix? (string-foldcase prefix)
-                  (string-foldcase (string-slice string start end))))
+  (%string-prefix? (%foldcase->nfc prefix)
+                  (%foldcase->nfc (string-slice string start end))))
 
 (define (%string-prefix? prefix string)
   (let ((n (string-length prefix)))
@@ -808,8 +811,8 @@ USA.
                   (string->nfc (string-slice string start end))))
 
 (define (string-suffix-ci? suffix string #!optional start end)
-  (%string-suffix? (string-foldcase suffix)
-                  (string-foldcase (string-slice string start end))))
+  (%string-suffix? (%foldcase->nfc suffix)
+                  (%foldcase->nfc (string-slice string start end))))
 
 (define (%string-suffix? suffix string)
   (let ((n (string-length suffix))
@@ -838,7 +841,7 @@ USA.
     (do ((index 0 (fix:+ index 1)))
        ((not (fix:< index end)))
       (builder (transform (string-ref string index))))
-    (builder)))
+    (builder 'immutable)))
 
 (define (string-titlecase string)
   (let ((builder (string-builder)))
@@ -847,7 +850,7 @@ USA.
            end)
          0
          (string-word-breaks string))
-    (builder)))
+    (builder 'immutable)))
 
 (define (maybe-titlecase string start end builder)
   (let loop ((index start))
@@ -1466,7 +1469,7 @@ USA.
                (guarantee string? string caller)
                (builder string))
              strings)
-    (builder)))
+    (builder 'immutable)))
 
 (define (string . objects)
   (string* objects))
@@ -1485,7 +1488,7 @@ USA.
                              (lambda (port)
                                (display object port))))))))
              objects)
-    (builder)))
+    (builder 'immutable)))
 \f
 ;;;; Mapping
 
@@ -1548,7 +1551,7 @@ USA.
       (do ((i 0 (fix:+ i 1)))
          ((not (fix:< i n)))
        (builder (proc i)))
-      (builder))))
+      (builder 'immutable))))
 \f
 (define (string-count proc string . strings)
   (receive (n proc) (mapper-values proc string strings)
@@ -1617,7 +1620,7 @@ USA.
                          (builder string))
                        (cdr strings))
              (builder suffix)
-             (builder))
+             (builder 'immutable))
            "")))))
 
 (define-deferred string-joiner-options
@@ -1749,7 +1752,7 @@ USA.
                   (builder fill-with))
                 (if (eq? where 'leading)
                     (builder string))
-                (builder))))))))
+                (builder 'immutable))))))))
 
 (define (grapheme-cluster-string? object)
   (and (string? object)
@@ -1798,7 +1801,7 @@ USA.
                                       (ustring-length string)))))
 
 (define (string-ci-hash string #!optional modulus)
-  (string-hash (string-foldcase string) modulus))
+  (string-hash (%foldcase->nfc string) modulus))
 
 (define (8-bit-string? object)
   (and (string? object)
index 259ce3548287eaba918ee0d77c23fdf69b6c386e..3293bff672c685269d0ad43ae46b1742b998f7cc 100644 (file)
@@ -57,7 +57,9 @@ USA.
 
 (define (string->uninterned-symbol string #!optional start end)
   ((ucode-primitive system-pair-cons) (ucode-type uninterned-symbol)
-                                     (string->utf8 string start end)
+                                     (string->utf8
+                                      (string->nfc
+                                       (substring string start end)))
                                      (make-unmapped-unbound-reference-trap)))
 
 (define (string->symbol string #!optional start end)
@@ -68,7 +70,7 @@ USA.
            (default-object? start)
            (default-object? end))
        (->bytes string)
-       (string->utf8 string start end))))
+       (string->utf8 (string->nfc (substring string start end))))))
 
 (define (symbol->string symbol)
   (let ((bytes (%symbol-bytes symbol 'symbol->string)))
@@ -145,7 +147,7 @@ USA.
           (ustring-ascii? string))
       ;; Needed during cold load.
       (->bytes (ascii-string-foldcase string))
-      (string->utf8 (string-foldcase string))))
+      (string->utf8 (string->nfc (string-foldcase string)))))
 
 (define (ustring-ascii? string)
   (let ((end (ustring-length string)))
index 76ada0762811df8f5513f493f953633487f4c423..9927769edb80ac7117e6743ded90516e7c7cea83 100644 (file)
@@ -413,7 +413,7 @@ USA.
     (do ((i 0 (fix:+ i 1)))
        ((not (fix:< i n)))
       (builder (integer->char (bytevector-u8-ref bv i))))
-    (builder)))
+    (builder 'immutable)))
 
 (define (set-status-header message code)
   (set-header message
index 9c3dfbd077c651af5538750de6992b24325e14cb..24df70ec2f127c52a01310dc3e063537b9316a80 100644 (file)
@@ -903,7 +903,7 @@ USA.
                      (builder (string-slice string start index))
                      (loop (step-over-eol index)))
                    (builder (string-slice string start)))))
-           (builder))))
+           (builder 'immutable))))
       (if (if (default-object? always-copy?) #f always-copy?)
          (string-copy string)
          string)))
index c4ee5284c76c146b71243c0cef27f736b79d1d99..cbce4d82c4b8726bdd640e2d4e2f7b6a55922a68 100644 (file)
@@ -602,4 +602,4 @@ USA.
                    (builder #\space))
                (builder (symbol->string nmtoken)))
              nmtokens)
-    (builder)))
\ No newline at end of file
+    (builder 'immutable)))
\ No newline at end of file
index dc03582905392e6a8fecf059620927bad2591e85..d446c4293acc347a6043bbf0bdace5f95898dd16 100644 (file)
@@ -34,7 +34,8 @@ USA.
   (lambda (expected re string #!optional start end)
     (let ((thunk
           (lambda ()
-            (translate-regexp-match (proc re string start end)))))
+            (translate-regexp-match
+             (proc re string start end)))))
       (lambda ()
        (with-test-properties
            (lambda ()
@@ -756,11 +757,11 @@ USA.
   (match-all-test '(0 5) '(* numeric) "12345")
   (match-all-test #f '(w/ascii (* numeric)) "12345")
 
-  (match-all-test '(0 1) 'grapheme "한")
-  (match-all-test '(0 1) 'grapheme "글")
+  (match-all-test '(0 1) 'grapheme (string->nfc "한"))
+  (match-all-test '(0 1) 'grapheme (string->nfc "글"))
 
-  (match-all-test '(0 1) '(: bog grapheme eog) "한")
-  (match-all-test #f '(: "ᄒ" bog grapheme eog "ᆫ") "한"))
+  (match-all-test '(0 1) '(: bog grapheme eog) (string->nfc "한"))
+  (match-all-test #f '(: "ᄒ" bog grapheme eog "ᆫ") (string->nfc "한")))
 
 (define-test 'chibi-extract
   (lambda ()
index 561a0bc6f9bfc146eb009578ceadca59f4484695..5be92814de143701a39e85cd7ddd34ad2e9ba54d 100644 (file)
@@ -148,7 +148,7 @@ USA.
 (define (build-string objects)
   (let ((builder (string-builder)))
     (for-each builder objects)
-    (builder)))
+    (builder 'immutable)))
 
 (define (chars->string chars)
   (let ((s (make-string (length chars))))