spec: format — CL-style string formatting (~a ~s ~d ~x ~o ~b ~f ~% ~& ~~ ~t)
28 tests, passes on both JS and OCaml. - spec/stdlib.sx: pure SX format function - spec/primitives.sx: format primitive declaration - lib/r7rs.sx: fix number->string to support optional radix arg - hosts/ocaml: add format-decimal primitive, load stdlib.sx in test runner - hosts/javascript: load stdlib.sx in test runner Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
134
spec/stdlib.sx
Normal file
134
spec/stdlib.sx
Normal file
@@ -0,0 +1,134 @@
|
||||
;; ==========================================================================
|
||||
;; stdlib.sx — Pure SX standard library functions
|
||||
;;
|
||||
;; Loaded by test runners after primitives. These functions are implemented
|
||||
;; in SX and require no host-specific code.
|
||||
;;
|
||||
;; IMPORTANT: SX let/when bodies evaluate only the LAST expression.
|
||||
;; Multi-step bodies must be wrapped in (do expr1 expr2 ...).
|
||||
;; ==========================================================================
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; format — CL-style string formatting
|
||||
;;
|
||||
;; Directives:
|
||||
;; ~a display (no quotes) ~s write (with quotes)
|
||||
;; ~d decimal ~x hex ~o octal ~b binary
|
||||
;; ~f fixed-point (6dp) ~% newline
|
||||
;; ~& fresh line ~~ literal tilde
|
||||
;; ~t tab
|
||||
;;
|
||||
;; Signature: (format template arg...) -> string
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define
|
||||
(format template &rest args)
|
||||
(let
|
||||
((buf (make-string-buffer)) (n (string-length template)))
|
||||
(define
|
||||
(consume-arg args)
|
||||
(if
|
||||
(nil? args)
|
||||
(list "" nil)
|
||||
(list (display-to-string (first args)) (rest args))))
|
||||
(define
|
||||
(consume-num args radix)
|
||||
(if
|
||||
(nil? args)
|
||||
(list "" nil)
|
||||
(list (number->string (first args) radix) (rest args))))
|
||||
(define
|
||||
(loop i args)
|
||||
(cond
|
||||
((>= i n) (string-buffer->string buf))
|
||||
((and (= (substring template i (+ i 1)) "~") (< (+ i 1) n))
|
||||
(let
|
||||
((dir (substring template (+ i 1) (+ i 2))))
|
||||
(cond
|
||||
((= dir "a")
|
||||
(let
|
||||
((p (consume-arg args)))
|
||||
(do
|
||||
(string-buffer-append! buf (first p))
|
||||
(loop (+ i 2) (first (rest p))))))
|
||||
((= dir "s")
|
||||
(if
|
||||
(nil? args)
|
||||
(loop (+ i 2) args)
|
||||
(do
|
||||
(string-buffer-append!
|
||||
buf
|
||||
(write-to-string (first args)))
|
||||
(loop (+ i 2) (rest args)))))
|
||||
((= dir "d")
|
||||
(let
|
||||
((p (consume-num args 10)))
|
||||
(do
|
||||
(string-buffer-append! buf (first p))
|
||||
(loop (+ i 2) (first (rest p))))))
|
||||
((= dir "x")
|
||||
(let
|
||||
((p (consume-num args 16)))
|
||||
(do
|
||||
(string-buffer-append! buf (first p))
|
||||
(loop (+ i 2) (first (rest p))))))
|
||||
((= dir "o")
|
||||
(let
|
||||
((p (consume-num args 8)))
|
||||
(do
|
||||
(string-buffer-append! buf (first p))
|
||||
(loop (+ i 2) (first (rest p))))))
|
||||
((= dir "b")
|
||||
(let
|
||||
((p (consume-num args 2)))
|
||||
(do
|
||||
(string-buffer-append! buf (first p))
|
||||
(loop (+ i 2) (first (rest p))))))
|
||||
((= dir "f")
|
||||
(if
|
||||
(nil? args)
|
||||
(loop (+ i 2) args)
|
||||
(do
|
||||
(string-buffer-append!
|
||||
buf
|
||||
(format-decimal (first args) 6))
|
||||
(loop (+ i 2) (rest args)))))
|
||||
((= dir "%")
|
||||
(do
|
||||
(string-buffer-append! buf "\n")
|
||||
(loop (+ i 2) args)))
|
||||
((= dir "&")
|
||||
(do
|
||||
(let
|
||||
((so-far (string-buffer->string buf)))
|
||||
(when
|
||||
(or
|
||||
(= (string-length so-far) 0)
|
||||
(not
|
||||
(=
|
||||
(substring
|
||||
so-far
|
||||
(- (string-length so-far) 1)
|
||||
(string-length so-far))
|
||||
"\n")))
|
||||
(string-buffer-append! buf "\n")))
|
||||
(loop (+ i 2) args)))
|
||||
((= dir "~")
|
||||
(do
|
||||
(string-buffer-append! buf "~")
|
||||
(loop (+ i 2) args)))
|
||||
((= dir "t")
|
||||
(do
|
||||
(string-buffer-append! buf "\t")
|
||||
(loop (+ i 2) args)))
|
||||
(else
|
||||
(do
|
||||
(string-buffer-append! buf "~")
|
||||
(loop (+ i 1) args))))))
|
||||
(else
|
||||
(do
|
||||
(string-buffer-append!
|
||||
buf
|
||||
(substring template i (+ i 1)))
|
||||
(loop (+ i 1) args)))))
|
||||
(loop 0 args)))
|
||||
Reference in New Issue
Block a user