Change IR implementations to not hold all information in children.

- Added conditional attribute test.
- Reacted to Html optimization pass in tests.
- Removed directive IR bits since they'll be handled by the extensible directive system.

#844
This commit is contained in:
N. Taylor Mullen 2016-11-21 16:30:17 -08:00
parent d8b626c843
commit aa58ea6907
30 changed files with 417 additions and 323 deletions

View File

@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate; using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -11,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
protected override void ExecuteCore(RazorCodeDocument codeDocument) protected override void ExecuteCore(RazorCodeDocument codeDocument)
{ {
var syntaxTree = codeDocument.GetSyntaxTree(); var syntaxTree = codeDocument.GetSyntaxTree();
ThrowForMissingDependency<RazorSyntaxTree>(syntaxTree); ThrowForMissingDependency(syntaxTree);
var visitor = new Visitor(); var visitor = new Visitor();
@ -23,80 +25,89 @@ namespace Microsoft.AspNetCore.Razor.Evolution
private class Visitor : ParserVisitor private class Visitor : ParserVisitor
{ {
private readonly Stack<RazorIRBuilder> _builders;
public Visitor() public Visitor()
{ {
Builder = RazorIRBuilder.Document(); _builders = new Stack<RazorIRBuilder>();
var document = RazorIRBuilder.Document();
_builders.Push(document);
Namespace = new NamespaceDeclarationIRNode(); Namespace = new NamespaceDeclarationIRNode();
NamespaceBuilder = RazorIRBuilder.Create(Namespace);
Builder.Push(Namespace); Builder.Push(Namespace);
Class = new ClassDeclarationIRNode(); Class = new ClassDeclarationIRNode();
ClassBuilder = RazorIRBuilder.Create(Class);
Builder.Push(Class); Builder.Push(Class);
Method = new MethodDeclarationIRNode(); Method = new RazorMethodDeclarationIRNode();
Builder.Push(Method); Builder.Push(Method);
} }
public RazorIRBuilder Builder { get; } public RazorIRBuilder Builder => _builders.Peek();
public NamespaceDeclarationIRNode Namespace { get; } public NamespaceDeclarationIRNode Namespace { get; }
public RazorIRBuilder NamespaceBuilder { get; }
public ClassDeclarationIRNode Class { get; } public ClassDeclarationIRNode Class { get; }
public RazorIRBuilder ClassBuilder { get; } public RazorMethodDeclarationIRNode Method { get; }
public MethodDeclarationIRNode Method { get; } public override void VisitStartAttributeBlock(AttributeBlockChunkGenerator chunkGenerator, Block block)
public override void VisitStartAttributeBlock(AttributeBlockChunkGenerator chunk, Block block)
{ {
Builder.Push(new HtmlAttributeIRNode() var value = new ContainerRazorIRNode();
Builder.Add(new HtmlAttributeIRNode()
{ {
Name = chunk.Name, Name = chunkGenerator.Name,
Prefix = chunk.Prefix, Prefix = chunkGenerator.Prefix,
Suffix = chunk.Prefix, Value = value,
Suffix = chunkGenerator.Suffix,
SourceLocation = block.Start, SourceLocation = block.Start,
}); });
var valueBuilder = RazorIRBuilder.Create(value);
_builders.Push(valueBuilder);
} }
public override void VisitEndAttributeBlock(AttributeBlockChunkGenerator chunk, Block block) public override void VisitEndAttributeBlock(AttributeBlockChunkGenerator chunkGenerator, Block block)
{ {
Builder.Pop(); _builders.Pop();
} }
public override void VisitStartDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunk, Block block) public override void VisitStartDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunkGenerator, Block block)
{ {
Builder.Push(new CSharpAttributeValueIRNode() var content = new ContainerRazorIRNode();
Builder.Add(new CSharpAttributeValueIRNode()
{ {
Prefix = chunk.Prefix, Prefix = chunkGenerator.Prefix,
Content = content,
SourceLocation = block.Start, SourceLocation = block.Start,
}); });
var valueBuilder = RazorIRBuilder.Create(content);
_builders.Push(valueBuilder);
} }
public override void VisitEndDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunk, Block block) public override void VisitEndDynamicAttributeBlock(DynamicAttributeBlockChunkGenerator chunkGenerator, Block block)
{ {
Builder.Pop(); _builders.Pop();
} }
public override void VisitLiteralAttributeSpan(LiteralAttributeChunkGenerator chunk, Span span) public override void VisitLiteralAttributeSpan(LiteralAttributeChunkGenerator chunkGenerator, Span span)
{ {
Builder.Add(new HtmlAttributeValueIRNode() Builder.Add(new HtmlAttributeValueIRNode()
{ {
Prefix = chunk.Prefix, Prefix = chunkGenerator.Prefix,
Content = chunkGenerator.Value,
SourceLocation = span.Start, SourceLocation = span.Start,
}); });
} }
public override void VisitStartTemplateBlock(TemplateBlockChunkGenerator chunk, Block block) public override void VisitStartTemplateBlock(TemplateBlockChunkGenerator chunkGenerator, Block block)
{ {
Builder.Push(new TemplateIRNode()); Builder.Push(new TemplateIRNode());
} }
public override void VisitEndTemplateBlock(TemplateBlockChunkGenerator chunk, Block block) public override void VisitEndTemplateBlock(TemplateBlockChunkGenerator chunkGenerator, Block block)
{ {
Builder.Pop(); Builder.Pop();
} }
@ -107,20 +118,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// @DateTime.@*This is a comment*@Now // @DateTime.@*This is a comment*@Now
// //
// We need to capture this in the IR so that we can give each piece the correct source mappings // We need to capture this in the IR so that we can give each piece the correct source mappings
public override void VisitStartExpressionBlock(ExpressionChunkGenerator chunk, Block block) public override void VisitStartExpressionBlock(ExpressionChunkGenerator chunkGenerator, Block block)
{ {
Builder.Push(new CSharpExpressionIRNode() var value = new ContainerRazorIRNode();
Builder.Add(new CSharpExpressionIRNode()
{ {
Content = value,
SourceLocation = block.Start, SourceLocation = block.Start,
}); });
var valueBuilder = RazorIRBuilder.Create(value);
_builders.Push(valueBuilder);
} }
public override void VisitEndExpressionBlock(ExpressionChunkGenerator chunk, Block block) public override void VisitEndExpressionBlock(ExpressionChunkGenerator chunkGenerator, Block block)
{ {
Builder.Pop(); _builders.Pop();
} }
public override void VisitExpressionSpan(ExpressionChunkGenerator chunk, Span span) public override void VisitExpressionSpan(ExpressionChunkGenerator chunkGenerator, Span span)
{ {
Builder.Add(new CSharpTokenIRNode() Builder.Add(new CSharpTokenIRNode()
{ {
@ -129,44 +145,19 @@ namespace Microsoft.AspNetCore.Razor.Evolution
}); });
} }
public override void VisitStartSectionBlock(SectionChunkGenerator chunk, Block block) public override void VisitTypeMemberSpan(TypeMemberChunkGenerator chunkGenerator, Span span)
{ {
Builder.Push(new SectionIRNode() var functionsNode = new CSharpStatementIRNode()
{
Name = chunk.SectionName,
});
}
public override void VisitEndSectionBlock(SectionChunkGenerator chunk, Block block)
{
Builder.Pop();
}
public override void VisitTypeMemberSpan(TypeMemberChunkGenerator chunk, Span span)
{
ClassBuilder.Add(new CSharpStatementIRNode()
{ {
Content = span.Content, Content = span.Content,
SourceLocation = span.Start, SourceLocation = span.Start,
}); Parent = Class,
};
Class.Children.Add(functionsNode);
} }
public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunk, Span span) public override void VisitStatementSpan(StatementChunkGenerator chunkGenerator, Span span)
{
// Empty for now
}
public override void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunk, Span span)
{
// Empty for now
}
public override void VisitTagHelperPrefixSpan(TagHelperPrefixDirectiveChunkGenerator chunk, Span span)
{
// Empty for now
}
public override void VisitStatementSpan(StatementChunkGenerator chunk, Span span)
{ {
Builder.Add(new CSharpStatementIRNode() Builder.Add(new CSharpStatementIRNode()
{ {
@ -175,21 +166,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution
}); });
} }
public override void VisitSetBaseTypeSpan(SetBaseTypeChunkGenerator chunk, Span span) public override void VisitMarkupSpan(MarkupChunkGenerator chunkGenerator, Span span)
{ {
Class.BaseType = span.Content; var currentChildren = Builder.Current.Children;
} if (currentChildren.Count > 0 && currentChildren[currentChildren.Count - 1] is HtmlContentIRNode)
public override void VisitMarkupSpan(MarkupChunkGenerator chunk, Span span)
{
Builder.Add(new HtmlContentIRNode()
{ {
Content = span.Content, var existingHtmlContent = (HtmlContentIRNode)currentChildren[currentChildren.Count - 1];
SourceLocation = span.Start, existingHtmlContent.Content = string.Concat(existingHtmlContent.Content, span.Content);
}); }
else
{
Builder.Add(new HtmlContentIRNode()
{
Content = span.Content,
SourceLocation = span.Start,
});
}
} }
public override void VisitImportSpan(AddImportChunkGenerator chunk, Span span) public override void VisitImportSpan(AddImportChunkGenerator chunkGenerator, Span span)
{ {
// For prettiness, let's insert the usings before the class declaration. // For prettiness, let's insert the usings before the class declaration.
var i = 0; var i = 0;
@ -210,6 +205,47 @@ namespace Microsoft.AspNetCore.Razor.Evolution
Namespace.Children.Insert(i, @using); Namespace.Children.Insert(i, @using);
} }
private class ContainerRazorIRNode : RazorIRNode
{
private SourceLocation? _location;
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation
{
get
{
if (_location == null)
{
if (Children.Count > 0)
{
return Children[0].SourceLocation;
}
return SourceLocation.Undefined;
}
return _location.Value;
}
set
{
_location = value;
}
}
public override void Accept(RazorIRNodeVisitor visitor)
{
visitor.VisitDefault(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
return visitor.VisitDefault(this);
}
}
} }
} }
} }

