Skip to content

Commit b88178f

Browse files
committed
Initial commit, already some files added (tests not yet working due to GapFiller)
1 parent 56c5ae8 commit b88178f

30 files changed

+1506
-0
lines changed

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/.vs/
2+
/packages/
3+
/Parser/bin/
4+
/Parser/obj/
5+
/Tests/bin/
6+
/Tests/obj/
7+
8+
*.user

Parser/CharacterPositionFinder.cs

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
6+
using MiKoSolutions.SemanticParsers.TypeScript.Yaml;
7+
8+
namespace MiKoSolutions.SemanticParsers.TypeScript
9+
{
10+
public sealed class CharacterPositionFinder : IDisposable
11+
{
12+
private const int NewLine = 10; // '\n'
13+
private const int CarriageReturn = 13; // '\r'
14+
15+
private readonly List<MapInfo> _lineNumberToLengthAndCountMap;
16+
private readonly List<LineInfo> _characterPositionToLineInfoMap;
17+
18+
private CharacterPositionFinder(List<MapInfo> lineNumberToLengthAndCountMap, List<LineInfo> characterPositionToLineInfoMap)
19+
{
20+
_lineNumberToLengthAndCountMap = lineNumberToLengthAndCountMap;
21+
_characterPositionToLineInfoMap = characterPositionToLineInfoMap;
22+
}
23+
24+
public static CharacterPositionFinder CreateFrom(string filePath, Encoding encoding)
25+
{
26+
var lineNumber = 1;
27+
var count = -1;
28+
29+
var capacity = (int)new FileInfo(filePath).Length + 1;
30+
31+
var map = new List<MapInfo>(capacity / 4)
32+
{
33+
new MapInfo(0, count),
34+
};
35+
36+
var charPosToLineMap = new List<LineInfo>(capacity)
37+
{
38+
new LineInfo(1, 1),
39+
};
40+
41+
var lineLength = 0;
42+
43+
using (var reader = new StreamReader(filePath, encoding))
44+
{
45+
while (!reader.EndOfStream)
46+
{
47+
lineLength++;
48+
count++;
49+
50+
charPosToLineMap.Insert(count, new LineInfo(lineNumber, lineLength));
51+
52+
var index = reader.Read();
53+
switch (index)
54+
{
55+
case NewLine:
56+
{
57+
map.Insert(lineNumber++, new MapInfo(lineLength, count));
58+
lineLength = 0;
59+
break;
60+
}
61+
62+
case CarriageReturn:
63+
{
64+
// additional line break character ?
65+
var next = reader.Peek();
66+
if (next == NewLine)
67+
{
68+
// read over the character
69+
reader.Read();
70+
71+
lineLength++;
72+
count++;
73+
74+
charPosToLineMap.Insert(count, new LineInfo(lineNumber, lineLength));
75+
}
76+
77+
map.Insert(lineNumber++, new MapInfo(lineLength, count));
78+
lineLength = 0;
79+
break;
80+
}
81+
}
82+
}
83+
}
84+
85+
map.Insert(lineNumber, new MapInfo(lineLength, count));
86+
87+
return new CharacterPositionFinder(map, charPosToLineMap);
88+
}
89+
90+
public void Dispose()
91+
{
92+
_lineNumberToLengthAndCountMap.Clear();
93+
_characterPositionToLineInfoMap.Clear();
94+
}
95+
96+
public int GetCharacterPosition(LineInfo lineInfo) => GetCharacterPosition(lineInfo.LineNumber, lineInfo.LinePosition);
97+
98+
public int GetCharacterPosition(int lineNumber, int linePosition)
99+
{
100+
if (lineNumber == 0 && linePosition == 0)
101+
{
102+
return 0;
103+
}
104+
105+
var info = _lineNumberToLengthAndCountMap[lineNumber - 1]; // get previous line and then add the line position
106+
107+
return info.CharacterCount + linePosition;
108+
}
109+
110+
public int GetLineLength(LineInfo lineInfo) => GetLineLength(lineInfo.LineNumber);
111+
112+
public int GetLineLength(int lineNumber)
113+
{
114+
var info = _lineNumberToLengthAndCountMap[lineNumber];
115+
116+
return info.LineLength;
117+
}
118+
119+
public LineInfo GetLineInfo(int characterPosition)
120+
{
121+
if (characterPosition >= 0)
122+
{
123+
return _characterPositionToLineInfoMap[characterPosition];
124+
}
125+
126+
return LineInfo.None;
127+
}
128+
129+
private struct MapInfo : IEquatable<MapInfo>
130+
{
131+
internal readonly int LineLength;
132+
internal readonly int CharacterCount;
133+
134+
internal MapInfo(int lineLength, int characterCount)
135+
{
136+
LineLength = lineLength;
137+
CharacterCount = characterCount;
138+
}
139+
140+
public static bool operator ==(MapInfo left, MapInfo right) => left.Equals(right);
141+
142+
public static bool operator !=(MapInfo left, MapInfo right) => !left.Equals(right);
143+
144+
public bool Equals(MapInfo other) => LineLength == other.LineLength && CharacterCount == other.CharacterCount;
145+
146+
public override bool Equals(object obj) => obj is MapInfo other && Equals(other);
147+
148+
public override int GetHashCode()
149+
{
150+
unchecked
151+
{
152+
return (LineLength * 397) ^ CharacterCount;
153+
}
154+
}
155+
156+
public override string ToString() => string.Concat(nameof(LineLength) + "=", LineLength, " " + nameof(CharacterCount) + "=", CharacterCount);
157+
}
158+
}
159+
}

