private bool Rest(Parser <TToken, T> parser, ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, List <T> ts) { var lastStartingLoc = state.Location; var childExpecteds = new ExpectedCollector <TToken>(); var success = parser.TryParse(ref state, ref childExpecteds, out var result); while (success) { var endingLoc = state.Location; childExpecteds.Clear(); if (endingLoc <= lastStartingLoc) { childExpecteds.Dispose(); throw new InvalidOperationException("Many() used with a parser which consumed no input"); } ts.Add(result); lastStartingLoc = endingLoc; success = parser.TryParse(ref state, ref childExpecteds, out result); } var lastParserConsumedInput = state.Location > lastStartingLoc; expecteds.AddIf(ref childExpecteds, lastParserConsumedInput); childExpecteds.Dispose(); // we fail if the most recent parser failed after consuming input. // it sets state.Error for us return(!lastParserConsumedInput); }
// see comment about expecteds in ParseState.Error.cs internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out T result) { var firstTime = true; var err = new InternalError <TToken>( Maybe.Nothing <TToken>(), false, state.Location, "OneOf had no arguments" ); var childExpecteds = new ExpectedCollector <TToken>(); // the expecteds for all loop iterations var grandchildExpecteds = new ExpectedCollector <TToken>(); // the expecteds for the current loop iteration foreach (var p in _parsers) { var thisStartLoc = state.Location; var success = p.TryParse(ref state, ref grandchildExpecteds, out result); if (success) { // throw out all expecteds grandchildExpecteds.Dispose(); childExpecteds.Dispose(); return(true); } // we'll usually return the error from the first parser that didn't backtrack, // even if other parsers had a longer match. // There is some room for improvement here. if (state.Location > thisStartLoc) { // throw out all expecteds except this one expecteds.Add(ref grandchildExpecteds); childExpecteds.Dispose(); grandchildExpecteds.Dispose(); result = default; return(false); } childExpecteds.Add(ref grandchildExpecteds); grandchildExpecteds.Clear(); // choose the longest match, preferring the left-most error in a tie, // except the first time (avoid returning "OneOf had no arguments"). if (firstTime || state.Error.ErrorLocation > err.ErrorLocation) { err = state.Error; } firstTime = false; } state.Error = err; expecteds.Add(ref childExpecteds); childExpecteds.Dispose(); grandchildExpecteds.Dispose(); result = default; return(false); }
internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out U result) { var success1 = _parser.TryParse(ref state, ref expecteds, out var result1); if (!success1) { // state.Error set by _parser result = default; return(false); } var chainer = _factory(); chainer.Apply(result1); var lastStartLoc = state.Location; var childExpecteds = new ExpectedCollector <TToken>(); var success = _parser.TryParse(ref state, ref childExpecteds, out var childResult); while (success) { var endLoc = state.Location; childExpecteds.Clear(); if (endLoc <= lastStartLoc) { childExpecteds.Dispose(); chainer.OnError(); throw new InvalidOperationException("Many() used with a parser which consumed no input"); } chainer.Apply(childResult); lastStartLoc = endLoc; success = _parser.TryParse(ref state, ref childExpecteds, out childResult); } var lastParserConsumedInput = state.Location > lastStartLoc; expecteds.AddIf(ref childExpecteds, lastParserConsumedInput); childExpecteds.Dispose(); if (lastParserConsumedInput) // the most recent parser failed after consuming input { // state.Error set by _parser chainer.OnError(); result = default; return(false); } result = chainer.GetResult(); return(true); }
internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out T result) { var childExpecteds = new ExpectedCollector <TToken>(); var success = _parser.TryParse(ref state, ref childExpecteds, out result); expecteds.AddIf(ref childExpecteds, success); childExpecteds.Dispose(); if (!success) { return(false); } if (!_predicate(result)) { state.Error = new InternalError <TToken>( Maybe.Nothing <TToken>(), false, state.Location, _message(result) ); expecteds.Add(_expected); result = default; return(false); } return(true); }
internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out Unit result) { var startingLocation = state.Location; var token = state.HasCurrent ? Maybe.Just(state.Current) : Maybe.Nothing <TToken>(); state.PushBookmark(); // make sure we don't throw out the buffer, we may need it to compute a SourcePos var childExpecteds = new ExpectedCollector <TToken>(true); var success = _parser.TryParse(ref state, ref childExpecteds, out var result1); childExpecteds.Dispose(); state.PopBookmark(); if (success) { state.Error = new InternalError <TToken>( token, false, startingLocation, null ); result = default; return(false); } result = Unit.Value; return(true); }
// see comment about expecteds in ParseState.Error.cs internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out T result) { var childExpecteds = new ExpectedCollector <TToken>(); var success = _parser.TryParse(ref state, ref childExpecteds, out result); if (success) { childExpecteds.Dispose(); return(true); } var recoverParser = _errorHandler(state.BuildError(ref childExpecteds)); childExpecteds.Dispose(); return(recoverParser.TryParse(ref state, ref expecteds, out result)); }
internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out T result) { var childExpecteds = new ExpectedCollector <TToken>(true); var success = _parser.TryParse(ref state, ref childExpecteds, out result); childExpecteds.Dispose(); if (!success) { expecteds.Add(_expected); } return(success); }
private static Result <TToken, T> DoParse <TToken, T>(Parser <TToken, T> parser, ref ParseState <TToken> state) { var startingLoc = state.Location; var expecteds = new ExpectedCollector <TToken>(); var success = parser.TryParse(ref state, ref expecteds, out var result); var result1 = success ? new Result <TToken, T>(state.Location > startingLoc, result) : new Result <TToken, T>(state.Location > startingLoc, state.BuildError(ref expecteds)); expecteds.Dispose(); state.Dispose(); // ensure we return the state's buffers to the buffer pool return(result1); }
// see comment about expecteds in ParseState.Error.cs internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out IEnumerable <T>?result) { var ts = _keepResults ? new List <T>() : null; var firstItemStartLoc = state.Location; var firstItemSuccess = _parser.TryParse(ref state, ref expecteds, out var result1); if (!firstItemSuccess) { // state.Error set by _parser result = null; return(false); } if (state.Location <= firstItemStartLoc) { throw new InvalidOperationException("Until() used with a parser which consumed no input"); } ts?.Add(result1); var terminatorExpecteds = new ExpectedCollector <TToken>(); var itemExpecteds = new ExpectedCollector <TToken>(); while (true) { var terminatorStartLoc = state.Location; var terminatorSuccess = _terminator.TryParse(ref state, ref terminatorExpecteds, out var terminatorResult); if (terminatorSuccess) { terminatorExpecteds.Dispose(); itemExpecteds.Dispose(); result = ts; return(true); } if (state.Location > terminatorStartLoc) { // state.Error set by _terminator expecteds.Add(ref terminatorExpecteds); terminatorExpecteds.Dispose(); itemExpecteds.Dispose(); result = null; return(false); } var itemStartLoc = state.Location; var itemSuccess = _parser.TryParse(ref state, ref itemExpecteds, out var itemResult); var itemConsumedInput = state.Location > itemStartLoc; if (!itemSuccess) { if (!itemConsumedInput) { // get the expected from both _terminator and _parser expecteds.Add(ref terminatorExpecteds); expecteds.Add(ref itemExpecteds); } else { // throw out the _terminator expecteds and keep only _parser expecteds.Add(ref itemExpecteds); } terminatorExpecteds.Dispose(); itemExpecteds.Dispose(); result = null; return(false); } // throw out both sets of expecteds terminatorExpecteds.Clear(); itemExpecteds.Clear(); if (!itemConsumedInput) { throw new InvalidOperationException("Until() used with a parser which consumed no input"); } ts?.Add(itemResult); } }
internal sealed override bool TryParse(ref ParseState <TToken> state, ref ExpectedCollector <TToken> expecteds, out IEnumerable <T> result) { var success = _parser.TryParse(ref state, ref expecteds, out var result1); if (!success) { // state.Error set by _parser result = null; return(false); } var ts = new List <T> { result1 }; var childExpecteds = new ExpectedCollector <TToken>(); while (true) { var sepStartLoc = state.Location; var sepSuccess = _separator.TryParse(ref state, ref childExpecteds, out var _); var sepConsumedInput = state.Location > sepStartLoc; expecteds.AddIf(ref childExpecteds, !sepSuccess && sepConsumedInput); childExpecteds.Clear(); if (!sepSuccess) { childExpecteds.Dispose(); if (sepConsumedInput) { // state.Error set by _separator result = null; return(false); } result = ts; return(true); } var itemStartLoc = state.Location; var itemSuccess = _parser.TryParse(ref state, ref childExpecteds, out var itemResult); var itemConsumedInput = state.Location > itemStartLoc; expecteds.AddIf(ref childExpecteds, !itemSuccess && itemConsumedInput); childExpecteds.Clear(); if (!itemSuccess) { childExpecteds.Dispose(); if (itemConsumedInput) { // state.Error set by _parser result = null; return(false); } result = ts; return(true); } ts.Add(itemResult); } }