Commit graph

9 commits

Author SHA1 Message Date
Yogthos
7ca88ab2b5 core: move the pure-leaf fns to the overlay; memfn is a real macro now
Round 3 of the seed shrink. To the overlay: identity, constantly, neg?,
even?, odd? (20-coll, ahead of their first in-tier uses), not= and unreduced
(00-syntax — the kernel and seq tiers use them), ==, ensure-reduced,
halt-when, parse-boolean, parse-uuid, newline, seque, array-seq, to-array-2d,
and the masking unchecked-byte/short/char/float/double coercions. parse-uuid
validates via re-matches over a new __make-uuid host binding (overlay source
can't write :jolt/type map literals). memfn moves to 30-macros as a working
macro over the .method call sugar instead of a fn that throws.

Behavior fixes toward Clojure, each with spec rows: == now throws on
non-numbers instead of comparing them, and halt-when is the canonical
::halt-map version (the halt value replaces the whole reduction result, no
double completion). list? and map-entry? stay in the seed — both are
representation-coupled (plist/tuple checks).

clojure-test-suite goes 4701 -> 4700: update.cljc expects
(update {:k 1} :k identity 1 2 3 4) to throw an arity error, and jolt fns
don't enforce fixed arity anywhere (pre-existing, language-wide — the seed's
Janet identity threw natively). Filed as jolt-6xn; fixing it should flip
several suite rows at once.
2026-06-11 12:38:12 -04:00
Yogthos
9ac0f54e72 core: move promoting/unchecked arithmetic aliases, int?, num to the overlay
Jolt numbers don't overflow, so +'/-'/*'/inc'/dec' and the whole unchecked-*
family are just the checked ops — now one-line defs in core/20-coll.clj
instead of ~25 seed bindings. int? and num move the same way.

unchecked-divide-int now goes through quot, so dividing by zero throws like
the JVM instead of silently truncating infinity. unchecked-int/long gain
char handling via int, matching Clojure ((unchecked-int \a) => 97). The
masking byte/short/char coercions are not aliases and stay in the seed for
a later round.

Also drops a second duplicate set of unchecked defns that was shadowing the
first at module load.
2026-06-11 10:47:14 -04:00
Yogthos
eb7a9f1b20 core: spec 35-var batch A — 1.11 parsers, map/partition variants, with-redefs, ns fns
Fifteen vars from the spec coverage gap (docs/spec/coverage.md):
parse-long/parse-double/parse-boolean (strict validation; scan-number alone
accepts 0x10), newline, current-time-ms (host clock for time), update-keys/
update-vals (PHM base, collisions last-wins), partitionv/partitionv-all/
splitv-at (lazy seqs of vectors; splitv-at's tail stays a seq, matching the
reference), with-redefs/with-redefs-fn (roots restored on throw), time,
macroexpand (expand-1 to fixpoint), alias/ns-unalias (write BOTH alias stores
— require :as uses string-keyed :imports while ns-aliases reads :aliases;
split filed), ns-publics (symbol-keyed map; publics == interns, no privacy).