Parser/GapFiller.cs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Collections.Generic;
2+
3+
using MiKoSolutions.SemanticParsers.TypeScript.Yaml;
4+
5+
namespace MiKoSolutions.SemanticParsers.TypeScript
6+
{
7+
public static class GapFiller
8+
{
9+
public static void Fill(File file, CharacterPositionFinder finder)
10+
{
11+
var children = file.Children;
12+
for (var index = 0; index < children.Count; index++)
13+
{
14+
AdjustNode(children, index, finder);
15+
}
16+
17+
}
18+
19+
private static void AdjustChildren(Container container, CharacterPositionFinder finder)
20+
{
21+
var children = container.Children;
22+
23+
for (var index = 0; index < children.Count; index++)
24+
{
25+
AdjustNode(children, index, finder);
26+
}
27+
}
28+
29+
private static void AdjustNode(IList<ContainerOrTerminalNode> parentChildren, int indexInParentChildren, CharacterPositionFinder finder)
30+
{
31+
var child = parentChildren[indexInParentChildren];
32+
33+
if (indexInParentChildren > 0 && indexInParentChildren < parentChildren.Count - 1)
34+
{
35+
var previousSibling = parentChildren[indexInParentChildren - 1];
36+
37+
var indexAfter = finder.GetCharacterPosition(previousSibling.LocationSpan.End) + 1;
38+
var newStartPos = finder.GetLineInfo(indexAfter);
39+
40+
child.LocationSpan = new LocationSpan(newStartPos, child.LocationSpan.End);
41+
}
42+
43+
if (child is Container c)
44+
{
45+
var start = c.HeaderSpan.End + 1;
46+
47+
AdjustChildren(c, finder);
48+
49+
var end = finder.GetCharacterPosition(c.LocationSpan.End);
50+
c.FooterSpan = new CharacterSpan(start, end);
51+
}
52+
else if (child is TerminalNode t)
53+
{
54+
var start = finder.GetCharacterPosition(t.LocationSpan.Start);
55+
var end = finder.GetCharacterPosition(t.LocationSpan.End);
56+
t.Span = new CharacterSpan(start, end);
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)