View File

@ -1,29 +0,0 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class BlockDirectiveIRNode : RazorIRNode
{
public string Name { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
visitor.VisitBlockDirective(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
return visitor.VisitBlockDirective(this);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,21 +9,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class CSharpAttributeValueIRNode : RazorIRNode public class CSharpAttributeValueIRNode : RazorIRNode
{ {
public string Prefix { get; set; } public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; } internal override SourceLocation SourceLocation { get; set; }
public string Prefix { get; set; }
public RazorIRNode Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpAttributeValue(this); visitor.VisitCSharpAttributeValue(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpAttributeValue(this); return visitor.VisitCSharpAttributeValue(this);
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,21 +9,31 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class CSharpExpressionIRNode : RazorIRNode public class CSharpExpressionIRNode : RazorIRNode
{ {
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>(); public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; } internal override SourceLocation SourceLocation { get; set; }
public string Content { get; set; } public RazorIRNode Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpExpression(this); visitor.VisitCSharpExpression(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpExpression(this); return visitor.VisitCSharpExpression(this);
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class CSharpStatementIRNode : RazorIRNode public class CSharpStatementIRNode : RazorIRNode
{ {
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>(); public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }
@ -18,11 +19,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpStatement(this); visitor.VisitCSharpStatement(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpStatement(this); return visitor.VisitCSharpStatement(this);
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -18,11 +19,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpToken(this); visitor.VisitCSharpToken(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpToken(this); return visitor.VisitCSharpToken(this);
} }
} }

View File

@ -9,6 +9,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class ClassDeclarationIRNode : RazorIRNode public class ClassDeclarationIRNode : RazorIRNode
{ {
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public string AccessModifier { get; set; } public string AccessModifier { get; set; }
public string Name { get; set; } public string Name { get; set; }
@ -17,19 +23,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public IList<string> Interfaces { get; set; } public IList<string> Interfaces { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitClass(this); visitor.VisitClass(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitClass(this); return visitor.VisitClass(this);
} }
} }

View File

@ -42,10 +42,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
node = Pop(); node = Pop();
} }
return node; return node;
} }
public override RazorIRNode Pop() public override RazorIRNode Pop()
{ {
if (_depth == 0) if (_depth == 0)

View File

@ -1,27 +0,0 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class DirectiveTokenIRNode : RazorIRNode
{
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
visitor.VisitDirectiveToken(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
return visitor.VisitDirectiveToken(this);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -16,11 +17,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitDocument(this); visitor.VisitDocument(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitDocument(this); return visitor.VisitDocument(this);
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,25 +9,37 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class HtmlAttributeIRNode : RazorIRNode public class HtmlAttributeIRNode : RazorIRNode
{ {
public string Name { get; set; } public override IList<RazorIRNode> Children { get; } = EmptyArray;
public string Prefix { get; set; }
public string Suffix { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; } internal override SourceLocation SourceLocation { get; set; }
public string Name { get; set; }
public string Prefix { get; set; }
public RazorIRNode Value { get; set; }
public string Suffix { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitHtmlAttribute(this); visitor.VisitHtmlAttribute(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitHtmlAttribute(this); return visitor.VisitHtmlAttribute(this);
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,21 +9,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class HtmlAttributeValueIRNode : RazorIRNode public class HtmlAttributeValueIRNode : RazorIRNode
{ {
public string Prefix { get; set; } public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; } internal override SourceLocation SourceLocation { get; set; }
public string Prefix { get; set; }
public string Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitHtmlAttributeValue(this); visitor.VisitHtmlAttributeValue(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitHtmlAttributeValue(this); return visitor.VisitHtmlAttributeValue(this);
} }
} }

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public string Content { get; set; } public string Content { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>(); public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -14,13 +15,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
internal override SourceLocation SourceLocation { get; set; } internal override SourceLocation SourceLocation { get; set; }
public string Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitNamespace(this); visitor.VisitNamespace(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitNamespace(this); return visitor.VisitNamespace(this);
} }
} }

View File

@ -3,7 +3,7 @@
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public abstract class RazorIRNodeVisitor public abstract class RazorIRNodeVisitor
{ {
public virtual void Visit(RazorIRNode node) public virtual void Visit(RazorIRNode node)
{ {
@ -14,21 +14,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
} }
public virtual void VisitDirectiveToken(DirectiveTokenIRNode node)
{
VisitDefault(node);
}
public virtual void VisitTemplate(TemplateIRNode node) public virtual void VisitTemplate(TemplateIRNode node)
{ {
VisitDefault(node); VisitDefault(node);
} }
public virtual void VisitSection(SectionIRNode node)
{
VisitDefault(node);
}
public virtual void VisitCSharpStatement(CSharpStatementIRNode node) public virtual void VisitCSharpStatement(CSharpStatementIRNode node)
{ {
VisitDefault(node); VisitDefault(node);
@ -59,22 +49,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
VisitDefault(node); VisitDefault(node);
} }
public virtual void VisitSingleLineDirective(SingleLineDirectiveIRNode node)
{
VisitDefault(node);
}
public virtual void VisitBlockDirective(BlockDirectiveIRNode node)
{
VisitDefault(node);
}
public virtual void VisitClass(ClassDeclarationIRNode node) public virtual void VisitClass(ClassDeclarationIRNode node)
{ {
VisitDefault(node); VisitDefault(node);
} }
public virtual void VisitMethodDeclaration(MethodDeclarationIRNode node) public virtual void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
{ {
VisitDefault(node); VisitDefault(node);
} }

View File

@ -15,21 +15,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
return default(TResult); return default(TResult);
} }
public virtual TResult VisitDirectiveToken(DirectiveTokenIRNode node)
{
return VisitDefault(node);
}
public virtual TResult VisitTemplate(TemplateIRNode node) public virtual TResult VisitTemplate(TemplateIRNode node)
{ {
return VisitDefault(node); return VisitDefault(node);
} }
public virtual TResult VisitSection(SectionIRNode node)
{
return VisitDefault(node);
}
public virtual TResult VisitCSharpStatement(CSharpStatementIRNode node) public virtual TResult VisitCSharpStatement(CSharpStatementIRNode node)
{ {
return VisitDefault(node); return VisitDefault(node);
@ -65,16 +55,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
return VisitDefault(node); return VisitDefault(node);
} }
public virtual TResult VisitSingleLineDirective(SingleLineDirectiveIRNode node) public virtual TResult VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
{
return VisitDefault(node);
}
public virtual TResult VisitBlockDirective(BlockDirectiveIRNode node)
{
return VisitDefault(node);
}
public virtual TResult VisitMethodDeclaration(MethodDeclarationIRNode node)
{ {
return VisitDefault(node); return VisitDefault(node);
} }

View File

@ -1,13 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class MethodDeclarationIRNode : RazorIRNode public class RazorMethodDeclarationIRNode : RazorIRNode
{ {
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public string AccessModifier { get; set; } public string AccessModifier { get; set; }
public IList<string> Modifiers { get; set; } public IList<string> Modifiers { get; set; }
@ -16,20 +23,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public string ReturnType { get; set; } public string ReturnType { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
visitor.VisitMethodDeclaration(this); if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitRazorMethodDeclaration(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
return visitor.VisitMethodDeclaration(this); if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitRazorMethodDeclaration(this);
} }
} }
} }

View File

@ -1,29 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class SectionIRNode : RazorIRNode
{
public string Name { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
visitor.VisitSection(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
return visitor.VisitSection(this);
}
}
}

View File

@ -1,29 +0,0 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class SingleLineDirectiveIRNode : RazorIRNode
{
public string Name { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
visitor.VisitSingleLineDirective(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
return visitor.VisitSingleLineDirective(this);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy; using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -16,11 +17,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor) public override void Accept(RazorIRNodeVisitor visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitTemplate(this); visitor.VisitTemplate(this);
} }
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor) public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{ {
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitTemplate(this); return visitor.VisitTemplate(this);
} }
} }

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class UsingStatementIRNode : RazorIRNode public class UsingStatementIRNode : RazorIRNode
{ {
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>(); public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { get; set; } public override RazorIRNode Parent { get; set; }

View File

@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitAddTagHelperSpan(this, span);
} }
public override void GenerateChunk(Span target, ChunkGeneratorContext context) public override void GenerateChunk(Span target, ChunkGeneratorContext context)

View File

@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public virtual void VisitBlock(Block block) public virtual void VisitBlock(Block block)
{ {
VisitStartBlock(block); VisitStartBlock(block);
for (var i = 0; i < block.Children.Count; i++) for (var i = 0; i < block.Children.Count; i++)
{ {
block.Children[i].Accept(this); block.Children[i].Accept(this);
@ -69,14 +69,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{ {
} }
public virtual void VisitSetBaseTypeSpan(SetBaseTypeChunkGenerator chunk, Span span)
{
}
public virtual void VisitTagHelperPrefixSpan(TagHelperPrefixDirectiveChunkGenerator chunk, Span span)
{
}
public virtual void VisitTypeMemberSpan(TypeMemberChunkGenerator chunk, Span span) public virtual void VisitTypeMemberSpan(TypeMemberChunkGenerator chunk, Span span)
{ {
} }
@ -85,18 +77,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{ {
} }
public virtual void VisitRemoveTagHelperSpan(RemoveTagHelperChunkGenerator chunk, Span span)
{
}
public virtual void VisitImportSpan(AddImportChunkGenerator chunk, Span span) public virtual void VisitImportSpan(AddImportChunkGenerator chunk, Span span)
{ {
} }
public virtual void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunk, Span span)
{
}
public virtual void VisitStatementSpan(StatementChunkGenerator chunk, Span span) public virtual void VisitStatementSpan(StatementChunkGenerator chunk, Span span)
{ {
} }
@ -113,14 +97,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{ {
} }
public virtual void VisitStartSectionBlock(SectionChunkGenerator chunk, Block block)
{
}
public virtual void VisitEndSectionBlock(SectionChunkGenerator chunk, Block block)
{
}
public virtual void VisitEndCommentBlock(RazorCommentChunkGenerator chunk, Block block) public virtual void VisitEndCommentBlock(RazorCommentChunkGenerator chunk, Block block)
{ {
} }

View File

@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitRemoveTagHelperSpan(this, span);
} }
public override void GenerateChunk(Span target, ChunkGeneratorContext context) public override void GenerateChunk(Span target, ChunkGeneratorContext context)

View File

@ -16,12 +16,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void AcceptStart(ParserVisitor visitor, Block block) public override void AcceptStart(ParserVisitor visitor, Block block)
{ {
visitor.VisitStartSectionBlock(this, block);
} }
public override void AcceptEnd(ParserVisitor visitor, Block block) public override void AcceptEnd(ParserVisitor visitor, Block block)
{ {
visitor.VisitEndSectionBlock(this, block);
} }
public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context) public override void GenerateStartParentChunk(Block target, ChunkGeneratorContext context)

View File

@ -16,7 +16,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitSetBaseTypeSpan(this, span);
} }
public override void GenerateChunk(Span target, ChunkGeneratorContext context) public override void GenerateChunk(Span target, ChunkGeneratorContext context)

View File

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{ {
@ -85,5 +83,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{ {
//context.ChunkTreeBuilder.EndParentChunk(); //context.ChunkTreeBuilder.EndParentChunk();
} }
public override void AcceptStart(ParserVisitor visitor, Block block)
{
}
public override void AcceptEnd(ParserVisitor visitor, Block block)
{
}
} }
} }

