Created
February 2, 2025 05:50
-
-
Save Xevion/fe1fc6aa6b847ca4dfa92ba3e4bf0779 to your computer and use it in GitHub Desktop.
SuperPower Token Positioning
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using Microsoft.Diagnostics.Tracing.Parsers.MicrosoftWindowsTCPIP; | |
using Superpower; | |
namespace Netophone.Systems.Plot.Parsers; | |
public interface ILocated { | |
PositionSpan Span { set; } | |
} | |
public readonly record struct PositionSpan(int Start = -1, int End = -1) { | |
public bool HasValue => Start >= 0 && End >= 0; | |
/// <summary> | |
/// Apply the position span to acquire a substring of the source string. | |
/// </summary> | |
/// <param name="source"></param> | |
/// <returns></returns> | |
public string Substring(string source) { | |
if (!HasValue) throw new InvalidOperationException("PositionSpan must have a value to be used."); | |
return source.Substring(Start, End - Start); | |
} | |
} | |
public static class ParserExtensions { | |
/// <summary> | |
/// When applied, ensures the parser's result embeds the positioning information into the results. | |
/// </summary> | |
/// <param name="parser"></param> | |
/// <typeparam name="T">An ILocated type</typeparam> | |
/// <returns></returns> | |
public static TextParser<T> WithLocation<T>(this TextParser<T> parser) | |
where T : ILocated { | |
return i => { | |
var inner = parser(i); | |
if (!inner.HasValue) return inner; | |
inner.Value.Span = new PositionSpan( | |
inner.Location.Position.Absolute, inner.Location.Position.Absolute + inner.Location.Length | |
); | |
return inner; | |
}; | |
} | |
/// <summary> | |
/// When applied, ensures the parser's result embeds the positioning information into the results. | |
/// </summary> | |
/// <param name="parser"></param> | |
/// <typeparam name="TKind"></typeparam> | |
/// <typeparam name="T">An ILocated type</typeparam> | |
/// <returns></returns> | |
public static TokenListParser<TKind, T> WithLocation<TKind, T>(this TokenListParser<TKind, T> parser) | |
where T : ILocated { | |
return i => { | |
var inner = parser(i); | |
if (!inner.HasValue) return inner; | |
var last = inner.Remainder.Any() | |
// inner.Location contains both tokens used and the remainder, so get the last 'used' token | |
? inner.Location.ElementAt(inner.Location.Count() - inner.Remainder.Count() - 1) | |
// inner.Location is 100% used, just grab the last one | |
: inner.Location.Last(); | |
inner.Value.Span = new PositionSpan(inner.Location.First().Position.Absolute, | |
last.Position.Absolute + last.Span.Length); | |
return inner; | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment