diff --git a/src/Parlot/Fluent/OneOf.cs b/src/Parlot/Fluent/OneOf.cs index 86e54c2..1ce87b8 100644 --- a/src/Parlot/Fluent/OneOf.cs +++ b/src/Parlot/Fluent/OneOf.cs @@ -25,6 +25,8 @@ public override bool Parse(ParseContext context, ref ParseResult(); + var start = context.Scanner.Cursor.Position; + for (var i = 0; i < Parsers.Count; i++) { if (Parsers[i].Parse(context, ref parsed)) @@ -32,6 +34,9 @@ public override bool Parse(ParseContext context, ref ParseResult result) return false; } + var start = context.Scanner.Cursor.Position; + for (var i = 0; i < Parsers.Count; i++) { if (Parsers[i].Parse(context, ref result)) { return true; } + + // If the choice as a subset of its parsers that succeeded, it might have advanced the cursor + context.Scanner.Cursor.ResetPosition(start); } return false; diff --git a/src/Parlot/Fluent/Sequence.cs b/src/Parlot/Fluent/Sequence.cs index 0535fb0..ee15da6 100644 --- a/src/Parlot/Fluent/Sequence.cs +++ b/src/Parlot/Fluent/Sequence.cs @@ -28,6 +28,8 @@ public override bool Parse(ParseContext context, ref ParseResult(parseResult1.Value, parseResult2.Value)); return true; } + + context.Scanner.Cursor.ResetPosition(parseResult1.Start); } return false; @@ -69,6 +71,8 @@ public override bool Parse(ParseContext context, ref ParseResult(); + var start = context.Scanner.Cursor.Position; + for (var i = 0; i < _parsers.Length; i++) { if (!_parsers[i].Parse(context, ref parsed)) @@ -279,6 +293,7 @@ public override bool Parse(ParseContext context, ref ParseResult result) result.Set(parseResult1.Buffer, parseResult1.Start, parseResult2.End, parseResult2.Value); return true; } + + context.Scanner.Cursor.ResetPosition(parseResult1.Start); } return false; diff --git a/src/Parlot/Fluent/TextBefore.cs b/src/Parlot/Fluent/TextBefore.cs index fdbf1eb..a92d423 100644 --- a/src/Parlot/Fluent/TextBefore.cs +++ b/src/Parlot/Fluent/TextBefore.cs @@ -26,6 +26,12 @@ public override bool Parse(ParseContext context, ref ParseResult resul var parsed = new ParseResult(); + if (_delimiter.Parse(context, ref parsed)) + { + context.Scanner.Cursor.ResetPosition(start); + return false; + } + while (true) { if (_delimiter.Parse(context, ref parsed) || (!_failOnEof && context.Scanner.Cursor.Eof)) @@ -88,6 +94,12 @@ public override bool Parse(ParseContext context, ref ParseResult resul var parsed = new ParseResult(); + if (_delimiter.Parse(context, ref parsed)) + { + context.Scanner.Cursor.ResetPosition(start); + return false; + } + while (true) { if (_delimiter.Parse(context, ref parsed) || (!_failOnEof && context.Scanner.Cursor.Eof)) diff --git a/test/Parlot.Tests/FluentTests.cs b/test/Parlot.Tests/FluentTests.cs index 4b60dd8..d6d7499 100644 --- a/test/Parlot.Tests/FluentTests.cs +++ b/test/Parlot.Tests/FluentTests.cs @@ -248,5 +248,17 @@ public void NumbersShouldAcceptSignIfAllowed() Assert.Equal(-123, Terms.Decimal(NumberOptions.AllowSign).Parse("-123")); Assert.Equal(-123, Terms.Integer(NumberOptions.AllowSign).Parse("-123")); } + + [Fact] + public void OneOfShouldRestorePosition() + { + var choice = OneOf( + Literals.Char('a').And(Literals.Char('b')).And(Literals.Char('c')).And(Literals.Char('d')), + Literals.Char('a').And(Literals.Char('b')).And(Literals.Char('e')).And(Literals.Char('d')) + ).Then(x => x.Item1.ToString() + x.Item2.ToString() + x.Item3.ToString() + x.Item4.ToString()); + + Assert.Equal("abcd", choice.Parse("abcd")); + Assert.Equal("abed", choice.Parse("abed")); + } } }