View File

@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void Accept(ParserVisitor visitor, Span span) public override void Accept(ParserVisitor visitor, Span span)
{ {
visitor.VisitTagHelperPrefixSpan(this, span);
} }
public override void GenerateChunk(Span target, ChunkGeneratorContext context) public override void GenerateChunk(Span target, ChunkGeneratorContext context)

View File

@ -7,18 +7,21 @@ using System;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
public class LoweringIntegrationTest public class DefaultRazorIRLoweringPhaseIntegrationTest
{ {
[Fact] [Fact]
public void Lower_EmptyDocument() public void Lower_EmptyDocument()
{ {
// Arrange
var codeDocument = TestRazorCodeDocument.CreateEmpty(); var codeDocument = TestRazorCodeDocument.CreateEmpty();
// Act
var irDocument = Lower(codeDocument); var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument); var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace); var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<MethodDeclarationIRNode>(@class); var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
var html = SingleChild<HtmlContentIRNode>(method); var html = SingleChild<HtmlContentIRNode>(method);
Assert.Equal(string.Empty, html.Content); Assert.Equal(string.Empty, html.Content);
@ -27,68 +30,118 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
[Fact] [Fact]
public void Lower_HelloWorld() public void Lower_HelloWorld()
{ {
// Arrange
var codeDocument = TestRazorCodeDocument.Create("Hello, World!"); var codeDocument = TestRazorCodeDocument.Create("Hello, World!");
// Act
var irDocument = Lower(codeDocument); var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument); var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace); var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<MethodDeclarationIRNode>(@class); var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
var html = SingleChild<HtmlContentIRNode>(method); var html = SingleChild<HtmlContentIRNode>(method);
Assert.Equal("Hello, World!", html.Content); Assert.Equal("Hello, World!", html.Content);
} }
[Fact] [Fact]
public void Lower_HtmlWithAttributes() public void Lower_HtmlWithDataDashAttributes()
{ {
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@" var codeDocument = TestRazorCodeDocument.Create(@"
<html> <html>
<body> <body>
<span data-val=""@Hello"" /> <span data-val=""@Hello"" />
</body> </body>
</html>"); </html>");
// Act
var irDocument = Lower(codeDocument); var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument); var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace); var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<MethodDeclarationIRNode>(@class); var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
Children(method, Children(method,
n => Html(Environment.NewLine, n), n => Html(
n => Html("<html>", n), @"
n => Html(Environment.NewLine + " ", n), <html>
n => Html("<body>", n), <body>
n => Html(Environment.NewLine + " ", n), <span data-val=""", n),
n => Html("<span", n),
n => Html(" data-val=\"", n),
n => CSharpExpression("Hello", n), n => CSharpExpression("Hello", n),
n => Html("\"", n), n => Html(@""" />
n => Html(" />", n), </body>
n => Html(Environment.NewLine + " ", n), </html>", n));
n => Html("</body>", n), }
n => Html(Environment.NewLine, n),
n => Html("</html>", n)); [Fact]
public void Lower_HtmlWithConditionalAttributes()
{
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"
<html>
<body>
<span val=""@Hello World"" />
</body>
</html>");
// Act
var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
Children(method,
n => Html(
@"
<html>
<body>
<span", n),
n => ConditionalAttribute(
prefix: " val=\"",
name: "val",
suffix: "\"",
node: n,
valueValidators: new Action<RazorIRNode>[]
{
value => CSharpAttributeValue(string.Empty, "Hello", value),
value => LiteralAttributeValue(" ", "World", value)
}),
n => Html(@" />
</body>
</html>", n));
} }
[Fact] [Fact]
public void Lower_WithUsing() public void Lower_WithUsing()
{ {
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"@functions { public int Foo { get; set; }}"); var codeDocument = TestRazorCodeDocument.Create(@"@functions { public int Foo { get; set; }}");
// Act
var irDocument = Lower(codeDocument); var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument); var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace); var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
Children(@class, Children(@class,
n => Assert.IsType<MethodDeclarationIRNode>(n), n => Assert.IsType<RazorMethodDeclarationIRNode>(n),
n => Assert.IsType<CSharpStatementIRNode>(n)); n => Assert.IsType<CSharpStatementIRNode>(n));
} }
[Fact] [Fact]
public void Lower_WithFunctions() public void Lower_WithFunctions()
{ {
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"@using System"); var codeDocument = TestRazorCodeDocument.Create(@"@using System");
// Act
var irDocument = Lower(codeDocument); var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument); var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
Children(@namespace, Children(@namespace,
n => Using("using System", n), n => Using("using System", n),

View File

@ -86,6 +86,60 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
} }
} }
public static void ConditionalAttribute(
string prefix,
string name,
string suffix,
RazorIRNode node,
params Action<RazorIRNode>[] valueValidators)
{
var attribute = Assert.IsType<HtmlAttributeIRNode>(node);
try
{
Assert.Equal(prefix, attribute.Prefix);
Assert.Equal(name, attribute.Name);
Assert.Equal(suffix, attribute.Suffix);
Children(attribute.Value, valueValidators);
}
catch (XunitException e)
{
throw new IRAssertException(attribute, attribute.Value.Children, e.Message, e);
}
}
public static void CSharpAttributeValue(string prefix, string expected, RazorIRNode node)
{
var attributeValue = Assert.IsType<CSharpAttributeValueIRNode>(node);
try
{
Assert.Equal(prefix, attributeValue.Prefix);
Children(attributeValue.Content, n => CSharpExpression(expected, n));
}
catch (XunitException e)
{
throw new IRAssertException(attributeValue, attributeValue.Content.Children, e.Message, e);
}
}
public static void LiteralAttributeValue(string prefix, string expected, RazorIRNode node)
{
var attributeValue = Assert.IsType<HtmlAttributeValueIRNode>(node);
try
{
Assert.Equal(prefix, attributeValue.Prefix);
Assert.Equal(expected, attributeValue.Content);
}
catch (XunitException e)
{
throw new IRAssertException(attributeValue, e.Message);
}
}
public static void CSharpExpression(string expected, RazorIRNode node) public static void CSharpExpression(string expected, RazorIRNode node)
{ {
try try
@ -93,9 +147,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
var cSharp = Assert.IsType<CSharpExpressionIRNode>(node); var cSharp = Assert.IsType<CSharpExpressionIRNode>(node);
var content = new StringBuilder(); var content = new StringBuilder();
for (var i = 0; i < cSharp.Children.Count; i++) for (var i = 0; i < cSharp.Content.Children.Count; i++)
{ {
content.Append(((CSharpTokenIRNode)cSharp.Children[i]).Content); content.Append(((CSharpTokenIRNode)cSharp.Content.Children[i]).Content);
} }
Assert.Equal(expected, content.ToString()); Assert.Equal(expected, content.ToString());
@ -108,7 +162,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
private class IRAssertException : XunitException private class IRAssertException : XunitException
{ {
public IRAssertException(RazorIRNode node, string userMessage) public IRAssertException(RazorIRNode node, string userMessage)
: base(Format(node, null, userMessage)) : base(Format(node, null, userMessage))
{ {
Node = node; Node = node;
@ -119,7 +173,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{ {
Node = node; Node = node;
Nodes = nodes; Nodes = nodes;
} }
public IRAssertException( public IRAssertException(
RazorIRNode node, RazorIRNode node,