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

Commit 57b9edc

Browse files
committed
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
1 parent fc3f45b commit 57b9edc

File tree

105 files changed

+15300
-7445
lines changed

Some content is hidden

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

105 files changed

+15300
-7445
lines changed
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
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 : SyntaxRewriter
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 SyntaxNode VisitRazorCommentBlock(RazorCommentBlockSyntax node)
28+
{
29+
return 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+
return razorCommentSyntax;
46+
});
47+
}
48+
49+
public override SyntaxNode VisitCSharpCodeBlock(CSharpCodeBlockSyntax node)
50+
{
51+
if (node.Parent is CSharpStatementBodySyntax ||
52+
node.Parent is CSharpExplicitExpressionBodySyntax ||
53+
node.Parent is CSharpImplicitExpressionBodySyntax ||
54+
node.Parent is RazorDirectiveBodySyntax ||
55+
(_currentBlockKind == BlockKindInternal.Directive &&
56+
node.Children.Count == 1 &&
57+
node.Children[0] is CSharpStatementLiteralSyntax))
58+
{
59+
return base.VisitCSharpCodeBlock(node);
60+
}
61+
62+
return WriteBlock(node, BlockKindInternal.Statement, base.VisitCSharpCodeBlock);
63+
}
64+
65+
public override SyntaxNode VisitCSharpStatement(CSharpStatementSyntax node)
66+
{
67+
return WriteBlock(node, BlockKindInternal.Statement, base.VisitCSharpStatement);
68+
}
69+
70+
public override SyntaxNode VisitCSharpExplicitExpression(CSharpExplicitExpressionSyntax node)
71+
{
72+
return WriteBlock(node, BlockKindInternal.Expression, base.VisitCSharpExplicitExpression);
73+
}
74+
75+
public override SyntaxNode VisitCSharpImplicitExpression(CSharpImplicitExpressionSyntax node)
76+
{
77+
return WriteBlock(node, BlockKindInternal.Expression, base.VisitCSharpImplicitExpression);
78+
}
79+
80+
public override SyntaxNode VisitRazorDirective(RazorDirectiveSyntax node)
81+
{
82+
return WriteBlock(node, BlockKindInternal.Directive, base.VisitRazorDirective);
83+
}
84+
85+
public override SyntaxNode VisitCSharpTemplateBlock(CSharpTemplateBlockSyntax node)
86+
{
87+
return WriteBlock(node, BlockKindInternal.Template, base.VisitCSharpTemplateBlock);
88+
}
89+
90+
public override SyntaxNode VisitMarkupBlock(MarkupBlockSyntax node)
91+
{
92+
return WriteBlock(node, BlockKindInternal.Markup, base.VisitMarkupBlock);
93+
}
94+
95+
public override SyntaxNode VisitGenericBlock(GenericBlockSyntax node)
96+
{
97+
if (!(node.Parent is MarkupTagHelperAttributeValueSyntax) &&
98+
node.FirstAncestorOrSelf<SyntaxNode>(n => n is MarkupTagHelperAttributeValueSyntax) != null)
99+
{
100+
return WriteBlock(node, BlockKindInternal.Expression, base.VisitGenericBlock);
101+
}
102+
103+
return base.VisitGenericBlock(node);
104+
}
105+
106+
public override SyntaxNode VisitMarkupTagHelperAttributeValue(MarkupTagHelperAttributeValueSyntax node)
107+
{
108+
// We don't generate a classified span when the attribute value is a simple literal value.
109+
if (node.Children.Count > 1 ||
110+
(node.Children.Count == 1 && node.Children[0] is MarkupDynamicAttributeValueSyntax))
111+
{
112+
return WriteBlock(node, BlockKindInternal.Markup, base.VisitMarkupTagHelperAttributeValue);
113+
}
114+
115+
return base.VisitMarkupTagHelperAttributeValue(node);
116+
}
117+
118+
public override SyntaxNode VisitMarkupTagBlock(MarkupTagBlockSyntax node)
119+
{
120+
return WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupTagBlock);
121+
}
122+
123+
public override SyntaxNode VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
124+
{
125+
return WriteBlock(node, BlockKindInternal.Tag, base.VisitMarkupTagHelperElement);
126+
}
127+
128+
public override SyntaxNode VisitMarkupTagHelperStartTag(MarkupTagHelperStartTagSyntax node)
129+
{
130+
var rewritten = new List<RazorSyntaxNode>();
131+
foreach (var child in node.Children)
132+
{
133+
if (child is MarkupTagHelperAttributeSyntax attribute)
134+
{
135+
var rewrittenAttribute = (MarkupTagHelperAttributeSyntax)Visit(attribute);
136+
rewritten.Add(rewrittenAttribute);
137+
}
138+
else
139+
{
140+
rewritten.Add(child);
141+
}
142+
}
143+
144+
return node.Update(new SyntaxList<RazorSyntaxNode>(rewritten));
145+
}
146+
147+
public override SyntaxNode VisitMarkupTagHelperEndTag(MarkupTagHelperEndTagSyntax node)
148+
{
149+
return node;
150+
}
151+
152+
public override SyntaxNode VisitMarkupAttributeBlock(MarkupAttributeBlockSyntax node)
153+
{
154+
return WriteBlock(node, BlockKindInternal.Markup, n =>
155+
{
156+
var equalsSyntax = SyntaxFactory.MarkupTextLiteral(new SyntaxList<SyntaxToken>(node.EqualsToken));
157+
var mergedAttributePrefix = MergeTextLiteralSpans(node.NamePrefix, node.Name, node.NameSuffix, equalsSyntax, node.ValuePrefix);
158+
Visit(mergedAttributePrefix);
159+
Visit(node.Value);
160+
Visit(node.ValueSuffix);
161+
162+
return n;
163+
});
164+
}
165+
166+
public override SyntaxNode VisitMarkupTagHelperAttribute(MarkupTagHelperAttributeSyntax node)
167+
{
168+
var rewrittenValue = (MarkupTagHelperAttributeValueSyntax)Visit(node.Value);
169+
170+
return node.Update(node.NamePrefix, node.Name, node.NameSuffix, node.EqualsToken, node.ValuePrefix, rewrittenValue, node.ValueSuffix);
171+
}
172+
173+
public override SyntaxNode VisitMarkupMinimizedAttributeBlock(MarkupMinimizedAttributeBlockSyntax node)
174+
{
175+
return WriteBlock(node, BlockKindInternal.Markup, n =>
176+
{
177+
var mergedAttributePrefix = MergeTextLiteralSpans(node.NamePrefix, node.Name);
178+
Visit(mergedAttributePrefix);
179+
180+
return n;
181+
});
182+
}
183+
184+
public override SyntaxNode VisitMarkupCommentBlock(MarkupCommentBlockSyntax node)
185+
{
186+
return WriteBlock(node, BlockKindInternal.HtmlComment, base.VisitMarkupCommentBlock);
187+
}
188+
189+
public override SyntaxNode VisitMarkupDynamicAttributeValue(MarkupDynamicAttributeValueSyntax node)
190+
{
191+
return WriteBlock(node, BlockKindInternal.Markup, base.VisitMarkupDynamicAttributeValue);
192+
}
193+
194+
public override SyntaxNode VisitRazorMetaCode(RazorMetaCodeSyntax node)
195+
{
196+
WriteSpan(node, SpanKindInternal.MetaCode);
197+
return base.VisitRazorMetaCode(node);
198+
}
199+
200+
public override SyntaxNode VisitCSharpTransition(CSharpTransitionSyntax node)
201+
{
202+
WriteSpan(node, SpanKindInternal.Transition);
203+
return base.VisitCSharpTransition(node);
204+
}
205+
206+
public override SyntaxNode VisitMarkupTransition(MarkupTransitionSyntax node)
207+
{
208+
WriteSpan(node, SpanKindInternal.Transition);
209+
return base.VisitMarkupTransition(node);
210+
}
211+
212+
public override SyntaxNode VisitCSharpStatementLiteral(CSharpStatementLiteralSyntax node)
213+
{
214+
WriteSpan(node, SpanKindInternal.Code);
215+
return base.VisitCSharpStatementLiteral(node);
216+
}
217+
218+
public override SyntaxNode VisitCSharpExpressionLiteral(CSharpExpressionLiteralSyntax node)
219+
{
220+
WriteSpan(node, SpanKindInternal.Code);
221+
return base.VisitCSharpExpressionLiteral(node);
222+
}
223+
224+
public override SyntaxNode VisitCSharpEphemeralTextLiteral(CSharpEphemeralTextLiteralSyntax node)
225+
{
226+
WriteSpan(node, SpanKindInternal.Code);
227+
return base.VisitCSharpEphemeralTextLiteral(node);
228+
}
229+
230+
public override SyntaxNode VisitUnclassifiedTextLiteral(UnclassifiedTextLiteralSyntax node)
231+
{
232+
WriteSpan(node, SpanKindInternal.None);
233+
return base.VisitUnclassifiedTextLiteral(node);
234+
}
235+
236+
public override SyntaxNode VisitMarkupLiteralAttributeValue(MarkupLiteralAttributeValueSyntax node)
237+
{
238+
WriteSpan(node, SpanKindInternal.Markup);
239+
return base.VisitMarkupLiteralAttributeValue(node);
240+
}
241+
242+
public override SyntaxNode VisitMarkupTextLiteral(MarkupTextLiteralSyntax node)
243+
{
244+
if (node.Parent is MarkupLiteralAttributeValueSyntax)
245+
{
246+
return base.VisitMarkupTextLiteral(node);
247+
}
248+
249+
WriteSpan(node, SpanKindInternal.Markup);
250+
return base.VisitMarkupTextLiteral(node);
251+
}
252+
253+
public override SyntaxNode VisitMarkupEphemeralTextLiteral(MarkupEphemeralTextLiteralSyntax node)
254+
{
255+
WriteSpan(node, SpanKindInternal.Markup);
256+
return base.VisitMarkupEphemeralTextLiteral(node);
257+
}
258+
259+
private SyntaxNode WriteBlock<TNode>(TNode node, BlockKindInternal kind, Func<TNode, SyntaxNode> handler) where TNode : SyntaxNode
260+
{
261+
var previousBlock = _currentBlock;
262+
var previousKind = _currentBlockKind;
263+
264+
_currentBlock = node;
265+
_currentBlockKind = kind;
266+
267+
var result = handler(node);
268+
269+
_currentBlock = previousBlock;
270+
_currentBlockKind = previousKind;
271+
272+
return result;
273+
}
274+
275+
private void WriteSpan(SyntaxNode node, SpanKindInternal kind, AcceptedCharactersInternal? acceptedCharacters = null)
276+
{
277+
if (node.IsMissing)
278+
{
279+
return;
280+
}
281+
282+
var spanSource = node.GetSourceSpan(_source);
283+
var blockSource = _currentBlock.GetSourceSpan(_source);
284+
if (!acceptedCharacters.HasValue)
285+
{
286+
acceptedCharacters = AcceptedCharactersInternal.Any;
287+
var context = node.GetSpanContext();
288+
if (context != null)
289+
{
290+
acceptedCharacters = context.EditHandler.AcceptedCharacters;
291+
}
292+
}
293+
294+
var span = new ClassifiedSpanInternal(spanSource, blockSource, kind, _currentBlockKind, acceptedCharacters.Value);
295+
_spans.Add(span);
296+
}
297+
298+
private MarkupTextLiteralSyntax MergeTextLiteralSpans(params MarkupTextLiteralSyntax[] literalSyntaxes)
299+
{
300+
if (literalSyntaxes == null || literalSyntaxes.Length == 0)
301+
{
302+
return null;
303+
}
304+
305+
SyntaxNode parent = null;
306+
var position = 0;
307+
var seenFirstLiteral = false;
308+
var builder = Syntax.InternalSyntax.SyntaxListBuilder.Create();
309+
310+
foreach (var syntax in literalSyntaxes)
311+
{
312+
if (syntax == null)
313+
{
314+
continue;
315+
}
316+
else if (!seenFirstLiteral)
317+
{
318+
// Set the parent and position of the merged literal to the value of the first non-null literal.
319+
parent = syntax.Parent;
320+
position = syntax.Position;
321+
seenFirstLiteral = true;
322+
}
323+
324+
foreach (var token in syntax.LiteralTokens)
325+
{
326+
builder.Add(token.Green);
327+
}
328+
}
329+
330+
var mergedLiteralSyntax = Syntax.InternalSyntax.SyntaxFactory.MarkupTextLiteral(
331+
builder.ToList<Syntax.InternalSyntax.SyntaxToken>());
332+
333+
return (MarkupTextLiteralSyntax)mergedLiteralSyntax.CreateRed(parent, position);
334+
}
335+
}
336+
}

0 commit comments

Comments
 (0)