/// <summary> /// Get the number of elements in a nested <see cref="SequenceResult{T1, T2}"/>, /// constructed and matched via Parser Combinators. /// </summary> /// <typeparam name="T1">Type of the first element in the <see cref="SequenceResult{T1, T2}"/>.</typeparam> /// <typeparam name="T2">Type of the second element in the <see cref="SequenceResult{T1, T2}"/>.</typeparam> /// <param name="result">The <see cref="SequenceResult{T1, T2}"/> to count the number of elements in.</param> /// <returns>The number of elements in a left-leaning nested <see cref="SequenceResult{T1, T2}"/>.</returns> public static int Count <T1, T2>(this SequenceResult <T1, T2> result) { var depth = 0; var type = result.GetType(); while (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(SequenceResult <,>)) { depth++; type = type.GetGenericArguments()[0]; } return(depth + 1); }
/// <summary> /// Get the item at the nth index in the given nested <see cref="SequenceResult{T1, T2}"/>, /// constructed and matched via Parser Combinators. Uses reflection to access elements dynamically, /// allowing the user to get to elements of very long sequences. /// </summary> /// <typeparam name="T1">Type of the first element in the <see cref="SequenceResult{T1, T2}"/>.</typeparam> /// <typeparam name="T2">Type of the second element in the <see cref="SequenceResult{T1, T2}"/>.</typeparam> /// <param name="result">The element at the nth index of this nested <see cref="SequenceResult{T1, T2}"/>, as an object.</param> /// <param name="index">Index to get the element of.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown if the index is less than 0 or greater than the number of elements in the sequence.</exception> /// <returns>The element matched in the given sequence at the given index.</returns> public static object ItemN <T1, T2>(this SequenceResult <T1, T2> result, int index) { var count = Count(result); if (index < 0 || index >= count) { throw new ArgumentOutOfRangeException("index", "Index must be a positive number less than the number of nested elements"); } object current = result; for (int i = 0; i < count - index - 1; i++) { current = current.GetType().GetProperty("First").GetValue(current); } return((index == 0) ? current : current.GetType().GetProperty("Next").GetValue(current)); }
/// <summary> /// Attempts to match an input string starting at the given index. /// </summary> /// <param name="input">String to match.</param> /// <param name="index">Index to begin matching at.</param> /// <returns>An <see cref="IParseResult{T}"/> containing the parsed value.</returns> public override IParseResult <SequenceResult <T1, T2> > Parse(string input, int index) { var i = index; var result1 = Parser1.Parse(input, i); if (!result1.Success) { var failure = (ParseFail <T1>)result1; return(new ParseFail <SequenceResult <T1, T2> >(failure.FailureType, failure.Index, failure.Message)); } i += result1.Length; var result2 = Parser2.Parse(input, i); if (!result2.Success) { var failure = (ParseFail <T2>)result2; return(new ParseFail <SequenceResult <T1, T2> >(failure.FailureType, failure.Index, failure.Message)); } var value = new SequenceResult <T1, T2>(result1.Value, result2.Value); return(new ParseSuccess <SequenceResult <T1, T2> >(string.Concat(result1.Text, result2.Text), value, index)); }