feat: complete atom implementation, new macros, predicates, and test coverage
## Runtime (src/jolt/core.janet, +637/-99) ### Atom system (complete) - core-atom: :validator and :meta options, watches table, atom-validate/atom-notify-watches helpers - New functions: swap-vals!, reset-vals!, compare-and-set!, set-validator!, get-validator, add-watch, remove-watch - Validator: blocks invalid reset!/swap!; watches: notification with old/new values; metadata support - All 7 functions registered in core-bindings ### New predicates - integer?, boolean?, list? — all registered in core-bindings ### New math - abs, rand, rand-int — registered in core-bindings ### Control flow macros (7 new) - cond, case (with one-of-many list support), condp, dotimes, while, if-not, when-first - Registered as macros: cond, case, for, dotimes, while, condp, if-not, when-first ### Threading macros (7) - -> (thread-first), ->> (thread-last), some->, some->>, cond->, cond->>, as-> - Renamed to core-thread-first/core-thread-last to avoid collision with comparison operators ### for comprehension - Full Clojure for macro: :when, :let modifiers, nested bindings - Uses map/mapcat expansion, correct last-group optimization ### Sequence operations (15 new) - last, butlast, second, ffirst, fnext, nfirst, nnext, nthnext, nthrest - drop-last, take-nth, map-indexed, keep, keep-indexed, reductions ### Nil-safety fixes - core-reverse, core-sort, core-sort-by, core-distinct now handle nil input ## Tests (7 new files, 361 assertions across all tests) ### Ported from Clojure test suite (4 files) - clojure-logic-test.janet: 82 assertions (if/and/or/not/some?/nil-punning) - clojure-control-test.janet: 56 assertions (do/when/if-let/cond/dotimes/while/loop/case) - clojure-macros-test.janet: 21 assertions (->/->>/some->/some->>/cond->/cond->>/as->) - clojure-for-test.janet: 4 assertions (:when/:let/nested for) ### Systematic coverage - clojure-atom-test.janet: 31 assertions (creation/reset!/swap!/swap-vals!/reset-vals!/CAS/validator/watches/meta) - systematic-coverage.janet: 120+ assertions (predicates/math/comparison/logic/collections/seq-ops/destructuring) - logic-test.janet: earlier ported logic tests ### Existing tests updated - lazy-test.janet, phase7-test.janet: updated for nil-safe core functions ## Result 47 test files, all passing. 19 new functions/macros implemented. Clojure atom semantics complete: validators, watches, metadata, CAS, swap-vals!/reset-vals!.
This commit is contained in:
parent
82bce033a5
commit
e2e7fa1447
12 changed files with 1462 additions and 98 deletions
151
test/clojure-control-test.janet
Normal file
151
test/clojure-control-test.janet
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# Ported from clojure/test_clojure/control.clj
|
||||
(use ../src/jolt/api)
|
||||
(defn ct-eval [ctx s] (eval-string ctx s))
|
||||
|
||||
(print "Ported Control Tests")
|
||||
|
||||
# --- test-do ---
|
||||
(print "test-do...")
|
||||
(let [ctx (init)]
|
||||
(assert (= nil (ct-eval ctx "(do)")) "do empty -> nil")
|
||||
(assert (= 1 (ct-eval ctx "(do 1)")) "do returns last")
|
||||
(assert (= 2 (ct-eval ctx "(do 1 2)")) "do returns last")
|
||||
(assert (= 5 (ct-eval ctx "(do 1 2 3 4 5)")) "do returns last"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-loop ---
|
||||
(print "test-loop...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(loop [] 1)")) "loop body")
|
||||
(assert (= 3 (ct-eval ctx "(loop [a 1] (if (< a 3) (recur (inc a)) a))")) "loop recur")
|
||||
(assert (= true (ct-eval ctx
|
||||
"(= [6 4 2] (loop [a () b [1 2 3]]
|
||||
(if (seq b)
|
||||
(recur (conj a (* 2 (first b))) (next b))
|
||||
a)))")) "loop accum list")
|
||||
(assert (= true (ct-eval ctx
|
||||
"(= [2 4 6] (loop [a [] b [1 2 3]]
|
||||
(if (seq b)
|
||||
(recur (conj a (* 2 (first b))) (next b))
|
||||
a)))")) "loop accum vector"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-when ---
|
||||
(print "test-when...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(when true 1)")) "when true")
|
||||
(assert (= nil (ct-eval ctx "(when true)")) "when true no body")
|
||||
(assert (= nil (ct-eval ctx "(when false)")) "when false")
|
||||
(assert (= nil (ct-eval ctx "(when false 1)")) "when false with body"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-when-not ---
|
||||
(print "test-when-not...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(when-not false 1)")) "when-not false")
|
||||
(assert (= nil (ct-eval ctx "(when-not true)")) "when-not true no body")
|
||||
(assert (= nil (ct-eval ctx "(when-not false)")) "when-not false no body")
|
||||
(assert (= nil (ct-eval ctx "(when-not true 1)")) "when-not true with body"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-if-not ---
|
||||
(print "test-if-not...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(if-not false 1)")) "if-not false")
|
||||
(assert (= 1 (ct-eval ctx "(if-not false 1 2)")) "if-not false with else")
|
||||
(assert (= nil (ct-eval ctx "(if-not true 1)")) "if-not true")
|
||||
(assert (= 2 (ct-eval ctx "(if-not true 1 2)")) "if-not true with else"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-when-let ---
|
||||
(print "test-when-let...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(when-let [a 1] a)")) "when-let simple")
|
||||
(assert (= 2 (ct-eval ctx "(when-let [[a b] '(1 2)] b)")) "when-let destructure")
|
||||
(assert (= nil (ct-eval ctx "(when-let [a false] 1)")) "when-let false"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-if-let ---
|
||||
(print "test-if-let...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(if-let [a 1] a)")) "if-let simple")
|
||||
(assert (= 2 (ct-eval ctx "(if-let [[a b] '(1 2)] b)")) "if-let destructure")
|
||||
(assert (= nil (ct-eval ctx "(if-let [a false] 1)")) "if-let false")
|
||||
(assert (= 1 (ct-eval ctx "(if-let [a false] a 1)")) "if-let false with else"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-if-some ---
|
||||
(print "test-if-some...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(if-some [a 1] a)")) "if-some simple")
|
||||
(assert (= false (ct-eval ctx "(if-some [a false] a)")) "if-some false is some")
|
||||
(assert (= nil (ct-eval ctx "(if-some [a nil] 1)")) "if-some nil")
|
||||
(assert (= 3 (ct-eval ctx "(if-some [[a b] [1 2]] (+ a b))")) "if-some destructure"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-when-some ---
|
||||
(print "test-when-some...")
|
||||
(let [ctx (init)]
|
||||
(assert (= 1 (ct-eval ctx "(when-some [a 1] a)")) "when-some simple")
|
||||
(assert (= 2 (ct-eval ctx "(when-some [[a b] [1 2]] b)")) "when-some destructure")
|
||||
(assert (= false (ct-eval ctx "(when-some [a false] a)")) "when-some false is some")
|
||||
(assert (= nil (ct-eval ctx "(when-some [a nil] 1)")) "when-some nil"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-cond ---
|
||||
(print "test-cond...")
|
||||
(let [ctx (init)]
|
||||
(assert (= nil (ct-eval ctx "(cond)")) "cond empty -> nil")
|
||||
(assert (= nil (ct-eval ctx "(cond nil true)")) "cond nil -> nil")
|
||||
(assert (= nil (ct-eval ctx "(cond false true)")) "cond false -> nil")
|
||||
(assert (= 1 (ct-eval ctx "(cond true 1)")) "cond true -> 1")
|
||||
(assert (= 3 (ct-eval ctx "(cond nil 1 false 2 true 3 true 4)")) "cond third branch")
|
||||
(assert (= :b (ct-eval ctx "(cond false :a true :b)")) "cond skips false")
|
||||
(assert (= :a (ct-eval ctx "(cond true :a true :b)")) "cond takes first true"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-condp ---
|
||||
(print "test-condp...")
|
||||
(let [ctx (init)]
|
||||
(assert (= :pass (ct-eval ctx "(condp = 1 1 :pass 2 :fail)")) "condp match first")
|
||||
(assert (= :pass (ct-eval ctx "(condp = 1 2 :fail 1 :pass)")) "condp match second")
|
||||
(assert (= :pass (ct-eval ctx "(condp = 1 2 :fail :pass)")) "condp default"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-dotimes ---
|
||||
(print "test-dotimes...")
|
||||
(let [ctx (init)]
|
||||
(assert (= nil (ct-eval ctx "(dotimes [n 1] n)")) "dotimes returns nil")
|
||||
(assert (= 3 (ct-eval ctx
|
||||
"(let [a (atom 0)]
|
||||
(dotimes [n 3] (swap! a inc))
|
||||
@a)")) "dotimes 3 iterations")
|
||||
(assert (= [0 1 2] (ct-eval ctx
|
||||
"(let [a (atom [])]
|
||||
(dotimes [n 3] (swap! a conj n))
|
||||
@a)")) "dotimes with index"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-while ---
|
||||
(print "test-while...")
|
||||
(let [ctx (init)]
|
||||
(assert (= nil (ct-eval ctx "(while nil 1)")) "while nil returns nil")
|
||||
(assert (= true (ct-eval ctx
|
||||
"(= [0 nil]
|
||||
(let [a (atom 3)
|
||||
w (while (pos? @a) (swap! a dec))]
|
||||
[@a w]))")) "while dec to 0"))
|
||||
(print " ok")
|
||||
|
||||
# --- test-case ---
|
||||
(print "test-case...")
|
||||
(let [ctx (init)]
|
||||
(assert (= :number (ct-eval ctx "(case 1 1 :number :default)")) "case match 1")
|
||||
(assert (= :string (ct-eval ctx "(case \"foo\" \"foo\" :string :default)")) "case match string")
|
||||
(assert (= :kw (ct-eval ctx "(case :zap :zap :kw :default)")) "case match keyword")
|
||||
(assert (= :symbol (ct-eval ctx "(case 'pow pow :symbol :default)")) "case match symbol")
|
||||
(assert (= :default (ct-eval ctx "(case 99 1 :number :default)")) "case default")
|
||||
(assert (= :matched (ct-eval ctx "(case 2 (2 3 4) :matched :default)")) "case one-of-many"))
|
||||
(print " ok")
|
||||
|
||||
(print "\nAll Ported Control tests passed!")
|
||||
Loading…
Add table
Add a link
Reference in a new issue