Releases: vlad-public-code/org.json-kula.jsonata2py
Release list
v0.1.2 Conformance, sequence-scan fusion
Conformance work, the sequence-scan fusion performance pass, and a docs
trim, brought together onto main.
Changelog
Performance
- Sequence-scan fusion (
translator/scan_fusion.py, new): groups a block's
operations per bound sequence and emits one helper that reads each distinct
field once, feeding every accumulator from that read. On the analytical
benchmark: 551 field reads per evaluation down to 320, 1 955 function calls
down to 1 253, evaluation 1.33x faster. It plans rather than rewrites —
operations are collected only from unconditionally evaluated positions — and
falls back to the original helper for anything but a plainint/float
field. $seq[field = <literal>]compiles to a monomorphizedfilter_field_eqcall
instead of a per-element callback (hoisted lambdas on the benchmark: 18 → 3).- Objects built from literal keys the translator has proved distinct skip
object_of's per-key duplicate check. - Cold compilation rises ~1.5x (~17 KB → ~29 KB of generated module), the
deliberate cost of the above; it repays after ~100 evaluations. - Current figures: 106 µs evaluation vs
jsonatapy285 µs,jsonata-rs
517 µs,jsonata-python5 797 µs.
Conformance
- Built-in context substitution:
$fn()as a path step, and direct calls
with fewer arguments than the signature, now route through a port of the
referenceparseSignature/validatelogic; the evaluation context is
substituted into focus (-) parameters by argument type at runtime. Covers
45+ previously diverging cases ($power(3)crash,$uppercase()wrong error
code, …).direct_call_is_safe()exempts fully-determined fast paths from the
validation cost. - Tuple paths (
runtime/tuples.py,translator/tuple_path_codegen.py,
both new): tuple-stream path evaluation and its codegen. - Parenthesized path head:
("ab").foois a value navigation (undefined),
not a field lookup. - Wildcard / descendant: ported reference
evaluateWildcard/
evaluateDescendants; leading-step outer-wrapper case separated from the
per-element case viawildcard_contextandat_input_root. - Nested path wildcard fold: the optimizer no longer flattens an inner
PathExprcontaining a wildcard or descendant step into the outer path,
preserving the re-split semantics of a nestedevaluatePath. $spread: singleton-collapses the single-object result and preserves the
array result, fixing the previous inversion.- Datetime picture formatting/parsing, decimal and integer pictures, English
number words, regex operations and string built-ins reworked against the
reference. _leaks_evaluator_scopeuses a whole-token regex, socall_builtin_ctxin
hoisted closure bodies no longer false-fires.
Tests
New suites for scan fusion, tuple-path bindings, signature validation, callback
hoisting, object construction, array-constructor path heads, constructor step
flattening and value wrappers, path-stage/null conformance, reference
conformance, cache bounds, memory (generated modules stay collectible) and
concurrency.
Docs
- Performance section in
README.mdanddocs/index.mdcut by ~40% — every
table, figure and caveat kept; the per-session measurement diary that had
accumulated around them removed. - Added a "Sibling implementations" table, and corrected the jsonata2js speedup
to the figure that project reports for itself (~53x-60x vs jsonata). - Version bumped to 0.1.1;
docs/llms.txtrefreshed.
🤖 Generated with Claude Code
release: 0.1.1 — conformance fixes + perf update
What
Version 0.1.1: conformance fixes, performance re-measurement, and docs update.
Conformance fixes (all verified against the reference jsonata JS interpreter)
Builtin context substitution
$fn() called as a path step, or any builtin called with fewer args than its parameter count, now routes through a faithful port of the reference's parseSignature/validate logic. The evaluation context is substituted into focus (-) parameters based on argument types at runtime — not just argument counts — matching the reference exactly.
Examples that were previously wrong:
v.$power(3)withv=2→ crashed (IndexError); now 8v.$uppercase()withv=5→ wrong error code T0410; now T0411v.$keys()on an object → null; now correct$toMillis()with context → crash; now correct- 45+ more cases across the 260-case sweep
direct_call_is_safe(sig, argc) exempts fast-path calls that provably can't need substitution (e.g. $string(x) with one arg) from paying the validation cost, keeping the perf gate green.
Parenthesized path head
("ab").foo was treated as a field lookup (same as "ab".foo). Fixed at parse time: a bare leading StringLiteral is converted to FieldRef; a Parenthesized node (value) is preserved.
Wildcard / descendant operators
Ported the reference evaluateWildcard / recurseDescendants algorithms. Added wildcard_context for the leading-step (outer-wrapper) case, vs per-element wildcard. at_input_root flag on GenCtx routes codegen to the correct variant.
Nested path wildcard fold
x.(*.y) was folded into x.*.y (identical code), losing the reference's per-element evaluatePath re-split semantics. Fixed: optimizer no longer flattens an inner PathExpr containing WildcardStep or DescendantStep.
$spread
Single-key object result now singleton-collapses ($spread({"a":1}) → {"a":1}, not [{"a":1}]). Array input now preserves the array. Previously inverted.
Closure hoisting guard
_leaks_evaluator_scope changed from substring to whole-token regex; call_builtin_ctx no longer false-fires it, restoring hoisting for predicate callbacks that happen to mention a builtin with _ctx in its name.
Regression tests added
tests/runtime/test_reference_conformance.py:
TestBuiltinContextSubstitution— 14 casesTestParenthesizedPathHead— 5 casesTestNestedPathWildcard— 4 casesTestSpread— 5 cases
Total suite: 5,535 passed (up from 5,506 before this PR's new tests).
Performance
Re-measured 2026-09-01 on the same machine (Intel Core i7-1185G7, Windows 11, CPython 3.14.3):
| jsonata2py 0.1.1 | jsonatapy | jsonata-python | |
|---|---|---|---|
| Evaluation | 123 µs | 250 µs | 5 740 µs |
| Speedup | baseline | 2.0× slower | 47× slower |
Perf gate green (eval_w1: 123 µs vs baseline; all 7 workloads within 1.5× limit).
Docs
- Performance tables updated in
README.md,docs/index.md,docs/llms.txt - Added Sibling implementations table to
README.mdanddocs/index.md - Version string bumped to 0.1.1 everywhere