Skip to content

Pass delimited tokens through verbatim (S_delim); release 0.5.0 - #7

Merged
shigarov merged 1 commit into
mainfrom
feature/s-delim-raw-split
Aug 26, 2026
Merged

Pass delimited tokens through verbatim (S_delim); release 0.5.0#7
shigarov merged 1 commit into
mainfrom
feature/s-delim-raw-split

Conversation

@shigarov

Copy link
Copy Markdown
Contributor

Brings S_delim in line with the formal model and jRegTab 0.5.0, and cuts the 0.5.0 release.

The change

S_delim = (δ, S_atom) decomposes the cell text into substrings s_k ∈ Σ* and applies S_atom to each as-is. pyRegTab trimmed every token and silently dropped empty ones, making the delimited specification the odd one out — atomic and compound segments already receive their text raw.

Splitting is now verbatim in both places it happens: n substrings always derive n items, numbered 0..n-1, surrounding whitespace intact and empty substrings included. "a, b" yields "a" and " b"; "a,,b" yields three items.

Motive: the explode stratum of ATBench (Auto-Tables, VLDB 2023) in regtab-eval-on-atbench has ground truth produced by pandas str.split(','), which keeps token whitespace and empty strings. Forced trimming made ~41 of 48 cases inexpressible.

⚠️ BREAKING (semantics)

Trimming is now opt-in via the atom's string extractor:

(VAL){","}        →  (VAL=TRIM){","}

Tasks 45 and 55 relied on the implicit trimming and were fixed that way, in both the RTL and the ATP suite. Their expected recordsets are unchanged — no fixture under tests/fixtures/ was touched.

RTL syntax, the grammar and ATP→RTL serialization are untouched. Canonical forms changed only for task_045/task_055, because of the added =TRIM in the patterns themselves.

Not a two-line deletion

Unlike jRegTab, pyRegTab tracks a byte span per item. split_with_spans now reports the span of the raw token and the leading-whitespace offset is gone. Item indices also become contiguous on the standalone delimited path, which is observable through POS filters (FilterTerm::PosExact/PosOffset/PosRange).

The whole behavioural change is one helper — both call sites go through it.

Corpus

Re-pinned to jRegTab v0.5.0 (035ff1a) and synced byte-for-byte (all 333 files verified against upstream; raw CRLF payload in task_099 and tabs in task_101 intact, no whitespace drift in the other 300):

  • 152 positive pairs, including the new delim_raw
  • the new normative conformance/semantic/ section — item 5 of the contract

tests/test_semantic_conformance.py executes that section (port of RtlSemanticConformanceTest). Note its defaults differ from the task suite: expected.csv is header-less and matched positionally against the schema the pattern produced, so implementation-invented attribute names stay out of the contract — task_runner.load_match_options must not be reused there.

Tests

src/matcher.rs gains a #[cfg(test)] module (the matcher had none): whitespace retention, empty tokens, edge empty tokens, contiguous indices, span arithmetic under a non-zero base, byte-exactness on multibyte text, and the =TRIM opt-in — plus end-to-end cases through match_atp.

Checked to be discriminating: with the old trimming temporarily restored, all 10 new tests fail and the 4 pre-existing ones stay green.

cargo test --no-default-features    14 passed   (was 4)
pytest tests -q                   1918 passed   (was 1908)
cargo clippy --all-targets -D warnings   clean
tools/check_grammar_sync.py              OK

Differential run against jRegTab v0.5.0, executed locally: 750/750 variants identical.

Release 0.5.0

Version bumped in Cargo.toml, Cargo.lock, pyproject.toml and __init__.py; grammar/UPSTREAM re-pinned to v0.5.0 (RTL.g4 byte-identical, sha256 unchanged); the manual differential CI job now builds jregtab@v0.5.0; README/docs parity statements updated to 0.5.0 ≙ jRegTab 0.5.0.

Tagging v0.5.0 after merge triggers the wheel build and PyPI publish.

Plan document: plans/S_DELIM_RAW_SPLIT.md.

🤖 Generated with Claude Code

The delimited content specification `(VAL){"d"}` trimmed every token and
silently dropped empty ones. That deviated from def:delimited-content-spec,
where the input decomposes into substrings s_k in Sigma* and S_atom applies to
each one as-is, and it made the delimited specification the odd one out: atomic
and compound segments already receive their text raw.

Splitting is now verbatim in both places it happens (a standalone delimited cell
and a delimited segment nested in a compound one): n substrings always derive n
items, numbered 0..n-1, surrounding whitespace intact and empty substrings
included. This matches pandas str.split, so patterns over exploded columns
become expressible without post-processing -- the motivating case is the
`explode` stratum of ATBench in regtab-eval-on-atbench.

BREAKING (semantics). Trimming is now opt-in through the atom's string
extractor: (VAL){","} -> (VAL=TRIM){","}. Tasks 45 and 55 relied on the implicit
trimming and were fixed that way, in both the RTL and the ATP suite; their
expected recordsets are unchanged. RTL syntax, the grammar and ATP->RTL
serialization are untouched.

Unlike jRegTab, pyRegTab tracks a byte span per item, so this is not just a
deletion: split_with_spans now reports the span of the raw token and the
leading-whitespace offset is gone. Item indices become contiguous on the
standalone path too, which is observable through POS filters.

Adds a #[cfg(test)] module to src/matcher.rs (the matcher had no unit tests of
its own) covering whitespace retention, empty tokens, contiguous indices, span
arithmetic under a non-zero base and the =TRIM opt-in.

Corpus re-pinned to jRegTab v0.5.0 (035ff1a) and synced byte-for-byte: 152
positive pairs including the new `delim_raw`, and the new normative
conformance/semantic/ section -- item 5 of the contract, executed here by
tests/test_semantic_conformance.py. Note its defaults differ from the task
suite: expected.csv is header-less and matched positionally against the schema
the pattern produced, so implementation-invented attribute names stay out of the
contract.

Release 0.5.0 (breaking behaviour change): version bumped in Cargo.toml,
Cargo.lock, pyproject.toml and __init__.py; grammar/UPSTREAM re-pinned to v0.5.0
(RTL.g4 byte-identical, sha256 unchanged); the differential CI job now builds
jregtab@v0.5.0. Verified locally against that tag: 750/750 variants identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shigarov
shigarov merged commit abca0c7 into main Aug 26, 2026
8 checks passed
@shigarov
shigarov deleted the feature/s-delim-raw-split branch August 26, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant