spec: string-buffer primitive — make-string-buffer/append!/->string/length

OCaml: StringBuffer of Buffer.t in sx_types.ml; 5 primitives in
sx_primitives.ml (make-string-buffer, string-buffer?, string-buffer-append!,
string-buffer->string, string-buffer-length); inspect case added.

JS: SxStringBuffer with array+join backend; _string_buffer marker for
typeOf dispatch and dict? exclusion (also excludes _vector from dict?).

spec/primitives.sx: 5 define-primitive entries.
17/17 tests pass on both OCaml and JS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-26 17:05:05 +00:00
parent cc0af51921
commit d98b5fa223
7 changed files with 190 additions and 4 deletions

View File

@@ -0,0 +1,131 @@
(defsuite
"string-buffer"
(deftest
"make-string-buffer creates a string-buffer"
(let ((buf (make-string-buffer))) (assert (string-buffer? buf))))
(deftest
"string-buffer? is false for non-buffers"
(assert= false (string-buffer? "hello"))
(assert= false (string-buffer? 42))
(assert= false (string-buffer? nil))
(assert= false (string-buffer? (list)))
(assert= false (string-buffer? {:key "val"})))
(deftest
"type-of returns string-buffer"
(assert= "string-buffer" (type-of (make-string-buffer))))
(deftest
"empty buffer converts to empty string"
(let
((buf (make-string-buffer)))
(assert= "" (string-buffer->string buf))))
(deftest
"empty buffer has length zero"
(let
((buf (make-string-buffer)))
(assert= 0 (string-buffer-length buf))))
(deftest
"single append accumulates string"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "hello")
(assert= "hello" (string-buffer->string buf))))
(deftest
"multiple appends join in order"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "foo")
(string-buffer-append! buf "bar")
(string-buffer-append! buf "baz")
(assert= "foobarbaz" (string-buffer->string buf))))
(deftest
"length tracks total bytes appended"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "abc")
(string-buffer-append! buf "de")
(assert= 5 (string-buffer-length buf))))
(deftest
"append returns nil"
(let
((buf (make-string-buffer)))
(assert= nil (string-buffer-append! buf "x"))))
(deftest
"appending empty string is harmless"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "start")
(string-buffer-append! buf "")
(string-buffer-append! buf "end")
(assert= "startend" (string-buffer->string buf))
(assert= 8 (string-buffer-length buf))))
(deftest
"buffer is still usable after string-buffer->string"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "hello")
(string-buffer->string buf)
(string-buffer-append! buf " world")
(assert= "hello world" (string-buffer->string buf))))
(deftest
"two buffers are independent"
(let
((b1 (make-string-buffer)) (b2 (make-string-buffer)))
(string-buffer-append! b1 "one")
(string-buffer-append! b2 "two")
(string-buffer-append! b1 "ONE")
(assert= "oneONE" (string-buffer->string b1))
(assert= "two" (string-buffer->string b2))))
(deftest
"loop building — linear string concat"
(let
((buf (make-string-buffer)))
(let
loop
((i 0))
(when
(< i 5)
(string-buffer-append! buf (str i))
(loop (+ i 1))))
(assert= "01234" (string-buffer->string buf))
(assert= 5 (string-buffer-length buf))))
(deftest
"building CSV row with separator"
(let
((buf (make-string-buffer)) (items (list "a" "b" "c" "d")))
(let
loop
((remaining items) (is-first true))
(when
(not (empty? remaining))
(when (not is-first) (string-buffer-append! buf ","))
(string-buffer-append! buf (first remaining))
(loop (rest remaining) false)))
(assert= "a,b,c,d" (string-buffer->string buf))))
(deftest
"unicode characters accumulate correctly"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "こんにちは")
(string-buffer-append! buf " ")
(string-buffer-append! buf "世界")
(assert= "こんにちは 世界" (string-buffer->string buf))))
(deftest
"repeated to-string calls are consistent"
(let
((buf (make-string-buffer)))
(string-buffer-append! buf "test")
(assert= (string-buffer->string buf) (string-buffer->string buf))))
(deftest
"building with join pattern produces correct output"
(let
((buf (make-string-buffer))
(words (list "the" "quick" "brown" "fox")))
(let
loop
((remaining words) (sep ""))
(when
(not (empty? remaining))
(string-buffer-append! buf sep)
(string-buffer-append! buf (first remaining))
(loop (rest remaining) " ")))
(assert= "the quick brown fox" (string-buffer->string buf)))))