Skip to content

Commit

Permalink
Улучшения работы с текстовыми координатами (#110)
Browse files Browse the repository at this point in the history
* #107 - оптимизация ITextCoordinateSystemComputer.GetLines

* #107 - правка тестов

* #109 - Вынос логики построения координат в сервис

* #109 - тесты
  • Loading branch information
Stepami committed Feb 2, 2025
1 parent 29e047c commit 524fb4c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,19 @@ namespace HydraScript.Domain.FrontEnd.Lexer;

public interface ITextCoordinateSystemComputer
{
/// <summary>
/// Возвращает список индексов переноса строки внутри фрагмента исходного кода<br/>
/// Всегда начинается с -1
/// </summary>
public IReadOnlyList<int> GetLines(string text);

/// <summary>
/// Строит координату в формате (Строка, Столбец)
/// </summary>
/// <param name="absoluteIndex">Индекс символа от начала строки, в диапазоне [0, ДлинаСтроки)</param>
/// <param name="newLineList">Список индексов переноса строки <see cref="GetLines"/></param>
/// <returns></returns>
public Coordinates GetCoordinates(
int absoluteIndex,
IReadOnlyList<int> newLineList);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public List<Token> GetTokens(string text)

public IEnumerator<Token> GetEnumerator()
{
var matches = Structure.Regex.Matches(_text);
foreach (Match match in matches)
foreach (Match match in Structure.Regex.Matches(_text))
{
foreach (var type in Structure)
{
Expand All @@ -32,9 +31,8 @@ public IEnumerator<Token> GetEnumerator()

var value = group.Value;
var segment = new Segment(
new Coordinates(group.Index, _lines),
new Coordinates(group.Index + group.Length, _lines)
);
computer.GetCoordinates(group.Index, _lines),
computer.GetCoordinates(absoluteIndex: group.Index + group.Length, _lines));
var token = new Token(type, segment, value);

if (type.Error()) throw new LexerException(token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,40 @@ public class TextCoordinateSystemComputer : ITextCoordinateSystemComputer
{
private readonly SearchValues<char> _sv = SearchValues.Create(['\n']);

/// <inheritdoc/>
public IReadOnlyList<int> GetLines(string text)
{
var newText = text.EndsWith(Environment.NewLine)
? text
: text + Environment.NewLine;
var textLength = newText.Length;

LinkedList<int> indices = [];
var indices = new List<int>(capacity: 128) { -1 };
var textAsSpan = newText.AsSpan();
while (true)
{
var start = indices.Last != null ? indices.Last.Value + 1 : 0;
var start = indices[^1] + 1;
if (start == textLength)
break;
var textAsSpan = newText.AsSpan(
var index = textAsSpan.Slice(
start,
length: textLength - start);
var index = textAsSpan.IndexOfAny(_sv);
indices.AddLast(start + index);
length: textLength - start).IndexOfAny(_sv);
indices.Add(start + index);
}

return indices.ToList();
}

/// <inheritdoc/>
public Coordinates GetCoordinates(int absoluteIndex, IReadOnlyList<int> newLineList)
{
for (var i = 1; i < newLineList.Count; i++)
if (absoluteIndex <= newLineList[i])
{
var offset = newLineList[i - 1];
return new Coordinates(Line: i, Column: absoluteIndex - offset);
}

return new Coordinates();
}
}
15 changes: 1 addition & 14 deletions src/Domain/HydraScript.Domain.FrontEnd/Lexer/Token.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,8 @@ public static implicit operator string(Segment segment) =>
[ExcludeFromCodeCoverage]
public record Coordinates(int Line, int Column)
{
public Coordinates(int absolutePos, IReadOnlyList<int> system) :
this(0, 0)
public Coordinates() : this(Line: 1, Column: 1)
{
for (var i = 0; i < system.Count; i++)
if (absolutePos <= system[i])
{
var offset = i == 0 ? -1 : system[i - 1];
(Line, Column) = (i + 1, absolutePos - offset);
break;
}

if (Line == 0)
{
(Line, Column) = (system.Count + 1, 1);
}
}

public override string ToString() => $"({Line}, {Column})";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ public void GetLines_NoNewLine_SingleIndexResult()
{
const string text = "let x = 0";
var result = _sut.GetLines(text);
result.Should().BeEquivalentTo([text.Length + Environment.NewLine.Length - 1]);
result.Should().BeEquivalentTo([-1, text.Length + Environment.NewLine.Length - 1]);
}

[Fact]
public void GetLines_HasNewLine_SingleIndexResult()
{
var text = "let x = 0" + Environment.NewLine;
var result = _sut.GetLines(text);
result.Should().BeEquivalentTo([text.Length - 1]);
result.Should().BeEquivalentTo([-1, text.Length - 1]);
}

[Fact]
Expand All @@ -39,9 +39,33 @@ public void GetLines_HasNewLines_MultipleIndicesResult()
var result = _sut.GetLines(text);
result.Should().BeEquivalentTo(
[
-1,
stmt1.Length + Environment.NewLine.Length - 1,
stmt1.Length + stmt2.Length + Environment.NewLine.Length * 2 - 1,
stmt1.Length + stmt2.Length + stmt3.Length + Environment.NewLine.Length * 3 - 1
]);
}

[Theory, MemberData(nameof(EmptySystems))]
public void GetCoordinates_EmptySystem_StartCoordinatesReturned(IReadOnlyList<int> newLineList)
{
var coord = _sut.GetCoordinates(
absoluteIndex: Random.Shared.Next(0, int.MaxValue),
newLineList);
coord.Should().Be(new Coordinates());
}

public static TheoryData<IReadOnlyList<int>> EmptySystems =>
new([[], [-1]]);

[Fact]
public void GetCoordinates_NotEmptySystem_CorrectCoordinatesReturned()
{
// abcd\nabc\naaaa\n
// 4 8 13
IReadOnlyList<int> newLineList = [-1, 4, 8, 13];
// координата символа b
var coord = _sut.GetCoordinates(absoluteIndex: 6, newLineList);
coord.Should().Be(new Coordinates(Line: 2, Column: 2));
}
}

0 comments on commit 524fb4c

Please sign in to comment.