Skip to content
This repository was archived by the owner on Dec 19, 2018. It is now read-only.

Commit 6c8e900

Browse files
authored
Razor parser rewrite (#2590)
* Razor parser rewrite - Rewrite CSharp parser - Basic rewrite of HTML parser (More improvements to follow) - Define and generate syntax nodes and boilerplate - Rewrite ClassifiedSpan and TagHelperSpan generation logic - Rewrite TagHelper phase - Rewrite Intermediate phase - Rewrite other miscellaneous features and bug fixes - Rewrite partial parsing - Added some syntax manipulation APIs - Removed unused legacy types * Test changes - Update parser test infrastructure - Update tests - Regenerated baselines - Removed unused legacy types
1 parent 61565f6 commit 6c8e900

File tree

1,453 files changed

+53372
-36188
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,453 files changed

+53372
-36188
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.AspNetCore.Razor.Language.Legacy;
7+
using Microsoft.AspNetCore.Razor.Language.Syntax;
8+
9+
namespace Microsoft.AspNetCore.Razor.Language
10+
{
11+
internal class ClassifiedSpanVisitor : SyntaxWalker
12+
{
13+
private RazorSourceDocument _source;
14+
private List<ClassifiedSpanInternal> _spans;
15+
private BlockKindInternal _currentBlockKind;
16+
private SyntaxNode _currentBlock;
17+
18+
public ClassifiedSpanVisitor(RazorSourceDocument source)
19+
{
20+
_source = source;
21+
_spans = new List<ClassifiedSpanInternal>();
22+
_currentBlockKind = BlockKindInternal.Markup;
23+
}
24+
25+
public IReadOnlyList<ClassifiedSpanInternal> ClassifiedSpans => _spans;
26+
27+
public override void VisitRazorCommentBlock(RazorCommentBlockSyntax node)
28+
{
29+
WriteBlock(node, BlockKindInternal.Comment, razorCommentSyntax =>
30+
{
31+
WriteSpan(razorCommentSyntax.StartCommentTransition, SpanKindInternal.Transition, AcceptedCharactersInternal.None);
32+
WriteSpan(razorCommentSyntax.StartCommentStar, SpanKindInternal.MetaCode, AcceptedCharactersInternal.None);
33+
34+
var comment = razorCommentSyntax.Comment;
35+
if (comment.IsMissing)
36+
{
37+
// We need to generate a classified span at this position. So insert a marker in its place.
38+
comment = (SyntaxToken)SyntaxFactory.Token(SyntaxKind.Marker, string.Empty).Green.CreateRed(razorCommentSyntax, razorCommentSyntax.StartCommentStar.EndPosition);
39+
}
40+
WriteSpan(comment, SpanKindInternal.Comment, AcceptedCharactersInternal.Any);
41+
42+
WriteSpan(razorCommentSyntax.EndCommentStar, SpanKindInternal.MetaCode, AcceptedCharactersInternal.None);
43+
WriteSpan(razorCommentSyntax.EndCommentTransition, SpanKindInternal.Transition, AcceptedCharactersInternal.None);
44+
});
45+
}
46+
47+
public override void VisitCSharpCodeBlock(CSharpCodeBlockSyntax node)
48+
{
49+
if (node.Parent is CSharpStatementBodySyntax ||
50+
node.Parent is CSharpExplicitExpressionBodySyntax ||
51+
node.Parent is CSharpImplicitExpressionBodySyntax ||
52+
node.Parent is RazorDirectiveBodySyntax ||
53+
(_currentBlockKind == BlockKindInternal.Directive &&
54+
node.Children.Count == 1 &&
55+
node.Children[0] is CSharpStatementLiteralSyntax))
56+
{
57+
base.VisitCSharpCodeBlock(node);
58+
return;
59+
}
60+
61+
WriteBlock(node, BlockKindInternal.Statement, base.VisitCSharpCodeBlock);
62+
}
63+
64+
public override void VisitCSharpStatement(CSharpStatementSyntax node)
65+
{
66+
WriteBlock(node, BlockKindInternal.Statement, base.VisitCSharpStatement);
67+
}
68+
69+
public override void VisitCSharpExplicitExpression(CSharpExplicitExpressionSyntax node)
70+
{
71+
WriteBlock(node, BlockKindInternal.Expression, base.VisitCSharpExplicitExpression);
72+
}
73+
74+
public override void VisitCSharpImplicitExpression(CSharpImplicitExpressionSyntax node)
75+
{
76+
WriteBlock(node, BlockKindInternal.Expression, base.VisitCSharpImplicitExpression);
77+
}
78+
79+
public override void VisitRazorDirective(RazorDirectiveSyntax node)
80+
{
81+
WriteBlock(node, BlockKindInternal.Directive, base.VisitRazorDirective);
82+
}
83+
84+
public override void VisitCSharpTemplateBlock(CSharpTemplateBlockSyntax node)
85+
{
86+
WriteBlock(node, BlockKindInternal.Template, base.VisitCSharpTemplateBlock);
87+
}
88+
89+
public override void VisitMarkupBlock(MarkupBlockSyntax node)
90+
{
91+
WriteBlock(node, BlockKindInternal.Markup, base.VisitMarkupBlock);
92+
}
93+
94+
public override void VisitMarkupTagHelperAttributeValue(MarkupTagHelperAttributeValueSyntax node)
95+
{
96+
// We don't generate a classified span when the attribute value is a simple literal value.
97+
// This is done so we maintain the classified spans generated in 2.x which
98+
// used ConditionalAttributeCollapser (combines markup literal attribute values into one span with no block parent).
99+
if (node.Children.Count > 1 ||
100+
(node.Children.Count == 1 && node.Children[0] is MarkupDynamicAttributeValueSyntax))
101+
{
102+
WriteBlock(node, BlockKindInternal.Markup, base.VisitMarkupTagHelperAttributeValue);
103+
return;
104+
}
105+
106+
base.VisitMarkupTagHelperAttributeValue(node);
107+
}
108+
109+
public override void VisitMarkupTagBlock(MarkupTagBlockSyntax node)
110+
{
111+
WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupTagBlock);
112+
}
113+
114+
public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
115+
{
116+
WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupTagHelperElement);
117+
}
118+
119+
public override void VisitMarkupTagHelperStartTag(MarkupTagHelperStartTagSyntax node)
120+
{
121+
foreach (var child in node.Children)
122+
{
123+
if (child is MarkupTagHelperAttributeSyntax attribute)
124+
{
125+
Visit(attribute);
126+
}
127+
}
128+
}
129+
130+
public override void VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node)
131+
{
132+
// We don't want to generate a classified span for a tag helper end tag. Do nothing.
133+
}
134+
135+
public override void VisitMarkupAttributeBlock(MarkupAttributeBlockSyntax node)
136+
{
137+
WriteBlock(node, BlockKindInternal.Markup, n =>
138+
{
139+
var equalsSyntax = SyntaxFactory.MarkupTextLiteral(new SyntaxList<SyntaxToken>(node.EqualsToken));
140+
var mergedAttributePrefix = MergeTextLiteralSpans(node.NamePrefix, node.Name, node.NameSuffix, equalsSyntax, node.ValuePrefix);
141+
Visit(mergedAttributePrefix);
142+
Visit(node.Value);
143+
Visit(node.ValueSuffix);
144+
});
145+
}
146+
147+
public override void VisitMarkupTagHelperAttribute(MarkupTagHelperAttributeSyntax node)
148+
{
149+
Visit(node.Value);
150+
}
151+
152+
public override void VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
153+
{
154+
WriteBlock(node, BlockKindInternal.Markup, n =>
155+
{
156+
var mergedAttributePrefix = MergeTextLiteralSpans(node.NamePrefix, node.Name);
157+
Visit(mergedAttributePrefix);
158+
});
159+
}
160+
161+
public override void VisitMarkupCommentBlock(MarkupCommentBlockSyntax node)
162+
{
163+
WriteBlock(node, BlockKindInternal.HtmlComment, base.VisitMarkupCommentBlock);
164+
}
165+
166+
public override void VisitMarkupDynamicAttributeValue(MarkupDynamicAttributeValueSyntax node)
167+
{
168+
WriteBlock(node, BlockKindInternal.Markup, base.VisitMarkupDynamicAttributeValue);
169+
}
170+
171+
public override void VisitRazorMetaCode(RazorMetaCodeSyntax node)
172+
{
173+
WriteSpan(node, SpanKindInternal.MetaCode);
174+
base.VisitRazorMetaCode(node);
175+
}
176+
177+
public override void VisitCSharpTransition(CSharpTransitionSyntax node)
178+
{
179+
WriteSpan(node, SpanKindInternal.Transition);
180+
base.VisitCSharpTransition(node);
181+
}
182+
183+
public override void VisitMarkupTransition(MarkupTransitionSyntax node)
184+
{
185+
WriteSpan(node, SpanKindInternal.Transition);
186+
base.VisitMarkupTransition(node);
187+
}
188+
189+
public override void VisitCSharpStatementLiteral(CSharpStatementLiteralSyntax node)
190+
{
191+
WriteSpan(node, SpanKindInternal.Code);
192+
base.VisitCSharpStatementLiteral(node);
193+
}
194+
195+
public override void VisitCSharpExpressionLiteral(CSharpExpressionLiteralSyntax node)
196+
{
197+
WriteSpan(node, SpanKindInternal.Code);
198+
base.VisitCSharpExpressionLiteral(node);
199+
}
200+
201+
public override void VisitCSharpEphemeralTextLiteral(CSharpEphemeralTextLiteralSyntax node)
202+
{
203+
WriteSpan(node, SpanKindInternal.Code);
204+
base.VisitCSharpEphemeralTextLiteral(node);
205+
}
206+
207+
public override void VisitUnclassifiedTextLiteral(UnclassifiedTextLiteralSyntax node)
208+
{
209+
WriteSpan(node, SpanKindInternal.None);
210+
base.VisitUnclassifiedTextLiteral(node);
211+
}
212+
213+
public override void VisitMarkupLiteralAttributeValue(MarkupLiteralAttributeValueSyntax node)
214+
{
215+
WriteSpan(node, SpanKindInternal.Markup);
216+
base.VisitMarkupLiteralAttributeValue(node);
217+
}
218+
219+
public override void VisitMarkupTextLiteral(MarkupTextLiteralSyntax node)
220+
{
221+
if (node.Parent is MarkupLiteralAttributeValueSyntax)
222+
{
223+
base.VisitMarkupTextLiteral(node);
224+
return;
225+
}
226+
227+
WriteSpan(node, SpanKindInternal.Markup);
228+
base.VisitMarkupTextLiteral(node);
229+
}
230+
231+
public override void VisitMarkupEphemeralTextLiteral(MarkupEphemeralTextLiteralSyntax node)
232+
{
233+
WriteSpan(node, SpanKindInternal.Markup);
234+
base.VisitMarkupEphemeralTextLiteral(node);
235+
}
236+
237+
private void WriteBlock<TNode>(TNode node, BlockKindInternal kind, Action<TNode> handler) where TNode : SyntaxNode
238+
{
239+
var previousBlock = _currentBlock;
240+
var previousKind = _currentBlockKind;
241+
242+
_currentBlock = node;
243+
_currentBlockKind = kind;
244+
245+
handler(node);
246+
247+
_currentBlock = previousBlock;
248+
_currentBlockKind = previousKind;
249+
}
250+
251+
private void WriteSpan(SyntaxNode node, SpanKindInternal kind, AcceptedCharactersInternal? acceptedCharacters = null)
252+
{
253+
if (node.IsMissing)
254+
{
255+
return;
256+
}
257+
258+
var spanSource = node.GetSourceSpan(_source);
259+
var blockSource = _currentBlock.GetSourceSpan(_source);
260+
if (!acceptedCharacters.HasValue)
261+
{
262+
acceptedCharacters = AcceptedCharactersInternal.Any;
263+
var context = node.GetSpanContext();
264+
if (context != null)
265+
{
266+
acceptedCharacters = context.EditHandler.AcceptedCharacters;
267+
}
268+
}
269+
270+
var span = new ClassifiedSpanInternal(spanSource, blockSource, kind, _currentBlockKind, acceptedCharacters.Value);
271+
_spans.Add(span);
272+
}
273+
274+
private MarkupTextLiteralSyntax MergeTextLiteralSpans(params MarkupTextLiteralSyntax[] literalSyntaxes)
275+
{
276+
if (literalSyntaxes == null || literalSyntaxes.Length == 0)
277+
{
278+
return null;
279+
}
280+
281+
SyntaxNode parent = null;
282+
var position = 0;
283+
var seenFirstLiteral = false;
284+
var builder = Syntax.InternalSyntax.SyntaxListBuilder.Create();
285+
286+
foreach (var syntax in literalSyntaxes)
287+
{
288+
if (syntax == null)
289+
{
290+
continue;
291+
}
292+
else if (!seenFirstLiteral)
293+
{
294+
// Set the parent and position of the merged literal to the value of the first non-null literal.
295+
parent = syntax.Parent;
296+
position = syntax.Position;
297+
seenFirstLiteral = true;
298+
}
299+
300+
foreach (var token in syntax.LiteralTokens)
301+
{
302+
builder.Add(token.Green);
303+
}
304+
}
305+
306+
var mergedLiteralSyntax = Syntax.InternalSyntax.SyntaxFactory.MarkupTextLiteral(
307+
builder.ToList<Syntax.InternalSyntax.SyntaxToken>());
308+
309+
return (MarkupTextLiteralSyntax)mergedLiteralSyntax.CreateRed(parent, position);
310+
}
311+
}
312+
}