Three pre-existing bugs fixed along the way:
- (partition n step pad coll) misparsed pad as the coll and returned ()
- (require 'bare.symbol) rejected — only vector specs were accepted
- analyze-form leaked the interpreted analyzer's ns on a punt: a throw out of
  the analyzer left current-ns=jolt.analyzer and :compile-ns set, so the
  fallback interpretation resolved user vars against the wrong namespace
  (bit (var user-sym) under compile mode)

And one overlay-authoring landmine documented in-code: a 20-coll fn must not
use 30-macros macros (with-redefs-fn's dotimes compiled as a forward ref that
resolved to the macro fn at runtime) — loop/recur instead.

Gate: conformance 316x3 (+14 rows), suite 4324 pass / 78 clean (was 4081/72;
parse_*/update_* files now contribute), baselines raised, all specs+unit,
fixpoint, self-host, sci, staged. Coverage: missing-portable 35 -> 20.
2026-06-10 11:16:54 -04:00
Dmitri Sotnikov
3e9fe8d0fb
Comprehensive spec (#19)
* core: fix jolt-265 — syntax-quote fully-qualifies core syms to clojure.core/

Re-attempt of the deferred gap, now unblocked. The earlier uberscript break
wasn't qualification itself but an aliased-ref resolution bug it exposed:
resolve-var looked up ns-aliases (e.g. g/foo) against the analyzer's REBOUND
ctx-current-ns (jolt.analyzer, since the analyzer runs interpreted in its own
ns) instead of the namespace being compiled. A user's aliased refs failed
mid-compile (g/hello -> nil in the bundled standalone).

- resolve-var resolves aliases against :compile-ns when set (same ns
  h-current-ns uses), falling back to ctx-current-ns — correct for both modes.
- sq-symbol qualifies a resolved clojure.core name to clojure.core/<name>
  (Clojure hygiene); special forms stay bare; unresolved syms -> current ns.

Tests updated to the qualified behavior (features-test, reader-forms-spec).

* test: comprehensive spec — regex + sorted colls + random/predicate gaps

Filling the biggest untested clojure.core areas found in a coverage audit
(168 of 506 provided fns had no spec). New + expanded suites:

- regex-spec.janet (20): #"…" literals, regex?, re-find/re-matches/re-seq
  (match/no-match/groups), re-pattern, and clojure.string split/replace with
  regex (incl $1 backrefs). Whole area was previously unspecced.
- sorted-spec.janet (14): sorted-map/sorted-set construction + ordering, sorted?,
  subseq/rsubseq. Pins the working subset — get/conj/assoc/keys/vals on sorted
  colls and the by-comparator ctors are not yet first-class (jolt-ti9).
- predicates-spec +14: seqable?, integer?, reduced?/unreduced, not-empty.
- numbers-spec +5: rand/rand-int/rand-nth invariants.

Fix: sorted? was bound to core-sorted-map? so it returned false for sorted-sets;
now true for both sorted maps and sets (core-sorted?).

Filed: jolt-ti9 (sorted collections incomplete: get/conj/assoc/keys/vals don't
operate on the sorted wrapper; sorted-*-by ignore the comparator).

Gate green incl full jpm build + jpm test.

* core: close surfaced gaps — first-class sorted colls, with-out-str, rand arity, deref reduced

jolt-ti9: sorted-map/sorted-set are now first-class across the collection fns —
get/assoc/dissoc/conj/contains?/keys/vals/disj and call-as-fn all operate on the
wrapper and preserve sort order. The by-comparator constructors (sorted-map-by/
sorted-set-by) now thread the user comparator (numeric or boolean-predicate) through
all derived colls. Sorted predicates/ctors/ops moved above core-conj so the
collection fns can branch on them; jolt-invoke (interpreter) gets inline branches.

jolt-rfw: add with-out-str (binds output to a string buffer) + the macro.
jolt-ek3: (rand n) arity and deref-of-reduced (uuid? still deferred).

Specs: new io-spec.janet; sorted-spec expanded to pin the now-working map/set ops
and by-comparator ordering; predicate/number spec restorations.

* remove old doc

* core: fix stale comment — by-comparator sorted ctors are implemented

---------

Co-authored-by: Yogthos <yogthos@gmail.com>
2026-06-10 20:33:22 +08:00
Yogthos
07d5b43fbb 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.
2026-06-05 10:58:21 -04:00
Yogthos
a4d9d5f70b fix: print Infinity/-Infinity/NaN like Clojure (str and pr-str)
Numbers printed via Janet's (string v) rendered infinities/NaN as inf/-inf/nan.
Add fmt-number so str/pr-str (and collection rendering) emit Infinity/-Infinity/
NaN. str.cljc 3->32 pass. Remaining str fails are the integer-valued-double
divergence ((str 0.0) is "0" not "0.0" since 0.0 == 0 in Janet).

spec: numbers/printing-of-inf-&-nan (5). jpm test green.
2026-06-05 10:23:57 -04:00
Yogthos
acfcf2f94b feat: read N/M/ratio/radix/exponent number literals; clean suite measurement
Reader gaps caused the clojure-test-suite worker to crash whole deftests on
literals it could not parse (0N, 1.5M, 2r1010, 1/2), losing every assertion in
the file. read-number now handles:
- N (bigint) / M (bigdec) suffixes -> plain number (Jolt has no bignum/bigdec)
- ratios a/b -> double quotient
- radix integers NrDDD (2r1010, 16rFF, 36rZ) parsed by base
- exponents (1e3, 1.5e-2) and 0X hex

Also fixed suite measurement: when-var-exists now skips silently (its SKIP
print to stdout was corrupting the worker's count line, dropping whole files),
and the worker emits counts on an @@COUNTS sentinel line (robust against test
bodies that print, e.g. with-out-str). Runner parses the sentinel; deftest
crashes now report the underlying message.

Impact: clojure-test-suite 210->231 files run, pass 1955->3535, clean files
24->39. Baseline raised to 3450/38.

spec: numbers/literal-syntax (13 cases). jpm test green.
2026-06-05 09:54:14 -04:00
Yogthos
03652dce5d feat: ##Inf/##-Inf/##NaN literals, infinite?/NaN?, fix intval? for infinity
The reader now reads the symbolic float values ##Inf, ##-Inf and ##NaN. Added
infinite? and NaN? predicates. Fixed intval? to exclude infinity (floor(inf)=inf
but inf isn't integer-valued), so float?/double? are true for ##Inf and
int?/pos-int?/nat-int?/neg-int? are false for it.

This unblocked many number-test files whose  forms previously failed to
READ (##Inf/##NaN literals), so clojure-test-suite jumped from 2241 to 2539
assertions and pass 1719 -> 1955. Baseline raised to 1900. NaN_qmark now runs.

float?/double? on integer-valued doubles (1.0) remain false: Janet represents
an integer and an integer-valued double identically, so they're inherently
indistinguishable — documented in the README Numbers section.

spec: numbers/floats-&-symbolic-values (15 cases). jpm test green.
Closes jolt-fy8 (fixable parts; int-vs-float ambiguity is a documented divergence).
2026-06-05 09:35:44 -04:00
Yogthos
68d6b1d6c1 test(spec): numbers, strings, predicates — fix variadic <, seq?, index-of
Add spec suites for numbers/arithmetic, strings (str + clojure.string), and
type/value predicates. Bugs they caught and fixed:
- <, >, <=, >= were binary-only; now variadic ((< 1 2 3) chains)
- seq? was true for vectors; vectors are not ISeq in Clojure, so (seq? [1])
  is now false (true only for lists/lazy-seqs)
- clojure.string/index-of and last-index-of were 1-based (stray inc); now
  0-based per Clojure

Corrected a systematic-coverage assertion that encoded the old seq? bug.
jpm test green, conformance 218/218.
2026-06-05 00:13:19 -04:00