Skip to content

Commit c331846

Browse files
committed
remove span from tokens
1 parent 808641e commit c331846

File tree

8 files changed

+90
-53
lines changed

8 files changed

+90
-53
lines changed

Discord.Net.ComponentDesigner.sln.DotSettings.user

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,5 +123,6 @@
123123
<TestId>xUnit::460851AC-1EFE-43D7-BCF1-396248CFB58D::net9.0::UnitTests.ComponentTests.SectionTests.EmptySection</TestId>
124124
<TestId>xUnit::460851AC-1EFE-43D7-BCF1-396248CFB58D::net9.0::UnitTests.ComponentTests.SectionTests.SectionWithInlineAccessory</TestId>
125125
<TestId>xUnit::460851AC-1EFE-43D7-BCF1-396248CFB58D::net9.0::UnitTests.ComponentTests.SectionTests.SectionWithChildAccessory</TestId>
126+
<TestId>xUnit::460851AC-1EFE-43D7-BCF1-396248CFB58D::net9.0::UnitTests.ParseTests.SyntaxTests.AttributesWithAndWithoutValues</TestId>
126127
</TestAncestor>
127128
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>

src/Discord.Net.ComponentDesigner.Parser/CXParser.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ internal CXNode ParseRootNode()
107107

108108
internal CXElement ParseElement()
109109
{
110-
if (IsIncremental && CurrentNode is CXElement element)
110+
if (IsIncremental && CurrentNode is CXElement incElement)
111111
{
112112
EatNode();
113-
return element;
113+
return incElement;
114114
}
115115

116116
using var _ = Lexer.SetMode(CXLexer.LexMode.Default);
@@ -153,10 +153,11 @@ CurrentToken.Kind is CXTokenKind.GreaterThan
153153
end,
154154
out var endStart,
155155
out var endIdent,
156-
out var endClose
156+
out var endClose,
157+
out var onCreate
157158
);
158159

159-
return new CXElement(
160+
var element = new CXElement(
160161
start,
161162
identifier,
162163
attributes,
@@ -166,6 +167,10 @@ out var endClose
166167
endIdent,
167168
endClose
168169
) { Diagnostics = diagnostics };
170+
171+
onCreate?.Invoke(element);
172+
173+
return element;
169174
default:
170175
case CXTokenKind.ForwardSlashGreaterThan:
171176
return new CXElement(
@@ -181,8 +186,11 @@ void ParseClosingElement(
181186
CXToken elementEnd,
182187
out CXToken elementEndStart,
183188
out CXToken? elementEndIdent,
184-
out CXToken elementEndClose)
189+
out CXToken elementEndClose,
190+
out Action<CXElement>? onCreate
191+
)
185192
{
193+
onCreate = null;
186194
var sentinel = _tokenIndex;
187195

188196
elementEndStart = Expect(CXTokenKind.LessThanForwardSlash);
@@ -213,20 +221,17 @@ var missingStructure
213221
missingStructure
214222
)
215223
{
216-
var diagnosticSpan = TextSpan.FromBounds(start.Span.Start, elementEnd.Span.End);
217-
218-
diagnostics.Add(
219-
CXDiagnostic.MissingElementClosingTag(identifier, diagnosticSpan)
220-
);
221-
222-
var missingSpan = elementEndStart.Span;
224+
onCreate = node =>
225+
{
226+
node.AddDiagnostic(CXDiagnostic.MissingElementClosingTag(identifier, node));
227+
};
223228

224-
elementEndStart = CXToken.CreateMissing(CXTokenKind.LessThanForwardSlash, missingSpan);
225-
elementEndIdent = identifier is not null
226-
? CXToken.CreateMissing(CXTokenKind.Identifier, missingSpan, identifier.Value)
229+
elementEndStart = CXToken.CreateMissing(CXTokenKind.LessThanForwardSlash);
230+
elementEndIdent = identifier is not null
231+
? CXToken.CreateMissing(CXTokenKind.Identifier, identifier.Value)
227232
: null;
228-
elementEndClose = CXToken.CreateMissing(CXTokenKind.GreaterThan, missingSpan);
229-
233+
elementEndClose = CXToken.CreateMissing(CXTokenKind.GreaterThan);
234+
230235
// rollback
231236
_tokenIndex = sentinel;
232237
}
@@ -392,7 +397,7 @@ internal CXValue ParseAttributeValue()
392397
ParseElement(),
393398
Expect(CXTokenKind.CloseParenthesis)
394399
);
395-
400+
396401
case CXTokenKind.Interpolation:
397402
return new CXValue.Interpolation(
398403
Eat(),
@@ -522,7 +527,6 @@ internal CXToken Expect(params ReadOnlySpan<CXTokenKind> kinds)
522527

523528
return new CXToken(
524529
kinds[0],
525-
new TextSpan(current.Span.Start, 1),
526530
0,
527531
0,
528532
Flags: CXTokenFlags.Missing,
@@ -540,7 +544,6 @@ internal CXToken Expect(CXTokenKind kind)
540544
{
541545
return new CXToken(
542546
kind,
543-
new TextSpan(token.Span.Start, 1),
544547
0,
545548
0,
546549
Flags: CXTokenFlags.Missing,

src/Discord.Net.ComponentDesigner.Parser/Diagnostics/CXDiagnostic.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@ public readonly record struct CXDiagnostic(
99
DiagnosticSeverity Severity,
1010
CXErrorCode Code,
1111
string Message,
12-
TextSpan Span
12+
ICXNode Owner
1313
)
1414
{
15-
public static CXDiagnostic MissingElementClosingTag(CXToken? identifier, TextSpan span)
15+
public TextSpan Span => Owner.Span;
16+
17+
public static CXDiagnostic MissingElementClosingTag(CXToken? identifier, ICXNode owner)
1618
=> new(
1719
DiagnosticSeverity.Error,
1820
CXErrorCode.MissingElementClosingTag,
1921
identifier is not null
2022
? $"Missing closing tag for '{identifier.Value}'"
2123
: "Missing fragment closing tag",
22-
span
24+
owner
2325
);
2426

2527
public static CXDiagnostic InvalidRootElement(CXToken token)
@@ -28,7 +30,7 @@ public static CXDiagnostic InvalidRootElement(CXToken token)
2830
DiagnosticSeverity.Error,
2931
CXErrorCode.InvalidRootElement,
3032
$"'{token.Kind}' is not a valid root element",
31-
token.FullSpan
33+
token
3234
);
3335
}
3436

@@ -38,7 +40,7 @@ public static CXDiagnostic InvalidElementChildToken(CXToken token)
3840
DiagnosticSeverity.Error,
3941
CXErrorCode.InvalidElementChildToken,
4042
$"'{token.Kind}' is not a valid child of an element",
41-
token.FullSpan
43+
token
4244
);
4345
}
4446

@@ -48,7 +50,7 @@ public static CXDiagnostic InvalidStringLiteralToken(CXToken token)
4850
DiagnosticSeverity.Error,
4951
CXErrorCode.InvalidStringLiteralToken,
5052
$"'{token.Kind}' is not valid within a string literal",
51-
token.FullSpan
53+
token
5254
);
5355
}
5456

