~ chicken-core (master) 3f4ab3d51cc0f49a3a1b3ce2bdabcb05dbaf3da1


commit 3f4ab3d51cc0f49a3a1b3ce2bdabcb05dbaf3da1
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Mon Aug 31 20:28:45 2026 +0200
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Mon Aug 31 20:28:45 2026 +0200

    Convert embedded strings in u8 vectors to UTF-8 instead of cutting of upper bits
    Also generalize element type handling.
    
    Bug reported by "klm`")

diff --git a/library.scm b/library.scm
index 145f5d21..31f12cac 100644
--- a/library.scm
+++ b/library.scm
@@ -5385,34 +5385,26 @@ EOF
       ((#\( #\") (##sys#read port ##sys#default-read-info-hook))
       (else (##sys#read-error port "invalid numeric vector syntax" c)))))
 
-;; This code is too complicated. We try to avoid mapping over
-;; a potentially large list and creating lots of garbage in the
-;; process, therefore the final result list is constructed
-;; via destructive updates and thus rather inelegant yet avoids
-;; any re-consing unless elements are non-numeric.
 (define (##sys#canonicalize-number-list! lst1)
   (let loop ((lst lst1) (prev #f))
     (if (and (##core#inline "C_blockp" lst)
              (##core#inline "C_pairp" lst))
         (let retry ((x (##sys#slot lst 0)))
           (cond ((char? x) (retry (string x)))
-                ((string? x)
-                 (if (zero? (string-length x))
-                     (loop (##sys#slot lst 1) prev)
-                     (let loop2 ((ns (string->list x)) (prev prev))
-                       (let ((n (cons (char->integer (##sys#slot ns 0))
-                                      (##sys#slot lst 1))))
-                         (if prev
-                             (##sys#setslot prev 1 n)
-                             (set! lst1 n))
-                         (let ((ns2 (##sys#slot ns 1)))
-                           (if (null? ns2)
-                               (loop (##sys#slot lst 1) n)
-                               (loop2 (##sys#slot ns 1) n)))))))
+                ((null? x) (loop (##sys#slot lst 1) prev))
+                ((list? x) 
+                  (let ((lst (##sys#append x (##sys#slot lst 1))))
+                    (if prev
+                        (##sys#setslot prev 1 lst)
+                        (set! lst1 lst))
+                    (loop lst prev)))
+                ((string? x) (retry (chicken.bytevector#string->utf8 x)))
+                ((and (##core#inline "C_blockp" x)
+                      (##sys#bytevector? x))
+                  (retry (##sys#bytevector->list x)))
+                ((##sys#srfi-4-vector? x) (retry (##sys#slot x 1)))
                 (else (loop (##sys#slot lst 1) lst))))
-        (cond (prev (##sys#setislot prev 1 '())
-                    lst1)
-              (else '())))))
+        lst1)))
 
 ;;; Table for specially-handled read-syntax:
 ;
diff --git a/manual/Module (chicken number-vector) b/manual/Module (chicken number-vector)
index 07058c21..1778aaba 100644
--- a/manual/Module (chicken number-vector)	
+++ b/manual/Module (chicken number-vector)	
@@ -96,7 +96,7 @@ will set {{x}} to the object {{#u8(1 2 3)}}. Since CHICKEN 4.9.0, literal homoge
  `(,x #u8(1 2))        ; legal
  `#u8(1 ,x 2)          ; illegal
 
-Elements may also be characters or strings, in that case they are interpreted
+Elements may also be characters, lists, number vectors or strings, in that case they are interpreted
 as a sequence of numerical character codes. For example,
 
  '#u8(#\x7f "EL" #\F 2 1)
@@ -107,8 +107,17 @@ is equivalent to
 
 Character literals inside numeric vectors expand into the UTF-8 sequence of
 the characters they represent, for strings the contained characters
-are interpreted in whatever encoding is used for the text file or stream
-in which the literal appears.
+are interpreted as UTF-8. Embedded bytevectors or numerical vectors are
+spliced directly into the result, without further translation. Lists are
+spliced as well, recursively, so:
+
+ '#u8(1 (2) ((3)) #u16(0xabcd))
+
+will result in
+
+  #u8(1 2 3 #\xcd #\xab) 
+
+on a little endian machine.
 
 Note that {{#u8"..."}} can be used as an abbreviation for the special case
 {{#u8("...")}}.
Trap