More library-compat fixes from porting the examples (markdown, malli)

Reader / loader:
- #?@ splicing reader conditionals now actually splice the matched collection's
  items into the enclosing sequence; the splice flag was read but ignored, so a
  binding vector like [a #?@(:clj [b (.foo b)])] lost its alignment.
- the file loader reads by position and skips a top-level form that reads as
  nothing (a :cljs-only #?, a #_ discard, a trailing comment) instead of
  treating it as EOF — which silently dropped the rest of a large .cljc file.
- jolt's reader feature set now includes :clj (was {:jolt :default}). jolt is a
  Clojure/JVM-compatible host that emulates clojure.lang.* and java.* interop,
  so it reads the :clj branch of a .cljc library, not :cljs. This also lets four
  more reader-conditional corpus cases pass (floor 2726 -> 2730).

Backend:
- munge-name escapes ' (prime) -> _PRIME_; a Clojure symbol like f' otherwise
  emitted a bare ' into Scheme, which is the quote reader macro and unbalanced
  the output.

Host shims:
- clojure.java.io/writer (pass through a StringWriter, file-back a path) and a
  readLine on the string reader, so line-seq over (io/reader …) works (markdown).

A better "unsupported destructuring pattern: <pat>" error message.
This commit is contained in:
Yogthos 2026-06-22 02:25:11 -04:00
parent 7e2704642b
commit 2de0543613
9 changed files with 93 additions and 18 deletions

View file

@ -294,6 +294,20 @@
(cons "close" (lambda (self) jolt-nil))
(cons "toString" (lambda (self) (sb-str self)))))
;; a file-backed writer (clojure.java.io/writer of a File/path): accumulates like
;; StringWriter, then persists to the path on flush/close, so
;; (with-open [w (io/writer "f")] (.write w …)) writes the file. State #(path buf).
(define (fw-path self) (vector-ref (jhost-state self) 0))
(define (fw-buf self) (vector-ref (jhost-state self) 1))
(define (fw-append! self s) (vector-set! (jhost-state self) 1 (string-append (fw-buf self) s)))
(define (fw-flush! self) (jolt-spit (fw-path self) (fw-buf self))) ; jolt-spit: io.ss
(register-host-methods! "file-writer"
(list (cons "write" (lambda (self x) (fw-append! self (writer-piece x)) jolt-nil))
(cons "append" (lambda (self x) (fw-append! self (render-piece x)) self))
(cons "flush" (lambda (self) (fw-flush! self) jolt-nil))
(cons "close" (lambda (self) (fw-flush! self) jolt-nil))
(cons "toString" (lambda (self) (fw-buf self)))))
;; ---- StringReader -----------------------------------------------------------
;; state: a vector #(string pos marked).
(register-class-ctor! "StringReader"
@ -310,6 +324,19 @@
(cons "reset" (lambda (self) (sr-pos! self (vector-ref (jhost-state self) 2)) jolt-nil))
(cons "skip" (lambda (self n) (let ((n (jnum->exact n)))
(sr-pos! self (min (string-length (sr-s self)) (+ (sr-pos self) n))) (->num n))))
;; readLine: the next line without its terminator (\n or \r\n), nil at EOF —
;; what line-seq drives over a BufferedReader.
(cons "readLine"
(lambda (self)
(let ((s (sr-s self)) (p (sr-pos self)) (len (string-length (sr-s self))))
(if (>= p len) jolt-nil
(let scan ((i p))
(cond
((>= i len) (sr-pos! self len) (substring s p len))
((char=? (string-ref s i) #\newline)
(sr-pos! self (+ i 1))
(substring s p (if (and (> i p) (char=? (string-ref s (- i 1)) #\return)) (- i 1) i)))
(else (scan (+ i 1)))))))))
(cons "close" (lambda (self) jolt-nil))))
;; ---- PushbackReader ---------------------------------------------------------