@@ -64,15 +66,15 @@ or CXTokenKind.EOF
6466
DiagnosticSeverity.Error,
6567
CXErrorCode.MissingAttributeValue,
6668
"Missing attribute value",
67-
token.FullSpan
69+
token
6870
);
6971
}
7072

7173
return new CXDiagnostic(
7274
DiagnosticSeverity.Error,
7375
CXErrorCode.InvalidAttributeValue,
7476
$"'{token.Kind}' is not a valid attribute value token",
75-
token.FullSpan
77+
token
7678
);
7779
}
7880

@@ -83,7 +85,7 @@ params CXTokenKind[] expected
8385
DiagnosticSeverity.Error,
8486
CXErrorCode.UnexpectedToken,
8587
$"Unexpected token; expected {FormatExpected(expected)}, but got '{token.Kind}'",
86-
token.FullSpan
88+
token
8789
);
8890

8991
private static string FormatExpected(CXTokenKind[] kinds)

src/Discord.Net.ComponentDesigner.Parser/Incremental/CXBlender.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,7 @@ private bool TryTakeOldNodeOrToken(
267267
}
268268

269269
MoveToNextSibling(ref cursor);
270-
271-
if (current is CXToken token)
272-
current = token.WithNewPosition(cursor.NewPosition);
273-
270+
274271
blendedNode = new(
275272
current,
276273
cursor with {NewPosition = cursor.NewPosition + current.FullSpan.Length,}

src/Discord.Net.ComponentDesigner.Parser/Lexer/CXLexer.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public enum LexMode
3232

3333
public const char NULL_CHAR = '\0';
3434
public const char NEWLINE_CHAR = '\n';
35-
public const char CARRAGE_RETURN_CHAR = '\r';
35+
public const char CARRIAGE_RETURN_CHAR = '\r';
3636

3737
public const char UNDERSCORE_CHAR = '_';
3838
public const char HYPHEN_CHAR = '-';
@@ -190,7 +190,6 @@ public CXToken Next()
190190

191191
var token = new CXToken(
192192
info.Kind,
193-
fullSpan,
194193
info.LeadingTriviaLength,
195194
info.TrailingTriviaLength,
196195
info.Flags,
@@ -452,7 +451,7 @@ private void GetTrivia(bool isTrailing, ref int trivia)
452451

453452
if (CurrentInterpolationSpan is not null) return;
454453

455-
if (current is CARRAGE_RETURN_CHAR && Reader.Next is NEWLINE_CHAR)
454+
if (current is CARRIAGE_RETURN_CHAR && Reader.Next is NEWLINE_CHAR)
456455
{
457456
trivia += 2;
458457
Reader.Advance(2);

src/Discord.Net.ComponentDesigner.Parser/Lexer/CXToken.cs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.CodeAnalysis;
1+
using System;
2+
using Microsoft.CodeAnalysis;
23
using Microsoft.CodeAnalysis.Text;
34
using System.Collections.Generic;
45
using System.Collections.Immutable;
@@ -8,7 +9,6 @@ namespace Discord.CX.Parser;
89

910
public sealed record CXToken(
1011
CXTokenKind Kind,
11-
TextSpan FullSpan,
1212
int LeadingTriviaLength,
1313
int TrailingTriviaLength,
1414
CXTokenFlags Flags,
@@ -26,6 +26,48 @@ params IReadOnlyList<CXDiagnostic> Diagnostics
2626
FullValue.Length - LeadingTriviaLength - TrailingTriviaLength
2727
);
2828

29+
public TextSpan FullSpan
30+
{
31+
get
32+
{
33+
return new TextSpan(
34+
GetOffset(),
35+
FullValue.Length
36+
);
37+
38+
int GetOffset()
39+
{
40+
if(Parent is null) return 0;
41+
42+
var parentOffset = Parent.Offset;
43+
var parentSlotIndex = GetParentSlotIndex();
44+
45+
return parentSlotIndex switch
46+
{
47+
-1 => throw new InvalidOperationException(),
48+
0 => parentOffset,
49+
_ => Parent.Slots[parentSlotIndex - 1].Value switch
50+
{
51+
CXNode sibling => sibling.Offset + sibling.Width,
52+
CXToken token => token.FullSpan.End,
53+
_ => throw new InvalidOperationException()
54+
}
55+
};
56+
}
57+
58+
int GetParentSlotIndex()
59+
{
60+
if (Parent is null) return -1;
61+
62+
for (var i = 0; i < Parent.Slots.Count; i++)
63+
if (Parent.Slots[i] == this)
64+
return i;
65+
66+
return -1;
67+
}
68+
}
69+
}
70+
2971
public CXNode? Parent { get; set; }
3072

3173
public bool HasErrors
@@ -65,7 +107,6 @@ public static CXToken CreateSynthetic(
65107
{
66108
return new CXToken(
67109
kind,
68-
span ?? default,
69110
0,
70111
0,
71112
CXTokenFlags.Synthetic | (flags ?? CXTokenFlags.None),
@@ -76,18 +117,15 @@ public static CXToken CreateSynthetic(
76117

77118
public static CXToken CreateMissing(
78119
CXTokenKind kind,
79-
TextSpan span,
80120
params IEnumerable<CXDiagnostic> diagnostics
81-
) => CreateMissing(kind, span, string.Empty, diagnostics);
121+
) => CreateMissing(kind, string.Empty, diagnostics);
82122

83123
public static CXToken CreateMissing(
84124
CXTokenKind kind,
85-
TextSpan span,
86125
string value,
87126
params IEnumerable<CXDiagnostic> diagnostics
88127
) => new(
89128
kind,
90-
span,
91129
0,
92130
0,
93131
Flags: CXTokenFlags.Missing,
@@ -100,13 +138,6 @@ public void ResetCachedState()
100138
_hasErrors = null;
101139
}
102140

103-
public CXToken WithNewPosition(int position)
104-
{
105-
if (FullSpan.Start == position) return this;
106-
107-
return this with { FullSpan = new(position, FullSpan.Length) };
108-
}
109-
110141
public override string ToString() => ToString(false, false);
111142
public string ToFullString() => ToString(true, true);
112143

src/Discord.Net.ComponentDesigner.Parser/Nodes/CXNode.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ public CXNode()
156156
_slots = [];
157157
}
158158

159+
public void AddDiagnostic(CXDiagnostic diagnostic)
160+
=> _diagnostics.Add(diagnostic);
161+
159162
private bool TryGetDocument(out CXDoc result)
160163
{
161164
if (_doc is not null)

tests/ParseTests/SyntaxTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -718,15 +718,14 @@ public void MissingElementCloseTag()
718718
allowErrors: true
719719
);
720720
{
721-
Diagnostic(CXErrorCode.MissingElementClosingTag);
722-
721+
CXElement barElement;
723722
Element();
724723
{
725724
Token(CXTokenKind.LessThan);
726725
Identifier("Foo");
727726
Token(CXTokenKind.GreaterThan);
728727

729-
Element();
728+
barElement = Element();
730729
{
731730
Token(CXTokenKind.LessThan);
732731
Identifier("Bar");
@@ -742,6 +741,8 @@ public void MissingElementCloseTag()
742741
Token(CXTokenKind.GreaterThan);
743742
}
744743

744+
Diagnostic(CXErrorCode.MissingElementClosingTag, span: barElement.Span);
745+
745746
EOF();
746747
}
747748
}

0 commit comments

Comments
 (0)