src/Microsoft.AspNetCore.Razor.Language/DefaultDirectiveSyntaxTreePass.cs

+21-15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using Microsoft.AspNetCore.Razor.Language.Extensions;
77
using Microsoft.AspNetCore.Razor.Language.Legacy;
8+
using Microsoft.AspNetCore.Razor.Language.Syntax;
89

910
namespace Microsoft.AspNetCore.Razor.Language
1011
{
@@ -23,37 +24,42 @@ public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree s
2324
{
2425
throw new ArgumentNullException(nameof(syntaxTree));
2526
}
26-
27-
var sectionVerifier = new NestedSectionVerifier();
28-
sectionVerifier.Verify(syntaxTree);
29-
30-
return syntaxTree;
27+
28+
var sectionVerifier = new NestedSectionVerifier(syntaxTree);
29+
return sectionVerifier.Verify();
3130
}
3231

33-
private class NestedSectionVerifier : ParserVisitor
32+
private class NestedSectionVerifier : SyntaxRewriter
3433
{
3534
private int _nestedLevel;
35+
private RazorSyntaxTree _syntaxTree;
36+
37+
public NestedSectionVerifier(RazorSyntaxTree syntaxTree)
38+
{
39+
_syntaxTree = syntaxTree;
40+
}
3641

37-
public void Verify(RazorSyntaxTree tree)
42+
public RazorSyntaxTree Verify()
3843
{
39-
tree.Root.Accept(this);
44+
var root = Visit(_syntaxTree.Root);
45+
var rewrittenTree = new DefaultRazorSyntaxTree(root, _syntaxTree.Source, _syntaxTree.Diagnostics, _syntaxTree.Options);
46+
return rewrittenTree;
4047
}
4148

42-
public override void VisitDirectiveBlock(DirectiveChunkGenerator chunkGenerator, Block block)
49+
public override SyntaxNode VisitRazorDirective(RazorDirectiveSyntax node)
4350
{
4451
if (_nestedLevel > 0)
4552
{
46-
var directiveStart = block.Children.First(child => !child.IsBlock && ((Span)child).Kind == SpanKindInternal.Transition).Start;
53+
var directiveStart = node.Transition.GetSourceLocation(_syntaxTree.Source);
4754
var errorLength = /* @ */ 1 + SectionDirective.Directive.Directive.Length;
4855
var error = RazorDiagnosticFactory.CreateParsing_SectionsCannotBeNested(new SourceSpan(directiveStart, errorLength));
49-
chunkGenerator.Diagnostics.Add(error);
56+
node = node.AppendDiagnostic(error);
5057
}
51-
5258
_nestedLevel++;
53-
54-
VisitDefault(block);
55-
59+
var result = base.VisitRazorDirective(node);
5660
_nestedLevel--;
61+
62+
return result;
5763
}
5864
}
5965
}

0 commit comments

Comments
 (0)