Adds read, write, display, newline, write-to-string, display-to-string
and current-*-port primitives to both JS and OCaml hosts.
JS: sxReadNormalize (#t/#f→true/false), sxReadConvert (()→nil),
sxEq array comparison, sxWriteVal symbol/keyword name fix,
readerMacroGet/readerMacroSet registry in parser platform.
OCaml: sx_write_val/sx_display_val helpers, read/write/display/newline
primitives on port types; parser extended for #t/#f and N/D rationals.
42 new tests (test-read-write.sx), all passing on JS and OCaml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
212 lines
6.3 KiB
Plaintext
212 lines
6.3 KiB
Plaintext
;; ==========================================================================
|
|
;; test-read-write.sx — Tests for read / write / display / newline
|
|
;; ==========================================================================
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; read — parse one datum from an input port
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"read:basics"
|
|
(deftest
|
|
"read integer"
|
|
(let ((p (open-input-string "42"))) (assert= (read p) 42)))
|
|
(deftest
|
|
"read float"
|
|
(let ((p (open-input-string "3.14"))) (assert= (read p) 3.14)))
|
|
(deftest
|
|
"read string"
|
|
(let ((p (open-input-string "\"hello\""))) (assert= (read p) "hello")))
|
|
(deftest
|
|
"read boolean true"
|
|
(let ((p (open-input-string "#t"))) (assert (read p))))
|
|
(deftest
|
|
"read boolean false"
|
|
(let ((p (open-input-string "#f"))) (assert (not (read p)))))
|
|
(deftest
|
|
"read nil"
|
|
(let ((p (open-input-string "()"))) (assert-nil (read p))))
|
|
(deftest
|
|
"read list"
|
|
(let
|
|
((p (open-input-string "(1 2 3)")))
|
|
(assert= (read p) (list 1 2 3))))
|
|
(deftest
|
|
"read nested list"
|
|
(let
|
|
((p (open-input-string "(+ 1 (* 2 3))")))
|
|
(assert=
|
|
(read p)
|
|
(list (quote +) 1 (list (quote *) 2 3))))))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; read — eof and multi-read
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"read:eof"
|
|
(deftest
|
|
"read eof returns eof-object"
|
|
(let ((p (open-input-string ""))) (assert (eof-object? (read p)))))
|
|
(deftest
|
|
"read whitespace-only returns eof"
|
|
(let ((p (open-input-string " "))) (assert (eof-object? (read p)))))
|
|
(deftest
|
|
"read two forms"
|
|
(let
|
|
((p (open-input-string "1 2")))
|
|
(let
|
|
((a (read p)) (b (read p)))
|
|
(assert (and (= a 1) (= b 2))))))
|
|
(deftest
|
|
"read returns eof after last form"
|
|
(let
|
|
((p (open-input-string "42")))
|
|
(read p)
|
|
(assert (eof-object? (read p))))))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; write — serialize with quoting
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"write:basics"
|
|
(deftest "write integer" (assert= (write-to-string 42) "42"))
|
|
(deftest
|
|
"write negative integer"
|
|
(assert= (write-to-string -5) "-5"))
|
|
(deftest "write float" (assert= (write-to-string 3.14) "3.14"))
|
|
(deftest "write true" (assert= (write-to-string true) "#t"))
|
|
(deftest "write false" (assert= (write-to-string false) "#f"))
|
|
(deftest "write nil" (assert= (write-to-string nil) "()"))
|
|
(deftest
|
|
"write string quotes"
|
|
(assert= (write-to-string "hello") "\"hello\""))
|
|
(deftest
|
|
"write string with escapes"
|
|
(assert= (write-to-string "a\"b") "\"a\\\"b\""))
|
|
(deftest
|
|
"write list"
|
|
(assert=
|
|
(write-to-string (list 1 2 3))
|
|
"(1 2 3)"))
|
|
(deftest
|
|
"write nested list"
|
|
(assert=
|
|
(write-to-string (list 1 (list 2 3)))
|
|
"(1 (2 3))"))
|
|
(deftest "write symbol" (assert= (write-to-string (quote foo)) "foo"))
|
|
(deftest "write rational" (assert= (write-to-string 1/3) "1/3")))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; display — serialize without quoting
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"display:basics"
|
|
(deftest "display integer" (assert= (display-to-string 42) "42"))
|
|
(deftest
|
|
"display string no quotes"
|
|
(assert= (display-to-string "hello") "hello"))
|
|
(deftest "display true" (assert= (display-to-string true) "#t"))
|
|
(deftest "display nil" (assert= (display-to-string nil) "()"))
|
|
(deftest
|
|
"display list"
|
|
(assert=
|
|
(display-to-string (list 1 2 3))
|
|
"(1 2 3)")))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; write vs display distinction
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"write-vs-display"
|
|
(deftest
|
|
"write quotes string, display does not"
|
|
(let
|
|
((s "hello"))
|
|
(assert
|
|
(and
|
|
(= (write-to-string s) "\"hello\"")
|
|
(= (display-to-string s) "hello")))))
|
|
(deftest
|
|
"write and display same for numbers"
|
|
(assert= (write-to-string 42) (display-to-string 42)))
|
|
(deftest
|
|
"write and display same for lists"
|
|
(assert=
|
|
(write-to-string (list 1 2))
|
|
(display-to-string (list 1 2)))))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; write/display/newline to port
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"write-to-port"
|
|
(deftest
|
|
"write to output port"
|
|
(let
|
|
((p (open-output-string)))
|
|
(write 42 p)
|
|
(assert= (get-output-string p) "42")))
|
|
(deftest
|
|
"display to output port"
|
|
(let
|
|
((p (open-output-string)))
|
|
(display "hi" p)
|
|
(assert= (get-output-string p) "hi")))
|
|
(deftest
|
|
"newline to output port"
|
|
(let
|
|
((p (open-output-string)))
|
|
(newline p)
|
|
(assert= (get-output-string p) "\n")))
|
|
(deftest
|
|
"write then newline"
|
|
(let
|
|
((p (open-output-string)))
|
|
(write "hello" p)
|
|
(newline p)
|
|
(assert= (get-output-string p) "\"hello\"\n")))
|
|
(deftest
|
|
"display multiple values"
|
|
(let
|
|
((p (open-output-string)))
|
|
(display 1 p)
|
|
(display " " p)
|
|
(display 2 p)
|
|
(assert= (get-output-string p) "1 2"))))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; write round-trip
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(defsuite
|
|
"write:round-trip"
|
|
(deftest
|
|
"integer round-trips"
|
|
(let
|
|
((p (open-input-string (write-to-string 42))))
|
|
(assert= (read p) 42)))
|
|
(deftest
|
|
"string round-trips"
|
|
(let
|
|
((p (open-input-string (write-to-string "hello world"))))
|
|
(assert= (read p) "hello world")))
|
|
(deftest
|
|
"list round-trips"
|
|
(let
|
|
((p (open-input-string (write-to-string (list 1 2 3)))))
|
|
(assert= (read p) (list 1 2 3))))
|
|
(deftest
|
|
"boolean true round-trips"
|
|
(let
|
|
((p (open-input-string (write-to-string true))))
|
|
(assert (read p))))
|
|
(deftest
|
|
"boolean false round-trips"
|
|
(let
|
|
((p (open-input-string (write-to-string false))))
|
|
(assert (not (read p)))))) |