feat(strictness): numeric ops reject non-numbers/non-integers like Clojure

- zero?/pos?/neg? throw on non-numbers; odd?/even? throw on non-integers
  (nil, infinities, NaN, fractional) via need-num/need-int helpers
- comparisons < > <= >= throw on non-number args (1-arity stays true, no check)
- max/min throw on non-number args
- quot/rem/mod throw on zero divisor and non-finite operands

odd?/even?/lt/gt/lt_eq/gt_eq suite files now clean; pass 3691->3738.
Updated systematic-coverage-test (zero? nil now throws). spec:
numbers/strictness (15). jpm test green.
This commit is contained in:
Yogthos 2026-06-05 10:58:21 -04:00
parent 4238ec745b
commit 07d5b43fbb
5 changed files with 50 additions and 15 deletions

View file

@ -18,7 +18,7 @@
# Baseline: assertions Jolt currently passes across the suite. Raise as Jolt
# improves so a regression (previously-passing assertion breaking) is caught.
(def baseline-pass 3690)
(def baseline-pass 3730)
# A file is "clean" when it ran with zero failures AND zero errors.
(def baseline-clean-files 45)
# Per-file wall-clock budget (seconds). Normal files finish in well under 1s;

View file

@ -59,7 +59,8 @@
(let [ctx (init)]
(assert (= true (ct-eval ctx "(zero? 0)")) "zero? 0")
(assert (= false (ct-eval ctx "(zero? 1)")) "zero? 1")
(assert (= false (ct-eval ctx "(zero? nil)")) "zero? nil")
# zero?/pos?/neg? now reject non-numbers (Clojure-strict), like the JVM.
(assert (not ((protect (ct-eval ctx "(zero? nil)")) 0)) "zero? nil throws")
(assert (= true (ct-eval ctx "(pos? 1)")) "pos?")
(assert (= false (ct-eval ctx "(pos? 0)")) "pos? 0")
(assert (= false (ct-eval ctx "(pos? -1)")) "pos? -1")

View file

@ -90,6 +90,25 @@
["exponent" "1000.0" "1e3"]
["exponent neg" "0.015" "1.5e-2"])
# Strictness: numeric ops reject non-numbers like Clojure; the integer
# predicates reject non-integers; quot/rem/mod reject zero/non-finite.
(defspec "numbers / strictness (throws like Clojure)"
["odd? nil" :throws "(odd? nil)"]
["odd? fractional" :throws "(odd? 1.5)"]
["even? inf" :throws "(even? ##Inf)"]
["zero? nil" :throws "(zero? nil)"]
["pos? false" :throws "(pos? false)"]
["neg? keyword" :throws "(neg? :a)"]
["< nil" :throws "(< nil 1)"]
["> with nil" :throws "(> 1 nil)"]
["max non-number" :throws "(max 1 nil)"]
["quot by zero" :throws "(quot 10 0)"]
["quot inf" :throws "(quot ##Inf 1)"]
["< arity-1 any" "true" "(< :anything)"]
["odd? ok" "true" "(odd? 3)"]
["< ok" "true" "(< 1 2 3)"]
["quot ok" "3" "(quot 10 3)"])
(defspec "numbers / printing of inf & nan"
["str Infinity" "\"Infinity\"" "(str ##Inf)"]
["str -Infinity" "\"-Infinity\"" "(str ##-Inf)"]