data.csv: fully passes, three general fixes
clojure.data.csv runs its whole suite on jolt (4/4 reading/writing/eof/line- endings). Three general gaps fixed, all runtime, no re-mint, JVM-certified: - The prefix-list form of :require/:use — (:require (clojure [string :as str])) means clojure.string :as str — now expands (loader.ss). It silently failed before, trying to load a "clojure" namespace. - extend-protocol to java.io.Reader / Writer / StringReader / PushbackReader now dispatches: those reader/writer host tags carry the right class names in value-host-tags AND are in host-type-set, so extend-protocol registers under the canonical tag instead of a local ns tag (records.ss). data.csv's Read-CSV-From protocol extends to String / Reader / PushbackReader. - (str StringWriter) returns its accumulated content (register-str-render for the "writer" jhost), not the opaque host object — data.csv writes CSV to one and reads it back. Listed in docs/libraries.md + the site. make test green (+2 corpus rows, 0 new divergences), shakesmoke byte-identical.
This commit is contained in:
parent
745d22260f
commit
44837f01ab
5 changed files with 74 additions and 23 deletions
|
|
@ -154,6 +154,9 @@
|
|||
(cons "flush" (lambda (self) jolt-nil))
|
||||
(cons "close" (lambda (self) jolt-nil))
|
||||
(cons "toString" (lambda (self) (sb-str self)))))
|
||||
;; (str sw) / print a StringWriter -> its accumulated content, like the JVM
|
||||
;; (str calls toString) — data.csv writes CSV to a StringWriter and reads it back.
|
||||
(register-str-render! (lambda (x) (and (jhost? x) (string=? (jhost-tag x) "writer"))) sb-str)
|
||||
|
||||
;; a file-backed writer (clojure.java.io/writer of a File/path): accumulates like
|
||||
;; StringWriter, then persists to the path on flush/close, so
|
||||
|
|
|
|||
|
|
@ -227,39 +227,67 @@
|
|||
(else '()))))
|
||||
(and (pair? items) (symbol-t? (car items)) (symbol-t-name (car items)))))
|
||||
|
||||
;; A libspec under a prefix joins onto it: a bare symbol `string` -> `prefix.string`,
|
||||
;; a vector `[string :as s]` -> `[prefix.string :as s]` (opts preserved).
|
||||
(define (prefix-join prefix lib)
|
||||
(cond
|
||||
((symbol-t? lib) (jolt-symbol #f (string-append prefix "." (symbol-t-name lib))))
|
||||
((pvec? lib)
|
||||
(let ((items (seq->list lib)))
|
||||
(if (and (pair? items) (symbol-t? (car items)))
|
||||
(apply jolt-vector (jolt-symbol #f (string-append prefix "." (symbol-t-name (car items)))) (cdr items))
|
||||
lib)))
|
||||
(else lib)))
|
||||
|
||||
;; The prefix-list form of a require/use spec: a LIST `(prefix lib …)` expands to
|
||||
;; one spec per lib (prefix.lib), so (:require (clojure [string :as str])) means
|
||||
;; clojure.string :as str. A vector / symbol spec is already a single lib.
|
||||
(define (expand-spec s)
|
||||
(if (or (cseq? s) (empty-list-t? s))
|
||||
(let ((items (seq->list s)))
|
||||
(if (and (pair? items) (symbol-t? (car items)) (pair? (cdr items)))
|
||||
(map (lambda (lib) (prefix-join (symbol-t-name (car items)) lib)) (cdr items))
|
||||
(list s)))
|
||||
(list s)))
|
||||
|
||||
;; --- require/use that LOAD ---------------------------------------------------
|
||||
;; Override the alias-only versions from natives-str.ss. Load each spec's target
|
||||
;; (no-op if baked/already loaded), THEN register its :as/:refer under the caller
|
||||
;; ns (chez-register-spec! reads the current ns, restored by load-namespace).
|
||||
(define (loader-require . specs)
|
||||
(for-each
|
||||
(lambda (s)
|
||||
(let ((target (spec-target-name s)))
|
||||
(when target (load-namespace target)))
|
||||
(chez-register-spec! (chez-current-ns) s))
|
||||
(lambda (s0)
|
||||
(for-each
|
||||
(lambda (s)
|
||||
(let ((target (spec-target-name s)))
|
||||
(when target (load-namespace target)))
|
||||
(chez-register-spec! (chez-current-ns) s))
|
||||
(expand-spec s0)))
|
||||
specs)
|
||||
jolt-nil)
|
||||
(def-var! "clojure.core" "require" loader-require)
|
||||
|
||||
(define (loader-use . specs)
|
||||
(define (loader-use . specs0)
|
||||
(for-each
|
||||
(lambda (spec)
|
||||
(let ((target (spec-target-name spec)))
|
||||
(when target (load-namespace target)))
|
||||
(chez-register-spec! (chez-current-ns) spec)
|
||||
(let* ((items (cond ((pvec? spec) (seq->list spec))
|
||||
((or (cseq? spec) (empty-list-t? spec)) (seq->list spec))
|
||||
((symbol-t? spec) (list spec))
|
||||
(else '())))
|
||||
(target (and (pair? items) (symbol-t? (car items)) (symbol-t-name (car items))))
|
||||
(filtered (let scan ((xs (if (pair? items) (cdr items) '())))
|
||||
(cond ((null? xs) #f)
|
||||
((and (keyword? (car xs))
|
||||
(member (keyword-t-name (car xs)) '("only" "refer"))) #t)
|
||||
(else (scan (cdr xs)))))))
|
||||
(when (and target (not filtered))
|
||||
(chez-register-refer-all! (chez-current-ns) target))))
|
||||
specs)
|
||||
(lambda (spec0)
|
||||
(for-each
|
||||
(lambda (spec)
|
||||
(let ((target (spec-target-name spec)))
|
||||
(when target (load-namespace target)))
|
||||
(chez-register-spec! (chez-current-ns) spec)
|
||||
(let* ((items (cond ((pvec? spec) (seq->list spec))
|
||||
((symbol-t? spec) (list spec))
|
||||
(else '())))
|
||||
(target (and (pair? items) (symbol-t? (car items)) (symbol-t-name (car items))))
|
||||
(filtered (let scan ((xs (if (pair? items) (cdr items) '())))
|
||||
(cond ((null? xs) #f)
|
||||
((and (keyword? (car xs))
|
||||
(member (keyword-t-name (car xs)) '("only" "refer"))) #t)
|
||||
(else (scan (cdr xs)))))))
|
||||
(when (and target (not filtered))
|
||||
(chez-register-refer-all! (chez-current-ns) target))))
|
||||
(expand-spec spec0)))
|
||||
specs0)
|
||||
jolt-nil)
|
||||
(def-var! "clojure.core" "use" loader-use)
|
||||
|
||||
|
|
|
|||
|
|
@ -469,6 +469,18 @@
|
|||
((and (jhost? obj) (string=? (jhost-tag obj) "uri")) '("URI" "java.net.URI" "Object"))
|
||||
;; a ByteBuffer — extend-protocol java.nio.ByteBuffer (aws-api util).
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "byte-buffer")) '("ByteBuffer" "java.nio.ByteBuffer" "Object"))
|
||||
;; java.io readers/writers — so (extend-protocol java.io.Reader …) (data.csv)
|
||||
;; and the like dispatch on one. A PushbackReader is also a Reader.
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "string-reader"))
|
||||
'("StringReader" "java.io.StringReader" "Reader" "java.io.Reader" "Object"))
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "pushback-reader"))
|
||||
'("PushbackReader" "java.io.PushbackReader" "FilterReader" "java.io.FilterReader" "Reader" "java.io.Reader" "Object"))
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "char-reader"))
|
||||
'("Reader" "java.io.Reader" "Object"))
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "char-writer"))
|
||||
'("Writer" "java.io.Writer" "Object"))
|
||||
((and (jhost? obj) (string=? (jhost-tag obj) "writer"))
|
||||
'("Writer" "java.io.Writer" "Object"))
|
||||
;; arrays dispatch by their JVM array-class name — extend-protocol to
|
||||
;; (Class/forName "[B") for byte[] (data.json, aws-api), "[C" for char[].
|
||||
((and (jolt-array? obj) (eq? (jolt-array-kind obj) 'byte)) '("[B" "Object"))
|
||||
|
|
@ -606,7 +618,12 @@
|
|||
"ChronoUnit" "ChronoField" "TemporalAmount" "TemporalUnit" "TemporalField"
|
||||
;; ByteBuffer + JVM array classes (extend-protocol to (Class/forName "[B"))
|
||||
"ByteBuffer" "java.nio.ByteBuffer"
|
||||
"[B" "[C" "[I" "[J" "[D" "[Ljava.lang.Object;"))
|
||||
"[B" "[C" "[I" "[J" "[D" "[Ljava.lang.Object;"
|
||||
;; java.io readers/writers — extend-protocol java.io.Reader (data.csv)
|
||||
"Reader" "java.io.Reader" "Writer" "java.io.Writer"
|
||||
"StringReader" "java.io.StringReader" "PushbackReader" "java.io.PushbackReader"
|
||||
"BufferedReader" "java.io.BufferedReader" "FilterReader" "java.io.FilterReader"
|
||||
"InputStream" "java.io.InputStream" "OutputStream" "java.io.OutputStream"))
|
||||
h))
|
||||
(define (strip-prefix s p)
|
||||
(let ((pl (string-length p)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue