// 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); }
// see comment about expecteds in ParseState.Error.cs internal sealed override InternalResult <T> Parse(ref ParseState <TToken> state) { var firstTime = true; var err = new InternalError <TToken>( Maybe.Nothing <TToken>(), false, state.Location, "OneOf had no arguments" ); state.BeginExpectedTran(); foreach (var p in _parsers) { state.BeginExpectedTran(); var thisResult = p.Parse(ref state); if (thisResult.Success) { // throw out all expecteds state.EndExpectedTran(false); state.EndExpectedTran(false); return(thisResult); } // 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 (thisResult.ConsumedInput) { // throw out all expecteds except this one var expected = state.ExpectedTranState(); state.EndExpectedTran(false); state.EndExpectedTran(false); state.AddExpected(expected.AsSpan()); expected.Dispose(clearArray: true); return(thisResult); } state.EndExpectedTran(true); // 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; state.EndExpectedTran(true); return(InternalResult.Failure <T>(false)); }