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);
}
}
}