fix: unify vector repr on tuples; realize lazy-seqs in =/vec/into; fix into for maps/lists; restore ns after PV load; deftype field-access fallback in IFn dispatch
This commit is contained in:
parent
accb7a2c2f
commit
2ea5b2bb5f
5 changed files with 69 additions and 37 deletions
|
|
@ -11,6 +11,7 @@
|
|||
(defn- load-persistent-structures
|
||||
"Load immutable persistent data structures and swap clojure.core bindings."
|
||||
[ctx]
|
||||
(def saved-ns (ctx-current-ns ctx))
|
||||
(def source (slurp "src/jolt/clojure/lang/persistent_vector.clj"))
|
||||
(var cur source)
|
||||
(while (> (length (string/trim cur)) 0)
|
||||
|
|
@ -18,11 +19,17 @@
|
|||
(set cur rest)
|
||||
(when (not (nil? form))
|
||||
(eval-form ctx @{} form)))
|
||||
(let [core-ns (ctx-find-ns ctx "clojure.core")
|
||||
pv-ns (ctx-find-ns ctx "jolt.lang.persistent-vector")]
|
||||
(ns-intern core-ns "vec" (var-get (ns-find pv-ns "vector")))
|
||||
(ns-intern core-ns "vector" (var-get (ns-find pv-ns "vector")))
|
||||
(ns-intern core-ns "vector?" (var-get (ns-find pv-ns "vector?")))))
|
||||
# Vectors are represented as Janet tuples throughout core; bind vec/vector/
|
||||
# vector? to the tuple-based implementations so literals (`[...]`) and the
|
||||
# constructors share one representation. The PersistentVector namespace stays
|
||||
# loaded for code that wants it explicitly via jolt.lang.persistent-vector.
|
||||
(let [core-ns (ctx-find-ns ctx "clojure.core")]
|
||||
(ns-intern core-ns "vec" core-vec)
|
||||
(ns-intern core-ns "vector" core-vector)
|
||||
(ns-intern core-ns "vector?" core-vector?))
|
||||
# Restore the namespace: loading the PV file above left current-ns set to
|
||||
# jolt.lang.persistent-vector, which would shadow clojure.core bindings.
|
||||
(ctx-set-current-ns ctx saved-ns))
|
||||
|
||||
(defn init
|
||||
"Create a new Jolt evaluation context.
|
||||
|
|
|
|||
|
|
@ -86,13 +86,19 @@
|
|||
# Comparison
|
||||
# ============================================================
|
||||
|
||||
(defn- norm-for-= [x]
|
||||
"Realize a lazy-seq to a tuple so it compares as a Clojure sequence."
|
||||
(if (lazy-seq? x)
|
||||
(let [s (ls-seq x)] (if (nil? s) [] (tuple/slice (tuple ;s))))
|
||||
x))
|
||||
|
||||
(defn core-= [& args]
|
||||
(if (< (length args) 2) true
|
||||
(do
|
||||
(var ok true)
|
||||
(var i 0)
|
||||
(while (and ok (< i (dec (length args))))
|
||||
(let [a (args i) b (args (+ i 1))]
|
||||
(let [a (norm-for-= (args i)) b (norm-for-= (args (+ i 1)))]
|
||||
(set ok
|
||||
(if (and (tuple? a) (array? b))
|
||||
(deep= a (tuple/slice (tuple ;b)))
|
||||
|
|
@ -232,24 +238,54 @@
|
|||
(if (struct? coll) (tuple ;(keys coll))
|
||||
coll))))))))
|
||||
|
||||
(defn realize-for-iteration [c]
|
||||
"If c is a lazy-seq, traverse and return all its elements as an array.
|
||||
Otherwise return c as-is. Warning: will loop on infinite lazy-seqs.
|
||||
Correctly handles nil elements (terminates on the empty cell, not on nil)."
|
||||
(if (lazy-seq? c)
|
||||
(do
|
||||
(var items @[])
|
||||
(var cur c)
|
||||
(var go true)
|
||||
(while go
|
||||
(let [cell (realize-ls cur)]
|
||||
(if (or (nil? cell) (= :jolt/pending cell) (= 0 (length cell)))
|
||||
(set go false)
|
||||
(do
|
||||
(array/push items (in cell 0))
|
||||
(let [rt (in cell 1)]
|
||||
(if (nil? rt) (set go false) (set cur (make-lazy-seq rt))))))))
|
||||
items)
|
||||
c))
|
||||
|
||||
(defn core-vec [coll]
|
||||
(if (tuple? coll) coll
|
||||
(if (array? coll) (tuple ;coll)
|
||||
(if (struct? coll) (tuple ;(map |(in (kvs coll) (+ (* $ 2) 1)) (range (/ (length (kvs coll)) 2))))
|
||||
(tuple)))))
|
||||
(let [coll (realize-for-iteration coll)]
|
||||
(if (tuple? coll) coll
|
||||
(if (array? coll) (tuple ;coll)
|
||||
(if (struct? coll) (tuple ;(map |(in (kvs coll) (+ (* $ 2) 1)) (range (/ (length (kvs coll)) 2))))
|
||||
(if (string? coll) (tuple ;(map |(string/from-bytes $) (string/bytes coll)))
|
||||
(tuple)))))))
|
||||
|
||||
(defn core-into [to from]
|
||||
(if (tuple? to)
|
||||
(tuple/slice (tuple ;(array/concat (array/slice to) (if (tuple? from) from (array/slice from)))))
|
||||
(if (array? to)
|
||||
(array/concat to from)
|
||||
(if (struct? to)
|
||||
(let [items (realize-for-iteration from)]
|
||||
(cond
|
||||
# map target: each item is a [k v] pair (or map entry) to assoc
|
||||
(or (phm? to) (struct? to) (and (table? to) (get to :jolt/deftype)))
|
||||
(do
|
||||
(var result to)
|
||||
(each [k v] (pairs from)
|
||||
(set result (merge result {k v})))
|
||||
(each item items
|
||||
(set result (core-assoc result (in item 0) (in item 1))))
|
||||
result)
|
||||
to))))
|
||||
# list target (jolt lists are arrays): conj prepends -> reversed order
|
||||
(array? to)
|
||||
(do
|
||||
(var result (array/slice to))
|
||||
(each x items (array/insert result 0 x))
|
||||
result)
|
||||
# vector target (jolt vectors are tuples): conj appends
|
||||
(tuple? to)
|
||||
(tuple/slice (tuple ;(array/concat (array/slice to) (array/slice items))))
|
||||
to)))
|
||||
|
||||
(defn core-merge [& maps]
|
||||
(if (phm? (first maps))
|
||||
|
|
@ -289,18 +325,6 @@
|
|||
# Sequence operations
|
||||
# ============================================================
|
||||
|
||||
(defn- realize-for-iteration [c]
|
||||
"If c is a lazy-seq, traverse and return all elements as an array.
|
||||
Otherwise return c as-is. Warning: will loop on infinite lazy-seqs."
|
||||
(if (lazy-seq? c)
|
||||
(do
|
||||
(var items @[])
|
||||
(var cur c)
|
||||
(while (not (nil? (ls-first cur)))
|
||||
(array/push items (ls-first cur))
|
||||
(set cur (ls-rest cur)))
|
||||
items)
|
||||
c))
|
||||
|
||||
(defn core-map [f & colls]
|
||||
(if (= 1 (length colls))
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
and deftype/record values implementing IFn. `args` is an array."
|
||||
[ctx f args]
|
||||
(cond
|
||||
(function? f) (apply f args)
|
||||
(or (function? f) (cfunction? f)) (apply f args)
|
||||
(keyword? f) (coll-lookup (get args 0) f (get args 1))
|
||||
(and (struct? f) (= :symbol (f :jolt/type)))
|
||||
(coll-lookup (get args 0) f (get args 1))
|
||||
|
|
@ -66,11 +66,11 @@
|
|||
(and (table? f) (get f :jolt/deftype))
|
||||
(let [ifn-fn (find-protocol-method ctx (get f :jolt/deftype) "IFn" "-invoke")]
|
||||
(if ifn-fn (apply ifn-fn f args)
|
||||
(if (get f :jolt/protocol-methods)
|
||||
(let [invoke-fn (get (f :jolt/protocol-methods) :-invoke)]
|
||||
(if invoke-fn (apply invoke-fn f args)
|
||||
(error (string "Cannot call " (type f) " as a function"))))
|
||||
(error (string "Cannot call " (type f) " as a function")))))
|
||||
(if (and (get f :jolt/protocol-methods) (get (f :jolt/protocol-methods) :-invoke))
|
||||
(apply (get (f :jolt/protocol-methods) :-invoke) f args)
|
||||
# No IFn impl: fall back to map-like field access, e.g. (point :x)
|
||||
(let [v (get f (get args 0) :jolt/not-found)]
|
||||
(if (= v :jolt/not-found) (get args 1) v)))))
|
||||
(and (table? f) (get f :jolt/protocol-methods))
|
||||
(let [invoke-fn (get (f :jolt/protocol-methods) :-invoke)]
|
||||
(if invoke-fn (apply invoke-fn f args)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue