using System; using System.Collections.Generic; using UniLinq; namespace Sprache { /// /// Contains helper functions to create instances. /// public static class Result { /// /// Creates a success result. /// /// The type of the result (value). /// The sucessfully parsed value. /// The remainder of the input. /// The new . public static IResult Success(T value, IInput remainder) { return new Result(value, remainder); } /// /// Creates a failure result. /// /// The type of the result. /// The remainder of the input. /// The error message. /// The parser expectations. /// The new . public static IResult Failure(IInput remainder, string message, IEnumerable expectations) { return new Result(remainder, message, expectations); } } internal class Result : IResult { private readonly T _value; private readonly IInput _remainder; private readonly bool _wasSuccessful; private readonly string _message; private readonly IEnumerable _expectations; public Result(T value, IInput remainder) { _value = value; _remainder = remainder; _wasSuccessful = true; _message = null; _expectations = Enumerable.Empty(); } public Result(IInput remainder, string message, IEnumerable expectations) { _value = default(T); _remainder = remainder; _wasSuccessful = false; _message = message; _expectations = expectations; } public T Value { get { if (!WasSuccessful) throw new InvalidOperationException("No value can be computed."); return _value; } } public bool WasSuccessful { get { return _wasSuccessful; } } public string Message { get { return _message; } } public IEnumerable Expectations { get { return _expectations; } } public IInput Remainder { get { return _remainder; } } public override string ToString() { if (WasSuccessful) return string.Format("Successful parsing of {0}.", Value); var expMsg = ""; if (Expectations.Any()) expMsg = " expected " + Expectations.Aggregate((e1, e2) => e1 + " or " + e2); var recentlyConsumed = CalculateRecentlyConsumed(); return string.Format("Parsing failure: {0};{1} ({2}); recently consumed: {3}", Message, expMsg, Remainder, recentlyConsumed); } private string CalculateRecentlyConsumed() { const int windowSize = 10; var totalConsumedChars = Remainder.Position; var windowStart = totalConsumedChars - windowSize; windowStart = windowStart < 0 ? 0 : windowStart; var numberOfRecentlyConsumedChars = totalConsumedChars - windowStart; return Remainder.Source.Substring(windowStart, numberOfRecentlyConsumedChars); } } }