Skip to content

Releases: vlad-public-code/org.json-kula.jsonata2py

v0.1.2 Conformance, sequence-scan fusion

Choose a tag to compare

@vlad-public-code vlad-public-code released this 05 Sep 14:39
3991634

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 plain int/float
    field.
  • $seq[field = <literal>] compiles to a monomorphized filter_field_eq call
    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 jsonatapy 285 µs, jsonata-rs
    517 µs, jsonata-python 5 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
    reference parseSignature/validate logic; 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").foo is 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 via wildcard_context and at_input_root.
  • Nested path wildcard fold: the optimizer no longer flattens an inner
    PathExpr containing a wildcard or descendant step into the outer path,
    preserving the re-split semantics of a nested evaluatePath.
  • $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_scope uses a whole-token regex, so call_builtin_ctx in
    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.md and docs/index.md cut 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.txt refreshed.

🤖 Generated with Claude Code

https://claude.ai/code/session_015XC8GqzZHFbZzTw8pEjwVs

release: 0.1.1 — conformance fixes + perf update

Choose a tag to compare

@vlad-public-code vlad-public-code released this 01 Sep 16:49
939bda6

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) with v=2 → crashed (IndexError); now 8
  • v.$uppercase() with v=5 → wrong error code T0410; now T0411
  • v.$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 cases
  • TestParenthesizedPathHead — 5 cases
  • TestNestedPathWildcard — 4 cases
  • TestSpread — 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.md and docs/index.md
  • Version string bumped to 0.1.1 everywhere

v0.1.0

Choose a tag to compare

@vlad-public-code vlad-public-code released this 23 Aug 22:40
first commit