...
This commit is contained in:
136
src/lang/Nub.Lang/Source.cs
Normal file
136
src/lang/Nub.Lang/Source.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Nub.Lang;
|
||||
|
||||
public readonly struct SourceSpan(SourceText content, SourceLocation start, SourceLocation end) : IEquatable<SourceSpan>
|
||||
{
|
||||
public SourceText Content { get; } = content;
|
||||
public SourceLocation Start { get; } = start;
|
||||
public SourceLocation End { get; } = end;
|
||||
|
||||
/// <summary>
|
||||
/// Merges one or more <see cref="SourceSpan"/> from a single file to a single <see cref="SourceSpan"/>
|
||||
/// </summary>
|
||||
/// <param name="spanEnumerable">The spans to merged</param>
|
||||
/// <returns>The merged <see cref="SourceSpan"/></returns>
|
||||
public static SourceSpan Merge(IEnumerable<SourceSpan> spanEnumerable)
|
||||
{
|
||||
var spans = spanEnumerable.ToArray();
|
||||
if (spans.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Cannot merge empty spans", nameof(spanEnumerable));
|
||||
}
|
||||
|
||||
var files = spans.Select(s => s.Content).Distinct().ToArray();
|
||||
if (files.Length > 1)
|
||||
{
|
||||
throw new ArgumentException("Cannot merge spans from multiple files", nameof(spanEnumerable));
|
||||
}
|
||||
|
||||
var first = spans.OrderBy(s => s.Start.Line).ThenBy(s => s.Start.Column).First().Start;
|
||||
var last = spans.OrderByDescending(s => s.End.Line).ThenByDescending(s => s.End.Column).Last().End;
|
||||
|
||||
return new SourceSpan(files[0], first, last);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Start.Line == End.Line)
|
||||
{
|
||||
if (Start.Column == End.Column)
|
||||
{
|
||||
return $"{Start.Line}:{Start.Column}";
|
||||
}
|
||||
|
||||
return $"{Start.Line}:{Start.Column}-{End.Column}";
|
||||
}
|
||||
|
||||
return $"{Start.Line}:{Start.Column}-{End.Line}:{End.Column}";
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is SourceSpan other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals(SourceSpan other)
|
||||
{
|
||||
return Content.Equals(other.Content) && Start.Equals(other.Start) && End.Equals(other.End);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Content, Start, End);
|
||||
}
|
||||
|
||||
public static bool operator ==(SourceSpan left, SourceSpan right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(SourceSpan left, SourceSpan right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct SourceText(string text) : IEquatable<SourceText>
|
||||
{
|
||||
public string Text { get; } = text;
|
||||
|
||||
public bool Equals(SourceText other)
|
||||
{
|
||||
return Text == other.Text;
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is SourceText other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Text.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(SourceText left, SourceText right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(SourceText left, SourceText right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct SourceLocation(int line, int column) : IEquatable<SourceLocation>
|
||||
{
|
||||
public int Line { get; } = line;
|
||||
public int Column { get; } = column;
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is SourceLocation other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals(SourceLocation other)
|
||||
{
|
||||
return Line == other.Line && Column == other.Column;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Line, Column);
|
||||
}
|
||||
|
||||
public static bool operator ==(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user