From 0003254141a3a11acad0566654f733485ba6093b Mon Sep 17 00:00:00 2001 From: rameel Date: Fri, 9 Oct 2026 19:18:17 +0500 Subject: [PATCH] parsers: make Return produce an empty matched segment Return consumes no input, but it left the matched segment of the previous parser in the context. Text() and Map then read that stale text: L("abc").Then(Return(42).Text()) produced "abc" instead of "". Return now calls Advance(0), as Eof, Optional and DefaultOnFail already do. The segment is empty and sits at the position where Return was applied. --- src/Ramstack.Parsing/Parser.Return.cs | 2 ++ .../ParsersTests.Return.cs | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/Ramstack.Parsing.Tests/ParsersTests.Return.cs diff --git a/src/Ramstack.Parsing/Parser.Return.cs b/src/Ramstack.Parsing/Parser.Return.cs index 8aaf35f..0543930 100644 --- a/src/Ramstack.Parsing/Parser.Return.cs +++ b/src/Ramstack.Parsing/Parser.Return.cs @@ -25,6 +25,8 @@ private sealed class ReturnParser(T returnValue) : Parser /// public override bool TryParse(ref ParseContext context, [NotNullWhen(true)] out T? value) { + context.Advance(0); + value = returnValue!; return true; } diff --git a/tests/Ramstack.Parsing.Tests/ParsersTests.Return.cs b/tests/Ramstack.Parsing.Tests/ParsersTests.Return.cs new file mode 100644 index 0000000..f587c5f --- /dev/null +++ b/tests/Ramstack.Parsing.Tests/ParsersTests.Return.cs @@ -0,0 +1,24 @@ +using static Ramstack.Parsing.Parser; + +namespace Ramstack.Parsing; + +partial class ParsersTests +{ + [Test] + public void Return_MatchedSegment_IsEmpty() + { + Assert.That(Return(42).Map(m => (m.Index, m.Length)).Parse("").Value, Is.EqualTo((0, 0))); + Assert.That(Return(42).Map(m => m.ToString()).Parse("").Value, Is.Empty); + Assert.That(Return(42).Text().Parse("abc").Value, Is.Empty); + } + + [Test] + public void Return_AfterMatch_DoesNotReuseStaleMatchedSegment() + { + var text = L("abc").Then(Return(42).Text()); + Assert.That(text.Parse("abc").Value, Is.Empty); + + var segment = L("abc").Then(Return(42).Map(m => (m.Index, m.Length))); + Assert.That(segment.Parse("abc").Value, Is.EqualTo((3, 0))); + } +}