Skip to content

parsers: add Where for parsed value conditions - #35

Merged
rameel merged 5 commits into
mainfrom
parsers/where
Sep 30, 2026
Merged

rameel merged 5 commits into
mainfrom
parsers/where

Conversation

@rameel

@rameel rameel commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Some grammar rules depend on the value they parsed. Literal.Number<int>() reads 256 without error, but an IPv4 octet must be in 0..255. Map and Do can transform the value, but they cannot reject it: a Do that returns false is still a successful match. FatalError does reject the value, but it stops the whole parse, so no alternative can run.

Where(predicate, expected) turns such a check into an ordinary parser:

using static Ramstack.Parsing.Parser;

var octet = Literal
    .Number<int>()
    .Where(
        n => n is >= 0 and <= 255,
        "octet");

var parser = octet.ThenIgnore(Eof);

parser.Parse("255").Value;        // 255
parser.Parse("256").ErrorMessage; // "(1:1) Expected octet"

What it gives:

  • A rejected value is an ordinary failed match. The input position returns to the start of the rule and nothing is consumed, so Or, Optional and Repeat keep working as usual.
  • The expected text is reported through the regular diagnostics at the point where the rule started, and joins other expectations recorded there.
  • The check is an acceptance condition. It still runs under .Void() and with suppressed diagnostics; only the parsed value is discarded.
  • Exceptions thrown by the predicate are not converted into failed matches. Parse returns them in ParseResult.Exception and TryParse passes them to the caller, consistent with Do and Map.

Additional changes

The branch also includes a small diagnostics fix found while testing:
ParseContext.ToString() used to format "(1:1) " when no diagnostics had been recorded and now returns an empty string. Parse reports "Parsing failed." when a failure records no diagnostics. Tests for the As and Eof behavior that Where relies on were added with it.

Note

The text of this description and the tests in this pull request
were prepared with the help of DeepSeek V4.1 Flash.

Add Where(predicate, expected) to reject parsed values with an ordinary
parse failure. Restore the input position on predicate rejection and
report the expected value at the start of the attempt.
While writing tests for Where, discovered that ParseContext.ToString()
returned "(1:1) " even when no diagnostics had been recorded.

Return an empty string in that case and document the actual behavior.
Use "Parsing failed." without coordinates when parsing fails without
diagnostics, so the failure is not mistaken for success.
Pin that a successful As preserves later diagnostics and that Eof
reports its position after a consumed prefix.

Both interactions surfaced while testing Where, which relies on them
indirectly; dedicated tests make a failure point at the owning parser
instead of showing up inside the Where suite.
@rameel
rameel merged commit 4b16ce3 into main Sep 30, 2026
2 checks passed
@rameel
rameel deleted the parsers/where branch September 30, 2026 18:40
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