parser: a trailing ; on a clause no longer empties the whole test body (Refs #2161) - #2736
Merged
Conversation
…ody (Refs #2161) A braceless clause may end with a semicolon: test t given p = 0; assert g(1) == 999 Nothing consumed it, so the next loop turn met `;` where it expects a clause head, read that as "stopped mid-clause", and restored the fallback -- discarding the WHOLE block over one character. The identical body without the semicolon lowered fine, which is what kept it invisible: two spellings of one clause, one of them silently emptying every assertion after it, and `gen_test_block` emits the resulting empty test with no marker. Measured over 746 tracked specs: discarded top-level tokens 35,224 -> 35,070 specs that parse 620 -> 620 t27c tests 1629/6 -> 1629/6 RATCHET CLEAN A SECOND shape in this family is NOT fixed here, deliberately. A body that OPENS with `var`/`const` has no earlier clause to take a column from, so `first_clause_col` is None and the statement arm is skipped. I wrote that fix, measured it recovering 1,914 tokens -- and it regressed specs/memory/notebooklm.t27 from parsing to not parsing. The mechanism is worth recording: seeding the column lets an EARLIER clause take the statement arm, and the parser then reaches `const (notebook, err) = ...` -- a tuple destructure the arm cannot handle -- in a state where the old path would have fallen back for the whole block. It dies with "Expected identifier after 'const', got LParen" instead. The arm's contract is that it may only ADD assertions and never break a file; that version broke one, so it is not in this commit. Filed separately. Isolated by disabling one edit at a time rather than by reading: with the semicolon consumption alone the spec parses, with the column seeding alone it does not. FROZEN_HASH resealed in the same commit (M5).
This was referenced Aug 27, 2026
Contributor
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A braceless clause may end with a semicolon:
Nothing consumed it, so the next loop turn met
;where it expects a clause head, read that as stopped mid-clause, and restored the fallback — discarding the whole block over one character. The identical body without the semicolon lowered fine, which is what kept it invisible: two spellings of one clause, one of them silently emptying every assertion after it, andgen_test_blockemits the resulting empty test with no marker.A second shape in this family is deliberately not here
A body that opens with
var/consthas no earlier clause to take a column from, so the statement arm is skipped. I wrote that fix and measured it recovering 1,914 tokens — and it regressedspecs/memory/notebooklm.t27from parsing to not parsing.Seeding the column lets an earlier clause take the statement arm, and the parser then reaches
const (notebook, err) = ...— a tuple destructure the arm cannot handle — in a state where the old path would have fallen back for the whole block. It dies withExpected identifier after 'const', got LPareninstead.Isolated by disabling one edit at a time rather than by reading: with the semicolon consumption alone the spec parses; with the column seeding alone it does not.
parse_bdd_clausescarries its own contract — "may only ADD assertions, never break a file" — and that version broke one. Filed as #2735 with the containment fix it actually needs.Refs #2161