feat: structural-sharing persistent vectors (immutable build) + mutable toggle
Round 2 of the persistent-collections work. Add a real 32-way branching-trie persistent vector (src/jolt/pv.janet) with a tail buffer: O(log32 n) conj/assoc/nth/pop, with unchanged subtrees shared by identity. Vector literals and vec/vector/conj/assoc/subvec/etc. now produce and maintain these in the default (immutable) build, replacing the old tuple-based vectors. Every core seq op, the destructurer, IFn application, the printers, =, and the evaluator's literal/splice paths were taught to handle the pvec type. Define several Clojure seq fns that were silently leaking to Janet builtins (some, keep, interleave, flatten, mapcat, interpose) and broke once vectors became tables; normalize collections through realize-for-iteration everywhere. Build-time JOLT_MUTABLE flag now selects fast Janet-native mutable collections: in that mode vectors are arrays (conj appends in place, vector? true, print []), sharing one representation with lists. Default build is immutable. Tests: conformance 206/206, features 71/71, jank 119 (baseline). Test helpers normalized so Janet-level = compares against tuple literals regardless of repr. The 2 test-load-sci failures (bit-clear/get-method) pre-date this work.
This commit is contained in:
parent
1ca93d61c6
commit
1eb2843365
44 changed files with 525 additions and 170 deletions
|
|
@ -75,7 +75,8 @@ Jolt targets Clojure semantics but runs on Janet, not the JVM. The notable diver
|
||||||
|
|
||||||
- **Host platform.** No JVM and no Java interop — `import`, `gen-class`, `proxy` of Java classes, and `java.*` are unavailable. `instance?` recognizes a small set of built-in types (`clojure.lang.Atom`, `Number`, `String`, …).
|
- **Host platform.** No JVM and no Java interop — `import`, `gen-class`, `proxy` of Java classes, and `java.*` are unavailable. `instance?` recognizes a small set of built-in types (`clojure.lang.Atom`, `Number`, `String`, …).
|
||||||
- **Numbers.** Janet integers and doubles only — no bignums, ratios, or `BigDecimal`. `(/ 1 3)` is `0.3333…`, large products lose precision, and there are no auto-promoting `+'`/`*'`. `quot`/`rem`/`mod` follow Clojure's sign rules. `bigint`, `rational?`, and `class` are not provided.
|
- **Numbers.** Janet integers and doubles only — no bignums, ratios, or `BigDecimal`. `(/ 1 3)` is `0.3333…`, large products lose precision, and there are no auto-promoting `+'`/`*'`. `quot`/`rem`/`mod` follow Clojure's sign rules. `bigint`, `rational?`, and `class` are not provided.
|
||||||
- **Collections.** Vectors are Janet tuples, lists are Janet arrays; maps and sets are persistent hash structures. Value equality and sequence operations are Clojure-compatible, but hash-map/hash-set iteration order is unspecified and differs from Clojure — use `sorted-map`/`sorted-set` when order matters.
|
- **Collections.** By default Jolt uses immutable persistent data structures: vectors are 32-way branching tries (structural-sharing persistent vectors with O(log₃₂ n) `conj`/`assoc`/`nth`), lists are immutable, and maps/sets are persistent hash structures. Value equality and sequence operations are Clojure-compatible, but hash-map/hash-set iteration order is unspecified and differs from Clojure — use `sorted-map`/`sorted-set` when order matters.
|
||||||
|
- **Mutable build mode.** Jolt can be compiled to use fast Janet-native *mutable* collections instead, via a build-time flag: `JOLT_MUTABLE=1 jpm build` (default `jpm build` is immutable). In mutable mode vectors and lists share one mutable array representation (so `conj` mutates in place and appends, and `vector?`/`list?` no longer distinguish them) — a performance/looseness trade-off. The default immutable build has full Clojure value semantics.
|
||||||
- **Concurrency / STM.** Single-threaded. No refs, `dosync`, agents, or `send`; `locking` evaluates its body without real locking. Atoms, volatiles, and delays are supported.
|
- **Concurrency / STM.** Single-threaded. No refs, `dosync`, agents, or `send`; `locking` evaluates its body without real locking. Atoms, volatiles, and delays are supported.
|
||||||
- **Regex.** Compiled to Janet's PEG engine (Janet has no regex). Supported: capturing groups (`[whole g1 …]`), greedy and lazy quantifiers with backtracking, `(?:…)`, lookahead `(?=…)`/`(?!…)`, alternation, anchors `^ $ \b \B`, character classes, and the `(?i)` flag. Not supported: lookbehind, backreferences (`\1`), and named groups (`(?<name>…)`).
|
- **Regex.** Compiled to Janet's PEG engine (Janet has no regex). Supported: capturing groups (`[whole g1 …]`), greedy and lazy quantifiers with backtracking, `(?:…)`, lookahead `(?=…)`/`(?!…)`, alternation, anchors `^ $ \b \B`, character classes, and the `(?i)` flag. Not supported: lookbehind, backreferences (`\1`), and named groups (`(?<name>…)`).
|
||||||
- **Not implemented.** Transients (`transient`/`persistent!`), JVM reflection, and `proxy`. (`reify` and `extend-protocol` work for Jolt protocols.)
|
- **Not implemented.** Transients (`transient`/`persistent!`), JVM reflection, and `proxy`. (`reify` and `extend-protocol` work for Jolt protocols.)
|
||||||
|
|
|
||||||
|
|
@ -2,34 +2,25 @@
|
||||||
# High-level interface for the Clojure-on-Janet interpreter.
|
# High-level interface for the Clojure-on-Janet interpreter.
|
||||||
|
|
||||||
(use ./types)
|
(use ./types)
|
||||||
|
(use ./pv)
|
||||||
(use ./reader)
|
(use ./reader)
|
||||||
(use ./evaluator)
|
(use ./evaluator)
|
||||||
(use ./core)
|
(use ./core)
|
||||||
(use ./compiler)
|
(use ./compiler)
|
||||||
(use ./loader)
|
(use ./loader)
|
||||||
|
|
||||||
(defn- load-persistent-structures
|
(defn normalize-pvecs
|
||||||
"Load immutable persistent data structures and swap clojure.core bindings."
|
"Deep-convert any sequential (pvec/tuple/array) to a Janet tuple. Test helper
|
||||||
[ctx]
|
so Janet-level `=`/deep= can compare jolt collection results against Janet
|
||||||
(def saved-ns (ctx-current-ns ctx))
|
tuple literals regardless of representation — mirroring Clojure, where vectors
|
||||||
(def source (slurp "src/jolt/clojure/lang/persistent_vector.clj"))
|
and lists with the same elements are equal."
|
||||||
(var cur source)
|
[x]
|
||||||
(while (> (length (string/trim cur)) 0)
|
(cond
|
||||||
(def [form rest] (parse-next cur))
|
(pvec? x) (tuple ;(map normalize-pvecs (pv->array x)))
|
||||||
(set cur rest)
|
(tuple? x) (tuple ;(map normalize-pvecs x))
|
||||||
(when (not (nil? form))
|
(array? x) (tuple ;(map normalize-pvecs x))
|
||||||
(eval-form ctx @{} form)))
|
x))
|
||||||
# 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
|
(defn init
|
||||||
"Create a new Jolt evaluation context.
|
"Create a new Jolt evaluation context.
|
||||||
|
|
@ -39,12 +30,11 @@
|
||||||
:compile? — enable compilation of Clojure forms to Janet"
|
:compile? — enable compilation of Clojure forms to Janet"
|
||||||
[&opt opts]
|
[&opt opts]
|
||||||
(default opts {})
|
(default opts {})
|
||||||
(let [ctx (make-ctx opts)
|
(let [ctx (make-ctx opts)]
|
||||||
mutable? (get opts :mutable?)]
|
# Collection representation (persistent vs mutable) is selected at BUILD time
|
||||||
|
# via JOLT_MUTABLE (see config.janet); init-core! registers vec/vector/conj/
|
||||||
|
# etc. that produce the mode-appropriate values, so nothing extra to load.
|
||||||
(init-core! ctx)
|
(init-core! ctx)
|
||||||
(if mutable?
|
|
||||||
nil
|
|
||||||
(load-persistent-structures ctx))
|
|
||||||
ctx))
|
ctx))
|
||||||
|
|
||||||
(defn eval-string
|
(defn eval-string
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,62 @@
|
||||||
(use ./phm)
|
(use ./phm)
|
||||||
(use ./regex)
|
(use ./regex)
|
||||||
(use ./config)
|
(use ./config)
|
||||||
|
(use ./pv)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Vector representation helpers
|
||||||
|
#
|
||||||
|
# In immutable mode a vector value is a structural-sharing persistent vector
|
||||||
|
# (pvec); in mutable mode it is a plain Janet array. Janet tuples may also still
|
||||||
|
# appear (e.g. literals that have not been routed through make-vec), so the read
|
||||||
|
# helpers below accept tuple, pvec and (mutable mode) array uniformly.
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn jvec?
|
||||||
|
"True when x is a vector VALUE. In immutable mode that is a persistent vector
|
||||||
|
or tuple; in mutable mode vectors are plain arrays (so vectors and lists share
|
||||||
|
one fast representation — `vector?` is true for both)."
|
||||||
|
[x]
|
||||||
|
(if mutable?
|
||||||
|
(or (array? x) (tuple? x))
|
||||||
|
(or (tuple? x) (pvec? x))))
|
||||||
|
|
||||||
|
(defn vcount [x] (if (pvec? x) (pv-count x) (length x)))
|
||||||
|
(defn vnth [x i] (if (pvec? x) (pv-nth x i) (in x i)))
|
||||||
|
|
||||||
|
(defn vview
|
||||||
|
"An indexed (tuple/array) view of a vector value, for iteration/slicing."
|
||||||
|
[x]
|
||||||
|
(if (pvec? x) (pv->array x) x))
|
||||||
|
|
||||||
|
(defn make-vec
|
||||||
|
"Build a vector value from a Janet array/tuple of elements, honoring the
|
||||||
|
build-time collection mode."
|
||||||
|
[xs]
|
||||||
|
(if mutable? (array ;xs) (pv-from-indexed xs)))
|
||||||
|
|
||||||
|
(defn realize-for-iteration [c]
|
||||||
|
"Normalize a seqable to a Janet array/tuple for iteration: pvec -> array,
|
||||||
|
set -> seq, lazy-seq -> realized array; others pass through. Warning: will
|
||||||
|
loop on infinite lazy-seqs. Terminates on the empty cell, not on nil."
|
||||||
|
(cond
|
||||||
|
(pvec? c) (pv->array c)
|
||||||
|
(set? c) (phs-seq c)
|
||||||
|
(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))
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Predicates
|
# Predicates
|
||||||
|
|
@ -22,10 +78,10 @@
|
||||||
(defn core-fn? [x] (or (function? x) (cfunction? x)))
|
(defn core-fn? [x] (or (function? x) (cfunction? x)))
|
||||||
(defn core-keyword? [x] (keyword? x))
|
(defn core-keyword? [x] (keyword? x))
|
||||||
(defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type))))
|
(defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type))))
|
||||||
(defn core-vector? [x] (tuple? x))
|
(defn core-vector? [x] (jvec? x))
|
||||||
(defn core-map? [x] (or (phm? x) (struct? x) (if (and (table? x) (get x :jolt/deftype)) true false)))
|
(defn core-map? [x] (or (phm? x) (struct? x) (if (and (table? x) (get x :jolt/deftype)) true false)))
|
||||||
(defn core-seq? [x] (or (array? x) (tuple? x)))
|
(defn core-seq? [x] (or (array? x) (tuple? x) (pvec? x)))
|
||||||
(defn core-coll? [x] (or (array? x) (tuple? x) (struct? x) (phm? x) (set? x) (lazy-seq? x)))
|
(defn core-coll? [x] (or (array? x) (tuple? x) (pvec? x) (struct? x) (phm? x) (set? x) (lazy-seq? x)))
|
||||||
|
|
||||||
(defn core-true? [x] (= true x))
|
(defn core-true? [x] (= true x))
|
||||||
(defn core-false? [x] (= false x))
|
(defn core-false? [x] (= false x))
|
||||||
|
|
@ -45,12 +101,14 @@
|
||||||
(if (nil? coll) true
|
(if (nil? coll) true
|
||||||
(if (set? coll) (= 0 (coll :cnt))
|
(if (set? coll) (= 0 (coll :cnt))
|
||||||
(if (phm? coll) (= 0 (coll :cnt))
|
(if (phm? coll) (= 0 (coll :cnt))
|
||||||
|
(if (pvec? coll) (= 0 (pv-count coll))
|
||||||
|
(if (lazy-seq? coll) (nil? (ls-first coll))
|
||||||
(if (struct? coll) (= 0 (length (keys coll)))
|
(if (struct? coll) (= 0 (length (keys coll)))
|
||||||
(= 0 (length coll)))))))
|
(= 0 (length coll)))))))))
|
||||||
|
|
||||||
(defn core-every? [pred coll]
|
(defn core-every? [pred coll]
|
||||||
(var result true)
|
(var result true)
|
||||||
(each x (if (set? coll) (phs-seq coll) coll)
|
(each x (realize-for-iteration coll)
|
||||||
(if (not (pred x)) (do (set result false) (break))))
|
(if (not (pred x)) (do (set result false) (break))))
|
||||||
result)
|
result)
|
||||||
|
|
||||||
|
|
@ -96,32 +154,13 @@
|
||||||
# Comparison
|
# Comparison
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
(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- eq-seqable
|
(defn- eq-seqable
|
||||||
"If x is a Clojure sequential (vector/list/lazy-seq), return its elements as
|
"If x is a Clojure sequential (vector/list/lazy-seq), return its elements as
|
||||||
an array; otherwise nil. Lets = compare across tuple/array/lazy-seq."
|
an array; otherwise nil. Lets = compare across tuple/array/lazy-seq."
|
||||||
[x]
|
[x]
|
||||||
(cond
|
(cond
|
||||||
(lazy-seq? x) (realize-for-iteration x)
|
(lazy-seq? x) (realize-for-iteration x)
|
||||||
|
(pvec? x) (pv->array x)
|
||||||
(tuple? x) x
|
(tuple? x) x
|
||||||
(array? x) x
|
(array? x) x
|
||||||
nil))
|
nil))
|
||||||
|
|
@ -192,17 +231,22 @@
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
(defn core-conj [coll & xs]
|
(defn core-conj [coll & xs]
|
||||||
|
(if (pvec? coll)
|
||||||
|
(do (var result coll) (each x xs (set result (pv-conj result x))) result)
|
||||||
(if (tuple? coll)
|
(if (tuple? coll)
|
||||||
(tuple/slice (tuple ;(array/concat (array/slice coll) xs)))
|
(tuple/slice (tuple ;(array/concat (array/slice coll) xs)))
|
||||||
(if (array? coll)
|
(if (array? coll)
|
||||||
|
(if mutable?
|
||||||
|
# mutable mode: arrays are vectors — append in place
|
||||||
|
(do (each x xs (array/push coll x)) coll)
|
||||||
|
# immutable mode: arrays are lists — prepend onto a copy
|
||||||
(do
|
(do
|
||||||
# lists prepend; copy first unless built in mutable mode
|
(var result (array/slice coll))
|
||||||
(var result (if mutable? coll (array/slice coll)))
|
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(while (< i (length xs))
|
(while (< i (length xs))
|
||||||
(set result (array/insert result 0 (xs i)))
|
(set result (array/insert result 0 (xs i)))
|
||||||
(++ i))
|
(++ i))
|
||||||
result)
|
result))
|
||||||
(if (set? coll)
|
(if (set? coll)
|
||||||
(apply phs-conj coll xs)
|
(apply phs-conj coll xs)
|
||||||
(if (phm? coll)
|
(if (phm? coll)
|
||||||
|
|
@ -211,7 +255,7 @@
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(while (< i (length xs))
|
(while (< i (length xs))
|
||||||
(let [pair (xs i)]
|
(let [pair (xs i)]
|
||||||
(set result (phm-assoc result (pair 0) (pair 1))))
|
(set result (phm-assoc result (vnth pair 0) (vnth pair 1))))
|
||||||
(++ i))
|
(++ i))
|
||||||
result)
|
result)
|
||||||
(do
|
(do
|
||||||
|
|
@ -219,14 +263,16 @@
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(while (< i (length xs))
|
(while (< i (length xs))
|
||||||
(let [pair (xs i)]
|
(let [pair (xs i)]
|
||||||
(set result (merge result {(pair 0) (pair 1)})))
|
(set result (merge result {(vnth pair 0) (vnth pair 1)})))
|
||||||
(++ i))
|
(++ i))
|
||||||
result))))))
|
result)))))))
|
||||||
|
|
||||||
(defn core-assoc [m & kvs]
|
(defn core-assoc [m & kvs]
|
||||||
(cond
|
(cond
|
||||||
(phm? m)
|
(phm? m)
|
||||||
(do (var result m) (var i 0) (while (< i (length kvs)) (set result (phm-assoc result (kvs i) (kvs (+ i 1)))) (+= i 2)) result)
|
(do (var result m) (var i 0) (while (< i (length kvs)) (set result (phm-assoc result (kvs i) (kvs (+ i 1)))) (+= i 2)) result)
|
||||||
|
(pvec? m)
|
||||||
|
(do (var result m) (var i 0) (while (< i (length kvs)) (set result (pv-assoc result (kvs i) (kvs (+ i 1)))) (+= i 2)) result)
|
||||||
# vector: assoc by integer index (appending at count is allowed); stays a vector
|
# vector: assoc by integer index (appending at count is allowed); stays a vector
|
||||||
(or (tuple? m) (array? m))
|
(or (tuple? m) (array? m))
|
||||||
(do (var result (array/slice m)) (var i 0)
|
(do (var result (array/slice m)) (var i 0)
|
||||||
|
|
@ -250,12 +296,14 @@
|
||||||
(if (nil? m) default
|
(if (nil? m) default
|
||||||
(if (set? m) (phs-get m k default)
|
(if (set? m) (phs-get m k default)
|
||||||
(if (phm? m) (phm-get m k default)
|
(if (phm? m) (phm-get m k default)
|
||||||
|
(if (pvec? m)
|
||||||
|
(if (and (number? k) (>= k 0) (< k (pv-count m))) (pv-nth m k) default)
|
||||||
(if (or (struct? m) (table? m))
|
(if (or (struct? m) (table? m))
|
||||||
(let [v (m k)]
|
(let [v (m k)]
|
||||||
(if (nil? v) default v))
|
(if (nil? v) default v))
|
||||||
(if (and (or (tuple? m) (array? m)) (number? k) (>= k 0) (< k (length m)))
|
(if (and (or (tuple? m) (array? m)) (number? k) (>= k 0) (< k (length m)))
|
||||||
(in m k)
|
(in m k)
|
||||||
default))))))
|
default)))))))
|
||||||
|
|
||||||
# Runtime invoke dispatch for COMPILED code (interpreter uses evaluator's
|
# Runtime invoke dispatch for COMPILED code (interpreter uses evaluator's
|
||||||
# jolt-invoke). Handles real functions plus Clojure IFn collections.
|
# jolt-invoke). Handles real functions plus Clojure IFn collections.
|
||||||
|
|
@ -266,6 +314,11 @@
|
||||||
(and (struct? f) (= :symbol (f :jolt/type))) (core-get (get args 0) f (get args 1))
|
(and (struct? f) (= :symbol (f :jolt/type))) (core-get (get args 0) f (get args 1))
|
||||||
(phm? f) (phm-get f (get args 0) (get args 1))
|
(phm? f) (phm-get f (get args 0) (get args 1))
|
||||||
(set? f) (if (phs-contains? f (get args 0)) (get args 0) (get args 1))
|
(set? f) (if (phs-contains? f (get args 0)) (get args 0) (get args 1))
|
||||||
|
(pvec? f)
|
||||||
|
(let [k (get args 0)]
|
||||||
|
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (pv-count f)))
|
||||||
|
(pv-nth f k)
|
||||||
|
(error (string "Index " k " out of bounds for vector of length " (pv-count f)))))
|
||||||
(or (tuple? f) (array? f))
|
(or (tuple? f) (array? f))
|
||||||
(let [k (get args 0)]
|
(let [k (get args 0)]
|
||||||
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (length f)))
|
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (length f)))
|
||||||
|
|
@ -276,8 +329,22 @@
|
||||||
(if (= v :jolt/not-found) (get args 1) v))
|
(if (= v :jolt/not-found) (get args 1) v))
|
||||||
(error (string "Cannot call " (type f) " as a function"))))
|
(error (string "Cannot call " (type f) " as a function"))))
|
||||||
|
|
||||||
|
(defn core-apply
|
||||||
|
"(apply f a b ... coll) — call f with the leading args plus the elements of
|
||||||
|
the final collection spliced in. Materializes pvec/lazy-seq/set tails."
|
||||||
|
[f & args]
|
||||||
|
(let [n (length args)]
|
||||||
|
(if (= n 0)
|
||||||
|
(jolt-call f)
|
||||||
|
(let [fixed (array/slice args 0 (- n 1))
|
||||||
|
t (in args (- n 1))
|
||||||
|
tail (cond (set? t) (phs-seq t) (phm? t) (tuple ;(phm-entries t))
|
||||||
|
(realize-for-iteration t))]
|
||||||
|
(jolt-call f ;fixed ;tail)))))
|
||||||
|
|
||||||
(defn core-get-in [m ks &opt default]
|
(defn core-get-in [m ks &opt default]
|
||||||
(default default nil)
|
(default default nil)
|
||||||
|
(def ks (vview ks))
|
||||||
(var current m)
|
(var current m)
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(while (< i (length ks))
|
(while (< i (length ks))
|
||||||
|
|
@ -289,11 +356,12 @@
|
||||||
(defn core-contains? [coll key]
|
(defn core-contains? [coll key]
|
||||||
(if (set? coll) (phs-contains? coll key)
|
(if (set? coll) (phs-contains? coll key)
|
||||||
(if (phm? coll) (let [b (get (coll :buckets) (phm-hash-key key))] (if b (phm-bucket-contains? b key) false))
|
(if (phm? coll) (let [b (get (coll :buckets) (phm-hash-key key))] (if b (phm-bucket-contains? b key) false))
|
||||||
|
(if (pvec? coll) (and (number? key) (>= key 0) (< key (pv-count coll)))
|
||||||
(if (struct? coll) (not (nil? (coll key)))
|
(if (struct? coll) (not (nil? (coll key)))
|
||||||
(if (table? coll) (not (nil? (coll key)))
|
(if (table? coll) (not (nil? (coll key)))
|
||||||
(if (or (tuple? coll) (array? coll))
|
(if (or (tuple? coll) (array? coll))
|
||||||
(and (number? key) (>= key 0) (< key (length coll)))
|
(and (number? key) (>= key 0) (< key (length coll)))
|
||||||
false))))))
|
false)))))))
|
||||||
|
|
||||||
# Sorted collections — minimal: backed by a struct (map) / sorted array (set),
|
# Sorted collections — minimal: backed by a struct (map) / sorted array (set),
|
||||||
# ordered by key/element on read. Defined early so seq/count/get can dispatch.
|
# ordered by key/element on read. Defined early so seq/count/get can dispatch.
|
||||||
|
|
@ -316,6 +384,7 @@
|
||||||
(core-sorted-map? coll) (length (keys (coll :map)))
|
(core-sorted-map? coll) (length (keys (coll :map)))
|
||||||
(core-sorted-set? coll) (length (coll :items))
|
(core-sorted-set? coll) (length (coll :items))
|
||||||
(lazy-seq? coll) (ls-count coll)
|
(lazy-seq? coll) (ls-count coll)
|
||||||
|
(pvec? coll) (pv-count coll)
|
||||||
(set? coll) (coll :cnt)
|
(set? coll) (coll :cnt)
|
||||||
(phm? coll) (coll :cnt)
|
(phm? coll) (coll :cnt)
|
||||||
(and (table? coll) (get coll :jolt/deftype)) (- (length (keys coll)) 1)
|
(and (table? coll) (get coll :jolt/deftype)) (- (length (keys coll)) 1)
|
||||||
|
|
@ -326,6 +395,7 @@
|
||||||
(core-sorted-map? coll) (let [e (sorted-map-entries coll)] (if (empty? e) nil (in e 0)))
|
(core-sorted-map? coll) (let [e (sorted-map-entries coll)] (if (empty? e) nil (in e 0)))
|
||||||
(core-sorted-set? coll) (let [i (coll :items)] (if (empty? i) nil (in i 0)))
|
(core-sorted-set? coll) (let [i (coll :items)] (if (empty? i) nil (in i 0)))
|
||||||
(lazy-seq? coll) (ls-first coll)
|
(lazy-seq? coll) (ls-first coll)
|
||||||
|
(pvec? coll) (if (= 0 (pv-count coll)) nil (pv-nth coll 0))
|
||||||
(or (nil? coll) (= 0 (length coll))) nil
|
(or (nil? coll) (= 0 (length coll))) nil
|
||||||
(string? coll) (make-char (in coll 0))
|
(string? coll) (make-char (in coll 0))
|
||||||
(in coll 0)))
|
(in coll 0)))
|
||||||
|
|
@ -333,6 +403,7 @@
|
||||||
(defn core-rest [coll]
|
(defn core-rest [coll]
|
||||||
(cond
|
(cond
|
||||||
(lazy-seq? coll) (ls-rest coll)
|
(lazy-seq? coll) (ls-rest coll)
|
||||||
|
(pvec? coll) (let [a (pv->array coll)] (if (<= (length a) 1) @[] (array/slice a 1)))
|
||||||
(or (nil? coll) (= 0 (length coll))) @[]
|
(or (nil? coll) (= 0 (length coll))) @[]
|
||||||
(string? coll) (tuple ;(map make-char (string/bytes (string/slice coll 1))))
|
(string? coll) (tuple ;(map make-char (string/bytes (string/slice coll 1))))
|
||||||
(tuple? coll) (tuple/slice coll 1)
|
(tuple? coll) (tuple/slice coll 1)
|
||||||
|
|
@ -352,6 +423,7 @@
|
||||||
(core-sorted-set? coll) (let [i (coll :items)] (if (empty? i) nil (tuple ;i)))
|
(core-sorted-set? coll) (let [i (coll :items)] (if (empty? i) nil (tuple ;i)))
|
||||||
(or (nil? coll) (and (or (tuple? coll) (array? coll)) (= 0 (length coll)))) nil
|
(or (nil? coll) (and (or (tuple? coll) (array? coll)) (= 0 (length coll)))) nil
|
||||||
(lazy-seq? coll) (ls-seq coll)
|
(lazy-seq? coll) (ls-seq coll)
|
||||||
|
(pvec? coll) (if (= 0 (pv-count coll)) nil (tuple ;(pv->array coll)))
|
||||||
(set? coll) (phs-seq coll)
|
(set? coll) (phs-seq coll)
|
||||||
(phm? coll) (tuple ;(phm-entries coll))
|
(phm? coll) (tuple ;(phm-entries coll))
|
||||||
(tuple? coll) (tuple/slice coll)
|
(tuple? coll) (tuple/slice coll)
|
||||||
|
|
@ -361,19 +433,23 @@
|
||||||
|
|
||||||
(defn core-vec [coll]
|
(defn core-vec [coll]
|
||||||
(let [coll (realize-for-iteration coll)]
|
(let [coll (realize-for-iteration coll)]
|
||||||
(if (tuple? coll) coll
|
(cond
|
||||||
(if (array? coll) (tuple ;coll)
|
(array? coll) (make-vec coll)
|
||||||
(if (struct? coll) (tuple ;(map |(in (kvs coll) (+ (* $ 2) 1)) (range (/ (length (kvs coll)) 2))))
|
(tuple? coll) (make-vec coll)
|
||||||
(if (string? coll) (tuple ;(map |(string/from-bytes $) (string/bytes coll)))
|
(struct? coll) (make-vec (map |(in (kvs coll) (+ (* $ 2) 1)) (range (/ (length (kvs coll)) 2))))
|
||||||
(tuple)))))))
|
(string? coll) (make-vec (map |(string/from-bytes $) (string/bytes coll)))
|
||||||
|
(make-vec @[]))))
|
||||||
|
|
||||||
(defn- into-conj [to items]
|
(defn- into-conj [to items]
|
||||||
(cond
|
(cond
|
||||||
(or (phm? to) (struct? to) (and (table? to) (get to :jolt/deftype)))
|
(or (phm? to) (struct? to) (and (table? to) (get to :jolt/deftype)))
|
||||||
(do (var result to)
|
(do (var result to)
|
||||||
(each item items (set result (core-assoc result (in item 0) (in item 1))))
|
(each item items (set result (core-assoc result (vnth item 0) (vnth item 1))))
|
||||||
result)
|
result)
|
||||||
(array? to) (do (var result (array/slice to)) (each x items (array/insert result 0 x)) result)
|
(pvec? to) (do (var result to) (each x items (set result (pv-conj result x))) result)
|
||||||
|
(array? to) (if mutable?
|
||||||
|
(do (each x items (array/push to x)) to) # vector: append
|
||||||
|
(do (var result (array/slice to)) (each x items (array/insert result 0 x)) result)) # list: prepend
|
||||||
(tuple? to) (tuple/slice (tuple ;(array/concat (array/slice to) (array/slice items))))
|
(tuple? to) (tuple/slice (tuple ;(array/concat (array/slice to) (array/slice items))))
|
||||||
to))
|
to))
|
||||||
|
|
||||||
|
|
@ -404,12 +480,13 @@
|
||||||
(if (struct? m) (table/to-struct result) result))
|
(if (struct? m) (table/to-struct result) result))
|
||||||
|
|
||||||
(defn core-zipmap [ks vs]
|
(defn core-zipmap [ks vs]
|
||||||
|
(let [ks (realize-for-iteration ks) vs (realize-for-iteration vs)]
|
||||||
(var result @{})
|
(var result @{})
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(while (and (< i (length ks)) (< i (length vs)))
|
(while (and (< i (length ks)) (< i (length vs)))
|
||||||
(put result (ks i) (vs i))
|
(put result (in ks i) (in vs i))
|
||||||
(++ i))
|
(++ i))
|
||||||
(table/to-struct result))
|
(table/to-struct result)))
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Transducers
|
# Transducers
|
||||||
|
|
@ -516,9 +593,9 @@
|
||||||
@[(f (core-first c)) (mstep (core-rest c))])))
|
@[(f (core-first c)) (mstep (core-rest c))])))
|
||||||
(make-lazy-seq (mstep coll)))
|
(make-lazy-seq (mstep coll)))
|
||||||
# Concrete collection: eager (preserves tuple/array representation).
|
# Concrete collection: eager (preserves tuple/array representation).
|
||||||
(let [c (if (set? coll) (phs-seq coll) coll)
|
(let [c (if (set? coll) (phs-seq coll) (realize-for-iteration coll))
|
||||||
result (do (var res @[]) (each x c (array/push res (f x))) res)]
|
result (do (var res @[]) (each x c (array/push res (f x))) res)]
|
||||||
(if (tuple? c) (tuple/slice (tuple ;result)) result))))
|
(if (jvec? coll) (make-vec result) result))))
|
||||||
# Multi-collection: lazy-seq with per-element independent state
|
# Multi-collection: lazy-seq with per-element independent state
|
||||||
(let [init-cs (array/new-filled (length colls) nil)
|
(let [init-cs (array/new-filled (length colls) nil)
|
||||||
init-idxs (array/new-filled (length colls) 0)
|
init-idxs (array/new-filled (length colls) 0)
|
||||||
|
|
@ -529,7 +606,8 @@
|
||||||
(let [c (in colls i)]
|
(let [c (in colls i)]
|
||||||
(if (lazy-seq? c)
|
(if (lazy-seq? c)
|
||||||
(put init-cs i c)
|
(put init-cs i c)
|
||||||
(do (put init-cs i nil) (put init-reals i c))))
|
(do (put init-cs i nil)
|
||||||
|
(put init-reals i (if (set? c) (phs-seq c) (realize-for-iteration c))))))
|
||||||
(++ i))
|
(++ i))
|
||||||
nil)]
|
nil)]
|
||||||
(defn step [cs idxs reals]
|
(defn step [cs idxs reals]
|
||||||
|
|
@ -582,9 +660,9 @@
|
||||||
(make-lazy-seq (fstep coll)))
|
(make-lazy-seq (fstep coll)))
|
||||||
(do
|
(do
|
||||||
(var result @[])
|
(var result @[])
|
||||||
(each x (if (set? coll) (phs-seq coll) coll)
|
(each x (if (set? coll) (phs-seq coll) (realize-for-iteration coll))
|
||||||
(if (pred x) (array/push result x)))
|
(if (pred x) (array/push result x)))
|
||||||
(if (tuple? coll) (tuple/slice (tuple ;result)) result))))))
|
(if (jvec? coll) (make-vec result) result))))))
|
||||||
|
|
||||||
(defn core-remove [pred & rest]
|
(defn core-remove [pred & rest]
|
||||||
(if (= 0 (length rest)) (td-remove pred)
|
(if (= 0 (length rest)) (td-remove pred)
|
||||||
|
|
@ -626,13 +704,13 @@
|
||||||
(set cur (ls-rest cur))
|
(set cur (ls-rest cur))
|
||||||
(++ i))
|
(++ i))
|
||||||
result)
|
result)
|
||||||
(do
|
(let [c (realize-for-iteration coll)]
|
||||||
(var result @[])
|
(var result @[])
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(while (and (< i n) (< i (length coll)))
|
(while (and (< i n) (< i (length c)))
|
||||||
(array/push result (coll i))
|
(array/push result (in c i))
|
||||||
(++ i))
|
(++ i))
|
||||||
(if (tuple? coll) (tuple/slice (tuple ;result)) result))))))
|
(if (jvec? coll) (make-vec result) result))))))
|
||||||
|
|
||||||
(defn core-drop [n & rest]
|
(defn core-drop [n & rest]
|
||||||
(if (= 0 (length rest)) (td-drop n)
|
(if (= 0 (length rest)) (td-drop n)
|
||||||
|
|
@ -645,10 +723,9 @@
|
||||||
(set cur (ls-rest cur))
|
(set cur (ls-rest cur))
|
||||||
(++ i))
|
(++ i))
|
||||||
(if (nil? (ls-first cur)) nil cur))
|
(if (nil? (ls-first cur)) nil cur))
|
||||||
(do
|
(let [c (realize-for-iteration coll)
|
||||||
(if (tuple? coll)
|
dropped (array/slice c (min n (length c)))]
|
||||||
(tuple/slice coll (min n (length coll)))
|
(if (jvec? coll) (make-vec dropped) dropped))))))
|
||||||
(array/slice coll (min n (length coll)))))))))
|
|
||||||
|
|
||||||
(defn core-take-while [pred & rest]
|
(defn core-take-while [pred & rest]
|
||||||
(if (= 0 (length rest)) (td-take-while pred)
|
(if (= 0 (length rest)) (td-take-while pred)
|
||||||
|
|
@ -663,13 +740,13 @@
|
||||||
result)
|
result)
|
||||||
(do
|
(do
|
||||||
(var result @[])
|
(var result @[])
|
||||||
(each x coll (if (pred x) (array/push result x) (break)))
|
(each x (realize-for-iteration coll) (if (pred x) (array/push result x) (break)))
|
||||||
(if (tuple? coll) (tuple/slice (tuple ;result)) result))))))
|
(if (jvec? coll) (make-vec result) result))))))
|
||||||
|
|
||||||
(defn core-drop-while [pred & rest]
|
(defn core-drop-while [pred & rest]
|
||||||
(if (= 0 (length rest)) (td-drop-while pred)
|
(if (= 0 (length rest)) (td-drop-while pred)
|
||||||
(let [coll (in rest 0)
|
(let [coll (in rest 0)
|
||||||
c (if (lazy-seq? coll) (realize-ls coll) coll)]
|
c (realize-for-iteration coll)]
|
||||||
(var start 0)
|
(var start 0)
|
||||||
(while (and (< start (length c)) (pred (c start)))
|
(while (and (< start (length c)) (pred (c start)))
|
||||||
(++ start))
|
(++ start))
|
||||||
|
|
@ -682,6 +759,7 @@
|
||||||
If the value is a function, call it and use the result.
|
If the value is a function, call it and use the result.
|
||||||
If the result is already a cell (array of [val, function]), return it directly."
|
If the result is already a cell (array of [val, function]), return it directly."
|
||||||
(if (nil? c) nil
|
(if (nil? c) nil
|
||||||
|
(if (pvec? c) (coll->cells (pv->array c))
|
||||||
(if (function? c)
|
(if (function? c)
|
||||||
(let [r (c)]
|
(let [r (c)]
|
||||||
(if (and (indexed? r) (= 2 (length r)) (function? (in r 1)))
|
(if (and (indexed? r) (= 2 (length r)) (function? (in r 1)))
|
||||||
|
|
@ -699,7 +777,7 @@
|
||||||
(if (tuple? c) (tuple/slice c 1) (array/slice c 1))
|
(if (tuple? c) (tuple/slice c 1) (array/slice c 1))
|
||||||
nil)]
|
nil)]
|
||||||
@[f (fn [] (coll->cells rest))])))
|
@[f (fn [] (coll->cells rest))])))
|
||||||
nil)))))
|
nil))))))
|
||||||
|
|
||||||
(defn core-concat [& colls]
|
(defn core-concat [& colls]
|
||||||
"Truly lazy concatenation. `step` returns a 0-arg thunk that is only forced
|
"Truly lazy concatenation. `step` returns a 0-arg thunk that is only forced
|
||||||
|
|
@ -724,6 +802,31 @@
|
||||||
(array/insert remaining 0 rest-fn)))]))))))
|
(array/insert remaining 0 rest-fn)))]))))))
|
||||||
(make-lazy-seq (step (if (tuple? colls) (array/slice colls) colls))))
|
(make-lazy-seq (step (if (tuple? colls) (array/slice colls) colls))))
|
||||||
|
|
||||||
|
(defn core-mapcat
|
||||||
|
"(mapcat f & colls) — map then concat. (mapcat f) returns a transducer."
|
||||||
|
[f & colls]
|
||||||
|
(if (= 0 (length colls))
|
||||||
|
# transducer: map f over each input, then splice (cat) the result
|
||||||
|
(fn [rf]
|
||||||
|
(fn [& a]
|
||||||
|
(case (length a)
|
||||||
|
0 (rf)
|
||||||
|
1 (rf (a 0))
|
||||||
|
(do (var acc (a 0))
|
||||||
|
(each x (realize-for-iteration (f (a 1)))
|
||||||
|
(set acc (rf acc x)))
|
||||||
|
acc))))
|
||||||
|
# map, then concat; a non-seqable result counts as a single element (this
|
||||||
|
# leniency is what jolt's `for` expansion relies on for :let on the last
|
||||||
|
# binding, whose body yields a scalar rather than a seq).
|
||||||
|
(let [mapped (realize-for-iteration (core-apply core-map f colls))
|
||||||
|
seqs (map (fn [item]
|
||||||
|
(if (or (tuple? item) (array? item) (pvec? item)
|
||||||
|
(lazy-seq? item) (set? item))
|
||||||
|
item (tuple item)))
|
||||||
|
mapped)]
|
||||||
|
(core-apply core-concat seqs))))
|
||||||
|
|
||||||
(defn core-reverse [coll]
|
(defn core-reverse [coll]
|
||||||
(if (nil? coll) @[]
|
(if (nil? coll) @[]
|
||||||
(if (lazy-seq? coll)
|
(if (lazy-seq? coll)
|
||||||
|
|
@ -739,17 +842,21 @@
|
||||||
(array/push reversed (in result i))
|
(array/push reversed (in result i))
|
||||||
(-- i))
|
(-- i))
|
||||||
reversed)
|
reversed)
|
||||||
(do
|
(let [c (realize-for-iteration coll)]
|
||||||
(var result @[])
|
(var result @[])
|
||||||
(var i (dec (length coll)))
|
(var i (dec (length c)))
|
||||||
(while (>= i 0)
|
(while (>= i 0)
|
||||||
(array/push result (coll i))
|
(array/push result (in c i))
|
||||||
(-- i))
|
(-- i))
|
||||||
(if (tuple? coll) (tuple/slice (tuple ;result)) result)))))
|
result))))
|
||||||
|
|
||||||
(defn core-nth
|
(defn core-nth
|
||||||
"Return the nth element of a sequential collection."
|
"Return the nth element of a sequential collection."
|
||||||
[coll idx &opt default]
|
[coll idx &opt default]
|
||||||
|
(if (pvec? coll)
|
||||||
|
(if (and (>= idx 0) (< idx (pv-count coll)))
|
||||||
|
(pv-nth coll idx)
|
||||||
|
(if (nil? default) (error (string "Index " idx " out of bounds, length: " (pv-count coll))) default))
|
||||||
(if (lazy-seq? coll)
|
(if (lazy-seq? coll)
|
||||||
(do
|
(do
|
||||||
(var cur coll)
|
(var cur coll)
|
||||||
|
|
@ -762,12 +869,12 @@
|
||||||
(error (string "Index " idx " out of bounds"))
|
(error (string "Index " idx " out of bounds"))
|
||||||
default)))
|
default)))
|
||||||
(do
|
(do
|
||||||
(var c (if (lazy-seq? coll) (realize-ls coll) coll))
|
(var c (realize-for-iteration coll))
|
||||||
(if (and (>= idx 0) (< idx (length c)))
|
(if (and (>= idx 0) (< idx (length c)))
|
||||||
(if (string? c) (make-char (in c idx)) (in c idx))
|
(if (string? c) (make-char (in c idx)) (in c idx))
|
||||||
(if (nil? default)
|
(if (nil? default)
|
||||||
(error (string "Index " idx " out of bounds, length: " (length c)))
|
(error (string "Index " idx " out of bounds, length: " (length c)))
|
||||||
default)))))
|
default))))))
|
||||||
|
|
||||||
(defn core-sort
|
(defn core-sort
|
||||||
"(sort coll) or (sort comparator coll). Comparator may return a boolean or a
|
"(sort coll) or (sort comparator coll). Comparator may return a boolean or a
|
||||||
|
|
@ -785,7 +892,7 @@
|
||||||
|
|
||||||
(defn core-sort-by [keyfn coll]
|
(defn core-sort-by [keyfn coll]
|
||||||
(if (nil? coll) (break @[]))
|
(if (nil? coll) (break @[]))
|
||||||
(var c (if (lazy-seq? coll) (realize-ls coll) coll))
|
(var c (realize-for-iteration coll))
|
||||||
(let [arr (if (tuple? c) (array/slice c) c)
|
(let [arr (if (tuple? c) (array/slice c) c)
|
||||||
sorted (sort-by keyfn arr)]
|
sorted (sort-by keyfn arr)]
|
||||||
(if (tuple? c) (tuple/slice (tuple ;sorted)) sorted)))
|
(if (tuple? c) (tuple/slice (tuple ;sorted)) sorted)))
|
||||||
|
|
@ -806,14 +913,14 @@
|
||||||
(do
|
(do
|
||||||
(var seen @{})
|
(var seen @{})
|
||||||
(var result @[])
|
(var result @[])
|
||||||
(each x coll
|
(each x (realize-for-iteration coll)
|
||||||
(if (nil? (seen x))
|
(if (nil? (seen x))
|
||||||
(do (put seen x true) (array/push result x))))
|
(do (put seen x true) (array/push result x))))
|
||||||
(if (tuple? coll) (tuple/slice (tuple ;result)) result)))))
|
(if (jvec? coll) (make-vec result) result)))))
|
||||||
|
|
||||||
(defn core-group-by [f coll]
|
(defn core-group-by [f coll]
|
||||||
(var result @{})
|
(var result @{})
|
||||||
(var c (if (lazy-seq? coll) (realize-ls coll) coll))
|
(var c (realize-for-iteration coll))
|
||||||
(each x c
|
(each x c
|
||||||
(let [k (f x)]
|
(let [k (f x)]
|
||||||
(put result k (array/push (core-get result k @[]) x))))
|
(put result k (array/push (core-get result k @[]) x))))
|
||||||
|
|
@ -844,7 +951,7 @@
|
||||||
(var result @[])
|
(var result @[])
|
||||||
(var part @[])
|
(var part @[])
|
||||||
(var last-k nil)
|
(var last-k nil)
|
||||||
(each x coll
|
(each x (realize-for-iteration coll)
|
||||||
(let [k (f x)]
|
(let [k (f x)]
|
||||||
(if (and last-k (deep= k last-k))
|
(if (and last-k (deep= k last-k))
|
||||||
(array/push part x)
|
(array/push part x)
|
||||||
|
|
@ -923,6 +1030,7 @@
|
||||||
(cond
|
(cond
|
||||||
(nil? coll) nil
|
(nil? coll) nil
|
||||||
(lazy-seq? coll) (ls-first coll)
|
(lazy-seq? coll) (ls-first coll)
|
||||||
|
(pvec? coll) (if (= 0 (pv-count coll)) nil (pv-nth coll (- (pv-count coll) 1))) # vector: last
|
||||||
(= 0 (length coll)) nil
|
(= 0 (length coll)) nil
|
||||||
(tuple? coll) (in coll (- (length coll) 1)) # vector: last
|
(tuple? coll) (in coll (- (length coll) 1)) # vector: last
|
||||||
(array? coll) (in coll 0) # list: first
|
(array? coll) (in coll 0) # list: first
|
||||||
|
|
@ -931,12 +1039,14 @@
|
||||||
(defn core-pop [coll]
|
(defn core-pop [coll]
|
||||||
(cond
|
(cond
|
||||||
(nil? coll) nil
|
(nil? coll) nil
|
||||||
|
(pvec? coll) (pv-pop coll) # vector: drop last
|
||||||
(tuple? coll) (tuple/slice coll 0 (- (length coll) 1)) # vector: drop last
|
(tuple? coll) (tuple/slice coll 0 (- (length coll) 1)) # vector: drop last
|
||||||
(array? coll) (array/slice coll 1) # list: rest
|
(array? coll) (array/slice coll 1) # list: rest
|
||||||
coll))
|
coll))
|
||||||
|
|
||||||
(defn core-subvec [v start &opt end]
|
(defn core-subvec [v start &opt end]
|
||||||
(tuple/slice v start (if (nil? end) (length v) end)))
|
(let [a (vview v)]
|
||||||
|
(make-vec (tuple/slice a start (if (nil? end) (length a) end)))))
|
||||||
|
|
||||||
(defn core-trampoline [f & args]
|
(defn core-trampoline [f & args]
|
||||||
(var result (apply f args))
|
(var result (apply f args))
|
||||||
|
|
@ -1050,7 +1160,7 @@
|
||||||
# Collection constructors
|
# Collection constructors
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
(defn core-vector [& xs] (tuple ;xs))
|
(defn core-vector [& xs] (make-vec xs))
|
||||||
(defn core-hash-map [& kvs] (make-phm kvs))
|
(defn core-hash-map [& kvs] (make-phm kvs))
|
||||||
|
|
||||||
(defn core-array-map [& kvs]
|
(defn core-array-map [& kvs]
|
||||||
|
|
@ -1084,7 +1194,7 @@
|
||||||
concat-form)
|
concat-form)
|
||||||
|
|
||||||
(defn core-set [coll]
|
(defn core-set [coll]
|
||||||
(apply core-hash-set (if (tuple? coll) (array/slice coll) coll)))
|
(apply core-hash-set (realize-for-iteration coll)))
|
||||||
|
|
||||||
(defn core-list [& xs]
|
(defn core-list [& xs]
|
||||||
(array ;xs))
|
(array ;xs))
|
||||||
|
|
@ -1140,9 +1250,11 @@
|
||||||
(lazy-seq? v) (pr-render-seq buf (realize-for-iteration v) "(" ")")
|
(lazy-seq? v) (pr-render-seq buf (realize-for-iteration v) "(" ")")
|
||||||
(set? v) (pr-render-seq buf (phs-seq v) "#{" "}")
|
(set? v) (pr-render-seq buf (phs-seq v) "#{" "}")
|
||||||
(phm? v) (pr-render-pairs buf (phm-entries v))
|
(phm? v) (pr-render-pairs buf (phm-entries v))
|
||||||
|
(pvec? v) (pr-render-seq buf (pv->array v) "[" "]")
|
||||||
(and (table? v) (get v :jolt/deftype)) (buffer/push-string buf (string v))
|
(and (table? v) (get v :jolt/deftype)) (buffer/push-string buf (string v))
|
||||||
(tuple? v) (pr-render-seq buf v "[" "]")
|
(tuple? v) (pr-render-seq buf v "[" "]")
|
||||||
(array? v) (pr-render-seq buf v "(" ")")
|
# mutable mode: arrays are vectors -> print with [] (else lists -> ())
|
||||||
|
(array? v) (if mutable? (pr-render-seq buf v "[" "]") (pr-render-seq buf v "(" ")"))
|
||||||
(struct? v) (pr-render-pairs buf (pairs v))
|
(struct? v) (pr-render-pairs buf (pairs v))
|
||||||
(table? v) (pr-render-pairs buf (pairs v))
|
(table? v) (pr-render-pairs buf (pairs v))
|
||||||
true (buffer/push-string buf (string v)))))
|
true (buffer/push-string buf (string v)))))
|
||||||
|
|
@ -1259,7 +1371,7 @@
|
||||||
(def core-int-array (fn [size] (array/new-filled size 0)))
|
(def core-int-array (fn [size] (array/new-filled size 0)))
|
||||||
(def core-to-array (fn [coll]
|
(def core-to-array (fn [coll]
|
||||||
(def arr @[])
|
(def arr @[])
|
||||||
(each x coll (array/push arr x))
|
(each x (realize-for-iteration coll) (array/push arr x))
|
||||||
arr))
|
arr))
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
@ -2094,14 +2206,14 @@
|
||||||
(if (tuple? ks) (tuple/slice ks 1) (array/slice ks 1)))
|
(if (tuple? ks) (tuple/slice ks 1) (array/slice ks 1)))
|
||||||
|
|
||||||
(defn core-assoc-in [m ks v]
|
(defn core-assoc-in [m ks v]
|
||||||
(let [k (in ks 0)]
|
(let [ks (vview ks) k (in ks 0)]
|
||||||
(if (<= (length ks) 1)
|
(if (<= (length ks) 1)
|
||||||
(core-assoc m k v)
|
(core-assoc m k v)
|
||||||
(let [sub (core-get m k)]
|
(let [sub (core-get m k)]
|
||||||
(core-assoc m k (core-assoc-in (if (nil? sub) {} sub) (ks-rest ks) v))))))
|
(core-assoc m k (core-assoc-in (if (nil? sub) {} sub) (ks-rest ks) v))))))
|
||||||
|
|
||||||
(defn core-update-in [m ks f & args]
|
(defn core-update-in [m ks f & args]
|
||||||
(let [k (in ks 0)]
|
(let [ks (vview ks) k (in ks 0)]
|
||||||
(if (<= (length ks) 1)
|
(if (<= (length ks) 1)
|
||||||
(core-assoc m k (apply f (core-get m k) args))
|
(core-assoc m k (apply f (core-get m k) args))
|
||||||
(let [sub (core-get m k)]
|
(let [sub (core-get m k)]
|
||||||
|
|
@ -2318,7 +2430,7 @@
|
||||||
|
|
||||||
(defn core-filterv [pred coll]
|
(defn core-filterv [pred coll]
|
||||||
(let [r @[]] (each x (realize-for-iteration coll) (when (truthy? (pred x)) (array/push r x)))
|
(let [r @[]] (each x (realize-for-iteration coll) (when (truthy? (pred x)) (array/push r x)))
|
||||||
(tuple/slice (tuple ;r))))
|
(make-vec r)))
|
||||||
|
|
||||||
(defn core-mapv [f & colls]
|
(defn core-mapv [f & colls]
|
||||||
(let [r @[]]
|
(let [r @[]]
|
||||||
|
|
@ -2327,14 +2439,59 @@
|
||||||
(let [cs (map realize-for-iteration colls)
|
(let [cs (map realize-for-iteration colls)
|
||||||
n (min ;(map length cs))]
|
n (min ;(map length cs))]
|
||||||
(var i 0) (while (< i n) (array/push r (apply f (map (fn [c] (in c i)) cs))) (++ i))))
|
(var i 0) (while (< i n) (array/push r (apply f (map (fn [c] (in c i)) cs))) (++ i))))
|
||||||
(tuple/slice (tuple ;r))))
|
(make-vec r)))
|
||||||
|
|
||||||
|
(defn core-interpose [sep coll]
|
||||||
|
(let [items (realize-for-iteration coll) r @[]]
|
||||||
|
(var first? true)
|
||||||
|
(each x items (if first? (set first? false) (array/push r sep)) (array/push r x))
|
||||||
|
(tuple ;r)))
|
||||||
|
|
||||||
|
(defn core-some-search
|
||||||
|
"(some pred coll) — first truthy (pred x), else nil."
|
||||||
|
[pred coll]
|
||||||
|
(var result nil)
|
||||||
|
(each x (realize-for-iteration coll)
|
||||||
|
(let [r (pred x)] (when (truthy? r) (set result r) (break))))
|
||||||
|
result)
|
||||||
|
|
||||||
|
(defn core-keep
|
||||||
|
"(keep f coll) — (f x) for each x, dropping nils. (keep f) is a transducer."
|
||||||
|
[f & rest]
|
||||||
|
(if (= 0 (length rest))
|
||||||
|
(td-keep f)
|
||||||
|
(let [r @[]]
|
||||||
|
(each x (realize-for-iteration (in rest 0))
|
||||||
|
(let [v (f x)] (when (not (nil? v)) (array/push r v))))
|
||||||
|
(tuple ;r))))
|
||||||
|
|
||||||
|
(defn core-interleave
|
||||||
|
"(interleave & colls) — take one from each in turn until the shortest ends."
|
||||||
|
[& colls]
|
||||||
|
(if (= 0 (length colls)) (tuple)
|
||||||
|
(let [cs (map realize-for-iteration colls)
|
||||||
|
n (min ;(map length cs))
|
||||||
|
r @[]]
|
||||||
|
(var i 0)
|
||||||
|
(while (< i n) (each c cs (array/push r (in c i))) (++ i))
|
||||||
|
(tuple ;r))))
|
||||||
|
|
||||||
|
(defn core-flatten
|
||||||
|
"(flatten coll) — fully flatten nested sequentials into one seq."
|
||||||
|
[coll]
|
||||||
|
(def r @[])
|
||||||
|
(defn seqish? [x] (or (tuple? x) (array? x) (pvec? x) (lazy-seq? x)))
|
||||||
|
(defn step [x] (each e (realize-for-iteration x) (if (seqish? e) (step e) (array/push r e))))
|
||||||
|
(when (seqish? coll) (step coll))
|
||||||
|
(tuple ;r))
|
||||||
|
|
||||||
(defn core-empty [coll]
|
(defn core-empty [coll]
|
||||||
(cond
|
(cond
|
||||||
(phm? coll) (make-phm)
|
(phm? coll) (make-phm)
|
||||||
(set? coll) (make-phs)
|
(set? coll) (make-phs)
|
||||||
|
(pvec? coll) (make-vec @[])
|
||||||
(struct? coll) (struct)
|
(struct? coll) (struct)
|
||||||
(tuple? coll) []
|
(tuple? coll) (make-vec @[])
|
||||||
(array? coll) @[]
|
(array? coll) @[]
|
||||||
(table? coll) @{}
|
(table? coll) @{}
|
||||||
nil))
|
nil))
|
||||||
|
|
@ -2366,12 +2523,12 @@
|
||||||
(each p preds (each x xs (when (and (nil? hit) (truthy? (p x))) (set hit (p x)))))
|
(each p preds (each x xs (when (and (nil? hit) (truthy? (p x))) (set hit (p x)))))
|
||||||
hit))
|
hit))
|
||||||
|
|
||||||
(defn core-sequential? [x] (or (tuple? x) (array? x) (lazy-seq? x)))
|
(defn core-sequential? [x] (or (tuple? x) (array? x) (pvec? x) (lazy-seq? x)))
|
||||||
(defn core-associative? [x] (or (phm? x) (struct? x) (tuple? x) (array? x) (and (table? x) (not (set? x)))))
|
(defn core-associative? [x] (or (phm? x) (struct? x) (tuple? x) (array? x) (pvec? x) (and (table? x) (not (set? x)))))
|
||||||
(defn core-ifn? [x]
|
(defn core-ifn? [x]
|
||||||
(or (function? x) (cfunction? x) (keyword? x) (phm? x) (set? x) (tuple? x) (array? x)
|
(or (function? x) (cfunction? x) (keyword? x) (phm? x) (set? x) (tuple? x) (array? x) (pvec? x)
|
||||||
(and (struct? x) (= :symbol (x :jolt/type)))))
|
(and (struct? x) (= :symbol (x :jolt/type)))))
|
||||||
(defn core-indexed? [x] (or (tuple? x) (array? x)))
|
(defn core-indexed? [x] (or (tuple? x) (array? x) (pvec? x)))
|
||||||
|
|
||||||
(defn core-distinct? [& xs]
|
(defn core-distinct? [& xs]
|
||||||
(var seen @{}) (var ok true)
|
(var seen @{}) (var ok true)
|
||||||
|
|
@ -2514,6 +2671,13 @@
|
||||||
"filter" core-filter
|
"filter" core-filter
|
||||||
"remove" core-remove
|
"remove" core-remove
|
||||||
"reduce" core-reduce
|
"reduce" core-reduce
|
||||||
|
"apply" core-apply
|
||||||
|
"interpose" core-interpose
|
||||||
|
"mapcat" core-mapcat
|
||||||
|
"some" core-some-search
|
||||||
|
"keep" core-keep
|
||||||
|
"interleave" core-interleave
|
||||||
|
"flatten" core-flatten
|
||||||
"every-pred" core-every-pred
|
"every-pred" core-every-pred
|
||||||
"find" core-find
|
"find" core-find
|
||||||
"transduce" core-transduce
|
"transduce" core-transduce
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
(use ./types)
|
(use ./types)
|
||||||
(use ./phm)
|
(use ./phm)
|
||||||
|
(use ./pv)
|
||||||
|
(use ./config)
|
||||||
(use ./reader)
|
(use ./reader)
|
||||||
(use ./regex)
|
(use ./regex)
|
||||||
|
|
||||||
|
|
@ -36,6 +38,9 @@
|
||||||
(cond
|
(cond
|
||||||
(phm? coll) (phm-get coll k default)
|
(phm? coll) (phm-get coll k default)
|
||||||
(set? coll) (if (phs-contains? coll k) k default)
|
(set? coll) (if (phs-contains? coll k) k default)
|
||||||
|
(pvec? coll)
|
||||||
|
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (pv-count coll)))
|
||||||
|
(pv-nth coll k) default)
|
||||||
(or (tuple? coll) (array? coll))
|
(or (tuple? coll) (array? coll))
|
||||||
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (length coll)))
|
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (length coll)))
|
||||||
(in coll k) default)
|
(in coll k) default)
|
||||||
|
|
@ -57,6 +62,11 @@
|
||||||
(coll-lookup (get args 0) f (get args 1))
|
(coll-lookup (get args 0) f (get args 1))
|
||||||
(phm? f) (phm-get f (get args 0) (get args 1))
|
(phm? f) (phm-get f (get args 0) (get args 1))
|
||||||
(set? f) (if (phs-contains? f (get args 0)) (get args 0) (get args 1))
|
(set? f) (if (phs-contains? f (get args 0)) (get args 0) (get args 1))
|
||||||
|
(pvec? f)
|
||||||
|
(let [k (get args 0)]
|
||||||
|
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (pv-count f)))
|
||||||
|
(pv-nth f k)
|
||||||
|
(error (string "Index " k " out of bounds for vector of length " (pv-count f)))))
|
||||||
(or (tuple? f) (array? f))
|
(or (tuple? f) (array? f))
|
||||||
(let [k (get args 0)]
|
(let [k (get args 0)]
|
||||||
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (length f)))
|
(if (and (number? k) (= k (math/floor k)) (>= k 0) (< k (length f)))
|
||||||
|
|
@ -114,14 +124,16 @@
|
||||||
(do (var result @[]) (var i 0) (while (< i (length form))
|
(do (var result @[]) (var i 0) (while (< i (length form))
|
||||||
(let [item (in form i)]
|
(let [item (in form i)]
|
||||||
(if (and (array? item) (> (length item) 0) (sym-name? (first item) "unquote-splicing"))
|
(if (and (array? item) (> (length item) 0) (sym-name? (first item) "unquote-splicing"))
|
||||||
(each v (eval-form ctx bindings (in item 1)) (array/push result v))
|
(let [sv (eval-form ctx bindings (in item 1))]
|
||||||
|
(each v (if (pvec? sv) (pv->array sv) sv) (array/push result v)))
|
||||||
(array/push result (syntax-quote* ctx bindings item gsmap))))
|
(array/push result (syntax-quote* ctx bindings item gsmap))))
|
||||||
(++ i)) (tuple ;result))
|
(++ i)) (tuple ;result))
|
||||||
(array? form)
|
(array? form)
|
||||||
(do (var result @[]) (var i 0) (while (< i (length form))
|
(do (var result @[]) (var i 0) (while (< i (length form))
|
||||||
(let [item (in form i)]
|
(let [item (in form i)]
|
||||||
(if (and (array? item) (> (length item) 0) (sym-name? (first item) "unquote-splicing"))
|
(if (and (array? item) (> (length item) 0) (sym-name? (first item) "unquote-splicing"))
|
||||||
(each v (eval-form ctx bindings (in item 1)) (array/push result v))
|
(let [sv (eval-form ctx bindings (in item 1))]
|
||||||
|
(each v (if (pvec? sv) (pv->array sv) sv) (array/push result v)))
|
||||||
(array/push result (syntax-quote* ctx bindings item gsmap))))
|
(array/push result (syntax-quote* ctx bindings item gsmap))))
|
||||||
(++ i)) result)
|
(++ i)) result)
|
||||||
(and (struct? form) (get form :jolt/type)) form
|
(and (struct? form) (get form :jolt/type)) form
|
||||||
|
|
@ -361,6 +373,7 @@
|
||||||
(defn- d-realize
|
(defn- d-realize
|
||||||
"Realize a lazy-seq to an array for positional destructuring; pass others through."
|
"Realize a lazy-seq to an array for positional destructuring; pass others through."
|
||||||
[val]
|
[val]
|
||||||
|
(if (pvec? val) (pv->array val)
|
||||||
(if (lazy-seq? val)
|
(if (lazy-seq? val)
|
||||||
(do
|
(do
|
||||||
(var items @[]) (var cur val) (var go true)
|
(var items @[]) (var cur val) (var go true)
|
||||||
|
|
@ -372,7 +385,7 @@
|
||||||
(let [rt (in cell 1)]
|
(let [rt (in cell 1)]
|
||||||
(if (nil? rt) (set go false) (set cur (make-lazy-seq rt))))))))
|
(if (nil? rt) (set go false) (set cur (make-lazy-seq rt))))))))
|
||||||
items)
|
items)
|
||||||
val))
|
val)))
|
||||||
|
|
||||||
(defn- d-get
|
(defn- d-get
|
||||||
"Look up key k in a map-like value (phm/struct/table/nil)."
|
"Look up key k in a map-like value (phm/struct/table/nil)."
|
||||||
|
|
@ -497,7 +510,7 @@
|
||||||
(keyword? obj) ["Keyword" "Object"]
|
(keyword? obj) ["Keyword" "Object"]
|
||||||
(and (struct? obj) (= :jolt/char (get obj :jolt/type))) ["Character" "Object"]
|
(and (struct? obj) (= :jolt/char (get obj :jolt/type))) ["Character" "Object"]
|
||||||
(and (struct? obj) (= :symbol (get obj :jolt/type))) ["Symbol" "Object"]
|
(and (struct? obj) (= :symbol (get obj :jolt/type))) ["Symbol" "Object"]
|
||||||
(or (tuple? obj) (array? obj)) ["PersistentVector" "IPersistentVector" "IPersistentCollection" "ISeq" "Object"]
|
(or (tuple? obj) (array? obj) (pvec? obj)) ["PersistentVector" "IPersistentVector" "IPersistentCollection" "ISeq" "Object"]
|
||||||
(or (function? obj) (cfunction? obj)) ["IFn" "Fn" "Object"]
|
(or (function? obj) (cfunction? obj)) ["IFn" "Fn" "Object"]
|
||||||
(nil? obj) ["nil" "Object"]
|
(nil? obj) ["nil" "Object"]
|
||||||
["Object"]))
|
["Object"]))
|
||||||
|
|
@ -667,8 +680,9 @@
|
||||||
(set i (+ i 1)))
|
(set i (+ i 1)))
|
||||||
(do (set result clause) (++ i)))))))
|
(do (set result clause) (++ i)))))))
|
||||||
result)
|
result)
|
||||||
"require" (let [spec (eval-form ctx bindings (in form 1))]
|
"require" (let [spec0 (eval-form ctx bindings (in form 1))
|
||||||
(if (and (tuple? spec) (> (length spec) 0))
|
spec (if (pvec? spec0) (pv->array spec0) spec0)]
|
||||||
|
(if (and (indexed? spec) (> (length spec) 0))
|
||||||
(eval-require ctx spec)
|
(eval-require ctx spec)
|
||||||
(error "require expects a vector spec")))
|
(error "require expects a vector spec")))
|
||||||
"all-ns" (all-ns ctx)
|
"all-ns" (all-ns ctx)
|
||||||
|
|
@ -997,7 +1011,7 @@
|
||||||
"clojure.lang.Volatile" (and (table? val) (= :jolt/volatile (val :jolt/type)))
|
"clojure.lang.Volatile" (and (table? val) (= :jolt/volatile (val :jolt/type)))
|
||||||
"clojure.lang.Delay" (and (table? val) (= :jolt/delay (val :jolt/type)))
|
"clojure.lang.Delay" (and (table? val) (= :jolt/delay (val :jolt/type)))
|
||||||
"clojure.lang.IPersistentMap" (or (phm? val) (struct? val))
|
"clojure.lang.IPersistentMap" (or (phm? val) (struct? val))
|
||||||
"clojure.lang.IPersistentVector" (tuple? val)
|
"clojure.lang.IPersistentVector" (or (tuple? val) (pvec? val))
|
||||||
"clojure.lang.IPersistentSet" (set? val)
|
"clojure.lang.IPersistentSet" (set? val)
|
||||||
"Object" true
|
"Object" true
|
||||||
false)))
|
false)))
|
||||||
|
|
@ -1203,7 +1217,9 @@
|
||||||
(keyword? form) form
|
(keyword? form) form
|
||||||
(bytes? form) form
|
(bytes? form) form
|
||||||
(buffer? form) form
|
(buffer? form) form
|
||||||
(tuple? form) (tuple/slice (map |(eval-form ctx bindings $) form))
|
(tuple? form)
|
||||||
|
(let [els (map |(eval-form ctx bindings $) form)]
|
||||||
|
(if mutable? (array ;els) (pv-from-indexed els)))
|
||||||
(struct? form)
|
(struct? form)
|
||||||
(if (= :symbol (form :jolt/type))
|
(if (= :symbol (form :jolt/type))
|
||||||
(resolve-sym ctx bindings form)
|
(resolve-sym ctx bindings form)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
(use ./api)
|
(use ./api)
|
||||||
(use ./types)
|
(use ./types)
|
||||||
(use ./phm)
|
(use ./phm)
|
||||||
|
(use ./pv)
|
||||||
|
(use ./config)
|
||||||
(use ./reader)
|
(use ./reader)
|
||||||
|
|
||||||
(def ctx (init))
|
(def ctx (init))
|
||||||
|
|
@ -23,6 +25,17 @@
|
||||||
|
|
||||||
(defn- write-collection [v buf]
|
(defn- write-collection [v buf]
|
||||||
(cond
|
(cond
|
||||||
|
(pvec? v)
|
||||||
|
(do
|
||||||
|
(push-str buf "[")
|
||||||
|
(let [a (pv->array v) n (pv-count v)]
|
||||||
|
(var i 0)
|
||||||
|
(while (< i n)
|
||||||
|
(write-value (in a i) buf)
|
||||||
|
(when (< (+ i 1) n) (push-str buf " "))
|
||||||
|
(++ i)))
|
||||||
|
(push-str buf "]"))
|
||||||
|
|
||||||
(tuple? v)
|
(tuple? v)
|
||||||
(do
|
(do
|
||||||
(push-str buf "[")
|
(push-str buf "[")
|
||||||
|
|
@ -57,14 +70,15 @@
|
||||||
|
|
||||||
(array? v)
|
(array? v)
|
||||||
(do
|
(do
|
||||||
(push-str buf "(")
|
# mutable mode: arrays are vectors -> [] ; immutable: arrays are lists -> ()
|
||||||
|
(push-str buf (if mutable? "[" "("))
|
||||||
(var i 0)
|
(var i 0)
|
||||||
(let [n (length v)]
|
(let [n (length v)]
|
||||||
(while (< i n)
|
(while (< i n)
|
||||||
(write-value (in v i) buf)
|
(write-value (in v i) buf)
|
||||||
(when (< (+ i 1) n) (push-str buf " "))
|
(when (< (+ i 1) n) (push-str buf " "))
|
||||||
(++ i)))
|
(++ i)))
|
||||||
(push-str buf ")"))
|
(push-str buf (if mutable? "]" ")")))
|
||||||
|
|
||||||
(and (table? v) (= :jolt/set (v :jolt/type)))
|
(and (table? v) (= :jolt/set (v :jolt/type)))
|
||||||
(do
|
(do
|
||||||
|
|
|
||||||
159
src/jolt/pv.janet
Normal file
159
src/jolt/pv.janet
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
# Persistent vector — a 32-way branching trie with a tail buffer, modeled on
|
||||||
|
# Clojure's PersistentVector. Immutable: every update returns a new vector that
|
||||||
|
# structurally shares unchanged subtrees with the old one, so conj/assoc/pop are
|
||||||
|
# O(log32 n) and share memory instead of copying the whole vector.
|
||||||
|
#
|
||||||
|
# Layout:
|
||||||
|
# @{:jolt/type :jolt/pvec
|
||||||
|
# :cnt n number of elements
|
||||||
|
# :shift s bits to shift the index for the root level (5 * depth)
|
||||||
|
# :root node trie root: a tuple of up to 32 children
|
||||||
|
# :tail tail} a tuple of up to 32 trailing elements (append fast-path)
|
||||||
|
#
|
||||||
|
# Trie nodes are immutable tuples so unchanged subtrees are shared by identity.
|
||||||
|
|
||||||
|
(def- bits 5)
|
||||||
|
(def- width 32) # 2^bits
|
||||||
|
(def- mask 31) # width - 1
|
||||||
|
|
||||||
|
(def empty-node [])
|
||||||
|
|
||||||
|
(defn pvec? [x]
|
||||||
|
(and (table? x) (= :jolt/pvec (get x :jolt/type))))
|
||||||
|
|
||||||
|
(defn make-pv [cnt shift root tail]
|
||||||
|
@{:jolt/type :jolt/pvec :cnt cnt :shift shift :root root :tail tail})
|
||||||
|
|
||||||
|
(def EMPTY (make-pv 0 bits empty-node []))
|
||||||
|
|
||||||
|
(defn pv-count [pv] (get pv :cnt))
|
||||||
|
|
||||||
|
# Index of the first element held in the tail (everything before lives in the trie).
|
||||||
|
(defn- tail-offset [cnt]
|
||||||
|
(if (< cnt width) 0 (blshift (brshift (- cnt 1) bits) bits)))
|
||||||
|
|
||||||
|
# Return the 32-element leaf array containing index i.
|
||||||
|
(defn- leaf-for [pv i]
|
||||||
|
(if (>= i (tail-offset (get pv :cnt)))
|
||||||
|
(get pv :tail)
|
||||||
|
(do
|
||||||
|
(var node (get pv :root))
|
||||||
|
(var level (get pv :shift))
|
||||||
|
(while (> level 0)
|
||||||
|
(set node (get node (band (brshift i level) mask)))
|
||||||
|
(set level (- level bits)))
|
||||||
|
node)))
|
||||||
|
|
||||||
|
(defn pv-nth [pv i &opt dflt]
|
||||||
|
(if (and (>= i 0) (< i (get pv :cnt)))
|
||||||
|
(get (leaf-for pv i) (band i mask))
|
||||||
|
dflt))
|
||||||
|
|
||||||
|
# --- conj -------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Push the full tail down into the trie, returning a new root node array.
|
||||||
|
(defn- push-tail [level parent tail cnt]
|
||||||
|
(def sub-idx (band (brshift (- cnt 1) level) mask))
|
||||||
|
(def child
|
||||||
|
(if (= level bits)
|
||||||
|
tail
|
||||||
|
(let [c (get parent sub-idx)]
|
||||||
|
(if c
|
||||||
|
(push-tail (- level bits) c tail cnt)
|
||||||
|
(push-tail (- level bits) empty-node tail cnt)))))
|
||||||
|
(def arr (array/slice parent))
|
||||||
|
(put arr sub-idx child)
|
||||||
|
(tuple/slice arr))
|
||||||
|
|
||||||
|
(defn pv-conj [pv val]
|
||||||
|
(def cnt (get pv :cnt))
|
||||||
|
(def tail (get pv :tail))
|
||||||
|
(if (< (length tail) width)
|
||||||
|
# Room in the tail: just append to it.
|
||||||
|
(make-pv (+ cnt 1) (get pv :shift)
|
||||||
|
(get pv :root)
|
||||||
|
(tuple/slice (tuple ;tail val)))
|
||||||
|
# Tail is full: push it into the trie, start a fresh tail with val.
|
||||||
|
(let [shift (get pv :shift)
|
||||||
|
root (get pv :root)]
|
||||||
|
(if (> (brshift cnt bits) (blshift 1 shift))
|
||||||
|
# Root overflow: grow the trie one level taller.
|
||||||
|
(let [new-root (tuple root (push-tail shift empty-node tail cnt))]
|
||||||
|
(make-pv (+ cnt 1) (+ shift bits) new-root [val]))
|
||||||
|
(make-pv (+ cnt 1) shift (push-tail shift root tail cnt) [val])))))
|
||||||
|
|
||||||
|
# --- assoc ------------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn- assoc-in-node [level node i val]
|
||||||
|
(def arr (array/slice node))
|
||||||
|
(if (= level 0)
|
||||||
|
(put arr (band i mask) val)
|
||||||
|
(let [sub-idx (band (brshift i level) mask)]
|
||||||
|
(put arr sub-idx (assoc-in-node (- level bits) (get node sub-idx) i val))))
|
||||||
|
(tuple/slice arr))
|
||||||
|
|
||||||
|
(defn pv-assoc [pv i val]
|
||||||
|
(def cnt (get pv :cnt))
|
||||||
|
(cond
|
||||||
|
(= i cnt) (pv-conj pv val)
|
||||||
|
(and (>= i 0) (< i cnt))
|
||||||
|
(if (>= i (tail-offset cnt))
|
||||||
|
(let [tail (array/slice (get pv :tail))]
|
||||||
|
(put tail (band i mask) val)
|
||||||
|
(make-pv cnt (get pv :shift) (get pv :root) (tuple/slice tail)))
|
||||||
|
(make-pv cnt (get pv :shift)
|
||||||
|
(assoc-in-node (get pv :shift) (get pv :root) i val)
|
||||||
|
(get pv :tail)))
|
||||||
|
(error (string "Index " i " out of bounds for vector of length " cnt))))
|
||||||
|
|
||||||
|
# --- pop --------------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn- pop-tail [level node cnt]
|
||||||
|
(def sub-idx (band (brshift (- cnt 2) level) mask))
|
||||||
|
(cond
|
||||||
|
(> level bits)
|
||||||
|
(let [child (pop-tail (- level bits) (get node sub-idx) cnt)]
|
||||||
|
(if (and (nil? child) (= sub-idx 0))
|
||||||
|
nil
|
||||||
|
(let [arr (array/slice node)] (put arr sub-idx child) (tuple/slice arr))))
|
||||||
|
(= sub-idx 0) nil
|
||||||
|
(let [arr (array/slice node)] (put arr sub-idx nil) (tuple/slice arr))))
|
||||||
|
|
||||||
|
(defn pv-pop [pv]
|
||||||
|
(def cnt (get pv :cnt))
|
||||||
|
(cond
|
||||||
|
(= cnt 0) (error "Can't pop empty vector")
|
||||||
|
(= cnt 1) EMPTY
|
||||||
|
(> (- cnt (tail-offset cnt)) 1)
|
||||||
|
# More than one element in the tail: drop the last tail element.
|
||||||
|
(let [tail (get pv :tail)]
|
||||||
|
(make-pv (- cnt 1) (get pv :shift) (get pv :root)
|
||||||
|
(tuple/slice tail 0 (- (length tail) 1))))
|
||||||
|
# Tail has one element: the new tail is the last leaf of the trie.
|
||||||
|
(let [shift (get pv :shift)
|
||||||
|
new-tail (leaf-for pv (- cnt 2))
|
||||||
|
new-root-raw (pop-tail shift (get pv :root) cnt)
|
||||||
|
new-root (if (nil? new-root-raw) empty-node new-root-raw)]
|
||||||
|
(if (and (> shift bits) (nil? (get new-root 1)))
|
||||||
|
# Trie lost a level: promote the single remaining child to root.
|
||||||
|
(make-pv (- cnt 1) (- shift bits) (get new-root 0) new-tail)
|
||||||
|
(make-pv (- cnt 1) shift new-root new-tail)))))
|
||||||
|
|
||||||
|
# --- conversions ------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn pv->array [pv]
|
||||||
|
(def out @[])
|
||||||
|
(def cnt (get pv :cnt))
|
||||||
|
(var i 0)
|
||||||
|
(while (< i cnt)
|
||||||
|
(array/push out (pv-nth pv i))
|
||||||
|
(++ i))
|
||||||
|
out)
|
||||||
|
|
||||||
|
(defn pv-from-indexed [xs]
|
||||||
|
# Build a pvec from any Janet-indexed collection (tuple/array).
|
||||||
|
(var pv EMPTY)
|
||||||
|
(def n (length xs))
|
||||||
|
(var i 0)
|
||||||
|
(while (< i n) (set pv (pv-conj pv (in xs i))) (++ i))
|
||||||
|
pv)
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
(print "3: eval-string with core fns...")
|
(print "3: eval-string with core fns...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
(assert (= true (eval-string ctx "(nil? nil)")) "nil?")
|
(assert (= true (eval-string ctx "(nil? nil)")) "nil?")
|
||||||
(assert (deep= [2 3 4] (eval-string ctx "(map inc [1 2 3])")) "map+inc")
|
(assert (deep= [2 3 4] (normalize-pvecs (eval-string ctx "(map inc [1 2 3])"))) "map+inc")
|
||||||
(assert (= 6 (eval-string ctx "(reduce + [1 2 3])")) "reduce"))
|
(assert (= 6 (eval-string ctx "(reduce + [1 2 3])")) "reduce"))
|
||||||
(print " passed")
|
(print " passed")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "CLJS Collections Ported Tests")
|
(print "CLJS Collections Ported Tests")
|
||||||
|
|
||||||
(print "1: dissoc...")
|
(print "1: dissoc...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "CLJS Core Ported Tests")
|
(print "CLJS Core Ported Tests")
|
||||||
|
|
||||||
(print "1: metadata on maps...")
|
(print "1: metadata on maps...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 1 ===")
|
(print "=== CLJS Ported Part 1 ===")
|
||||||
(print "1: core math...")
|
(print "1: core math...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 10 ===")
|
(print "=== CLJS Ported Part 10 ===")
|
||||||
|
|
||||||
(print "43: when/when-not...")
|
(print "43: when/when-not...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 1 ===")
|
(print "=== CLJS Ported Part 1 ===")
|
||||||
(print "1: core math...")
|
(print "1: core math...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 1b ===")
|
(print "=== CLJS Ported Part 1b ===")
|
||||||
(print "7: seq operations...")
|
(print "7: seq operations...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 2 ===")
|
(print "=== CLJS Ported Part 2 ===")
|
||||||
(print "12: atoms...")
|
(print "12: atoms...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 3 ===")
|
(print "=== CLJS Ported Part 3 ===")
|
||||||
(print "16: destructuring...")
|
(print "16: destructuring...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 3b ===")
|
(print "=== CLJS Ported Part 3b ===")
|
||||||
(print "21: clojure.string...")
|
(print "21: clojure.string...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 4 ===")
|
(print "=== CLJS Ported Part 4 ===")
|
||||||
|
|
||||||
(print "23: deftype/defrecord...")
|
(print "23: deftype/defrecord...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 5 ===")
|
(print "=== CLJS Ported Part 5 ===")
|
||||||
(print "22: destructuring...")
|
(print "22: destructuring...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 6 ===")
|
(print "=== CLJS Ported Part 6 ===")
|
||||||
|
|
||||||
(print "28: anon fn #()...")
|
(print "28: anon fn #()...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 7 ===")
|
(print "=== CLJS Ported Part 7 ===")
|
||||||
|
|
||||||
(print "32: seq destructuring...")
|
(print "32: seq destructuring...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 8 ===")
|
(print "=== CLJS Ported Part 8 ===")
|
||||||
|
|
||||||
(print "35: range and repeat...")
|
(print "35: range and repeat...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "=== CLJS Ported Part 9 ===")
|
(print "=== CLJS Ported Part 9 ===")
|
||||||
|
|
||||||
(print "40: seq predicates...")
|
(print "40: seq predicates...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "CLJS Ported Tests")
|
(print "CLJS Ported Tests")
|
||||||
|
|
||||||
(print "1: math...")
|
(print "1: math...")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Ported from clojure/test_clojure/atoms.clj + systematic atom tests
|
# Ported from clojure/test_clojure/atoms.clj + systematic atom tests
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Ported Atom Tests")
|
(print "Ported Atom Tests")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Ported from clojure/test_clojure/control.clj
|
# Ported from clojure/test_clojure/control.clj
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Ported Control Tests")
|
(print "Ported Control Tests")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Ported from clojure/test_clojure/for.clj
|
# Ported from clojure/test_clojure/for.clj
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Ported For Tests")
|
(print "Ported For Tests")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Ported from clojure/test_clojure/logic.clj
|
# Ported from clojure/test_clojure/logic.clj
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Ported Logic Tests (from clojure/test-clojure/logic.clj)")
|
(print "Ported Logic Tests (from clojure/test-clojure/logic.clj)")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Ported from clojure/test_clojure/macros.clj
|
# Ported from clojure/test_clojure/macros.clj
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Ported Macros Tests")
|
(print "Ported Macros Tests")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,18 @@
|
||||||
(use ../src/jolt/types)
|
(use ../src/jolt/types)
|
||||||
|
(use ../src/jolt/pv)
|
||||||
(use ../src/jolt/reader)
|
(use ../src/jolt/reader)
|
||||||
(use ../src/jolt/evaluator)
|
(use ../src/jolt/evaluator)
|
||||||
(use ../src/jolt/core)
|
(use ../src/jolt/core)
|
||||||
|
|
||||||
|
# Normalize jolt collection results to Janet tuples so Janet-level deep=/= can
|
||||||
|
# compare against tuple literals regardless of the (pvec) representation.
|
||||||
|
(defn norm [x]
|
||||||
|
(cond
|
||||||
|
(pvec? x) (tuple ;(map norm (pv->array x)))
|
||||||
|
(tuple? x) (tuple ;(map norm x))
|
||||||
|
(array? x) (tuple ;(map norm x))
|
||||||
|
x))
|
||||||
|
|
||||||
# Helper: create a fresh bootstrapped context
|
# Helper: create a fresh bootstrapped context
|
||||||
(defn make-boot-ctx []
|
(defn make-boot-ctx []
|
||||||
(let [ctx (make-ctx)]
|
(let [ctx (make-ctx)]
|
||||||
|
|
@ -12,7 +22,7 @@
|
||||||
# Helper: parse + eval
|
# Helper: parse + eval
|
||||||
(defn eval-str [ctx s]
|
(defn eval-str [ctx s]
|
||||||
(let [form (parse-string s)]
|
(let [form (parse-string s)]
|
||||||
(eval-form ctx @{} form)))
|
(norm (eval-form ctx @{} form))))
|
||||||
|
|
||||||
(print "1: predicates...")
|
(print "1: predicates...")
|
||||||
(let [ctx (make-boot-ctx)]
|
(let [ctx (make-boot-ctx)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "Eval Tests")
|
(print "Eval Tests")
|
||||||
|
|
||||||
(print "1: eval literal...")
|
(print "1: eval literal...")
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,8 @@
|
||||||
### 14. Janet interop
|
### 14. Janet interop
|
||||||
["interop method" "\"v=41\"" "(. {:value 41 :describe (fn [self] (str \"v=\" (:value self)))} describe)"]
|
["interop method" "\"v=41\"" "(. {:value 41 :describe (fn [self] (str \"v=\" (:value self)))} describe)"]
|
||||||
["interop field" "41" "(.-value {:value 41})"]
|
["interop field" "41" "(.-value {:value 41})"]
|
||||||
["interop janet-type" ":tuple" "(do (require '[jolt.interop :as j]) (j/janet-type [1 2 3]))"]
|
# vectors are persistent vectors (Janet tables); lists are Janet arrays
|
||||||
|
["interop janet-type" ":array" "(do (require '[jolt.interop :as j]) (j/janet-type (list 1 2 3)))"]
|
||||||
])
|
])
|
||||||
|
|
||||||
(each [label expected actual] cases (check label expected actual))
|
(each [label expected actual] cases (check label expected actual))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
|
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
# Helper: compare via Clojure = which handles PHM
|
# Helper: compare via Clojure = which handles PHM
|
||||||
(defn clj= [ctx a b]
|
(defn clj= [ctx a b]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "Janet Interop Tests")
|
(print "Janet Interop Tests")
|
||||||
|
|
||||||
(print "1: field access on tables...")
|
(print "1: field access on tables...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "LazySeq Tests")
|
(print "LazySeq Tests")
|
||||||
|
|
||||||
(print "1: lazy-seq from list...")
|
(print "1: lazy-seq from list...")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
(print "Ported Logic Tests (from clojure/test-clojure/logic.clj)")
|
(print "Ported Logic Tests (from clojure/test-clojure/logic.clj)")
|
||||||
|
|
||||||
(print "1: test-if true/false/nil...")
|
(print "1: test-if true/false/nil...")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
(use ../src/jolt/reader)
|
(use ../src/jolt/reader)
|
||||||
(use ../src/jolt/evaluator)
|
(use ../src/jolt/evaluator)
|
||||||
|
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(defn load-clj [ctx filepath]
|
(defn load-clj [ctx filepath]
|
||||||
(def source (slurp filepath))
|
(def source (slurp filepath))
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Phase 12: Protocol System Tests
|
# Phase 12: Protocol System Tests
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "35: defprotocol...")
|
(print "35: defprotocol...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(use ../src/jolt/evaluator)
|
(use ../src/jolt/evaluator)
|
||||||
(use ../src/jolt/reader)
|
(use ../src/jolt/reader)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(defn load-clj [ctx filepath]
|
(defn load-clj [ctx filepath]
|
||||||
(var s (slurp filepath))
|
(var s (slurp filepath))
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Phase 5: Multimethods + Hierarchy Tests
|
# Phase 5: Multimethods + Hierarchy Tests
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
# 22. Hierarchy
|
# 22. Hierarchy
|
||||||
(print "22: hierarchy...")
|
(print "22: hierarchy...")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
|
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Phase 6: comprehensive compile-mode tests...")
|
(print "Phase 6: comprehensive compile-mode tests...")
|
||||||
(let [ctx (init {:compile? true})]
|
(let [ctx (init {:compile? true})]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Phase 6: Reader Extensions Tests
|
# Phase 6: Reader Extensions Tests
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "28: #inst tagged literal...")
|
(print "28: #inst tagged literal...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Phase 7: LazySeq + PersistentHashSet completion
|
# Phase 7: LazySeq + PersistentHashSet completion
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "32: lazy-seq...")
|
(print "32: lazy-seq...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Phase 8: Protocol System Tests
|
# Phase 8: Protocol System Tests
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "35: defprotocol...")
|
(print "35: defprotocol...")
|
||||||
(let [ctx (init)]
|
(let [ctx (init)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Systematic coverage tests for Clojure language features
|
# Systematic coverage tests for Clojure language features
|
||||||
(use ../src/jolt/api)
|
(use ../src/jolt/api)
|
||||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
|
||||||
|
|
||||||
(print "Systematic Coverage Tests")
|
(print "Systematic Coverage Tests")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue