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.
// 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.Legacy;
@ -11,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
protected override void ExecuteCore(RazorCodeDocument codeDocument)
{
var syntaxTree = codeDocument.GetSyntaxTree();
ThrowForMissingDependency<RazorSyntaxTree>(syntaxTree);
ThrowForMissingDependency(syntaxTree);
var visitor = new Visitor();
@ -23,80 +25,89 @@ namespace Microsoft.AspNetCore.Razor.Evolution
private class Visitor : ParserVisitor
{
private readonly Stack<RazorIRBuilder> _builders;
public Visitor()
{
Builder = RazorIRBuilder.Document();
_builders = new Stack<RazorIRBuilder>();
var document = RazorIRBuilder.Document();
_builders.Push(document);
Namespace = new NamespaceDeclarationIRNode();
NamespaceBuilder = RazorIRBuilder.Create(Namespace);
Builder.Push(Namespace);
Class = new ClassDeclarationIRNode();
ClassBuilder = RazorIRBuilder.Create(Class);
Builder.Push(Class);
Method = new MethodDeclarationIRNode();
Method = new RazorMethodDeclarationIRNode();
Builder.Push(Method);
}
public RazorIRBuilder Builder { get; }
public RazorIRBuilder Builder => _builders.Peek();
public NamespaceDeclarationIRNode Namespace { get; }
public RazorIRBuilder NamespaceBuilder { get; }
public ClassDeclarationIRNode Class { get; }
public RazorIRBuilder ClassBuilder { get; }
public RazorMethodDeclarationIRNode Method { get; }
public MethodDeclarationIRNode Method { get; }
public override void VisitStartAttributeBlock(AttributeBlockChunkGenerator chunk, Block block)
public override void VisitStartAttributeBlock(AttributeBlockChunkGenerator chunkGenerator, Block block)
{
Builder.Push(new HtmlAttributeIRNode()
var value = new ContainerRazorIRNode();
Builder.Add(new HtmlAttributeIRNode()
{
Name = chunk.Name,
Prefix = chunk.Prefix,
Suffix = chunk.Prefix,
Name = chunkGenerator.Name,
Prefix = chunkGenerator.Prefix,
Value = value,
Suffix = chunkGenerator.Suffix,
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,
});
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()
{
Prefix = chunk.Prefix,
Prefix = chunkGenerator.Prefix,
Content = chunkGenerator.Value,
SourceLocation = span.Start,
});
}
public override void VisitStartTemplateBlock(TemplateBlockChunkGenerator chunk, Block block)
public override void VisitStartTemplateBlock(TemplateBlockChunkGenerator chunkGenerator, Block block)
{
Builder.Push(new TemplateIRNode());
}
public override void VisitEndTemplateBlock(TemplateBlockChunkGenerator chunk, Block block)
public override void VisitEndTemplateBlock(TemplateBlockChunkGenerator chunkGenerator, Block block)
{
Builder.Pop();
}
@ -107,20 +118,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// @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
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,
});
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()
{
@ -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()
{
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()
var functionsNode = new CSharpStatementIRNode()
{
Content = span.Content,
SourceLocation = span.Start,
});
Parent = Class,
};
Class.Children.Add(functionsNode);
}
public override void VisitAddTagHelperSpan(AddTagHelperChunkGenerator chunk, 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)
public override void VisitStatementSpan(StatementChunkGenerator chunkGenerator, Span span)
{
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;
}
public override void VisitMarkupSpan(MarkupChunkGenerator chunk, Span span)
{
Builder.Add(new HtmlContentIRNode()
var currentChildren = Builder.Current.Children;
if (currentChildren.Count > 0 && currentChildren[currentChildren.Count - 1] is HtmlContentIRNode)
{
Content = span.Content,
SourceLocation = span.Start,
});
var existingHtmlContent = (HtmlContentIRNode)currentChildren[currentChildren.Count - 1];
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.
var i = 0;
@ -210,6 +205,47 @@ namespace Microsoft.AspNetCore.Razor.Evolution
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.
// 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,21 +9,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class CSharpAttributeValueIRNode : RazorIRNode
{
public string Prefix { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public string Prefix { get; set; }
public RazorIRNode Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpAttributeValue(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpAttributeValue(this);
}
}

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,21 +9,31 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
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; }
internal override SourceLocation SourceLocation { get; set; }
public string Content { get; set; }
public RazorIRNode Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpExpression(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpExpression(this);
}
}

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
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; }
@ -18,11 +19,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpStatement(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpStatement(this);
}
}

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -18,11 +19,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitCSharpToken(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitCSharpToken(this);
}
}

View File

@ -9,6 +9,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
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 Name { get; set; }
@ -17,19 +23,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
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)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitClass(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitClass(this);
}
}

View File

@ -42,10 +42,10 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
node = Pop();
}
return node;
}
public override RazorIRNode Pop()
{
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.
// 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -16,11 +17,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitDocument(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitDocument(this);
}
}

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,25 +9,37 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class HtmlAttributeIRNode : RazorIRNode
{
public string Name { get; set; }
public string Prefix { get; set; }
public string Suffix { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { 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)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitHtmlAttribute(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitHtmlAttribute(this);
}
}

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -8,21 +9,33 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class HtmlAttributeValueIRNode : RazorIRNode
{
public string Prefix { get; set; }
public override IList<RazorIRNode> Children { get; } = new List<RazorIRNode>();
public override IList<RazorIRNode> Children { get; } = EmptyArray;
public override RazorIRNode Parent { get; set; }
internal override SourceLocation SourceLocation { get; set; }
public string Prefix { get; set; }
public string Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitHtmlAttributeValue(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitHtmlAttributeValue(this);
}
}

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
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; }

View File

@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -14,13 +15,25 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
internal override SourceLocation SourceLocation { get; set; }
public string Content { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitNamespace(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitNamespace(this);
}
}

View File

@ -3,7 +3,7 @@
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public abstract class RazorIRNodeVisitor
public abstract class RazorIRNodeVisitor
{
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)
{
VisitDefault(node);
}
public virtual void VisitSection(SectionIRNode node)
{
VisitDefault(node);
}
public virtual void VisitCSharpStatement(CSharpStatementIRNode node)
{
VisitDefault(node);
@ -59,22 +49,12 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
VisitDefault(node);
}
public virtual void VisitSingleLineDirective(SingleLineDirectiveIRNode node)
{
VisitDefault(node);
}
public virtual void VisitBlockDirective(BlockDirectiveIRNode node)
{
VisitDefault(node);
}
public virtual void VisitClass(ClassDeclarationIRNode node)
{
VisitDefault(node);
}
public virtual void VisitMethodDeclaration(MethodDeclarationIRNode node)
public virtual void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
{
VisitDefault(node);
}

View File

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

View File

@ -1,13 +1,20 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
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 IList<string> Modifiers { get; set; }
@ -16,20 +23,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
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)
{
visitor.VisitMethodDeclaration(this);
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitRazorMethodDeclaration(this);
}
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.
// 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
@ -16,11 +17,21 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
visitor.VisitTemplate(this);
}
public override TResult Accept<TResult>(RazorIRNodeVisitor<TResult> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
return visitor.VisitTemplate(this);
}
}

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
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; }

View File

@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void Accept(ParserVisitor visitor, Span span)
{
visitor.VisitAddTagHelperSpan(this, span);
}
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)
{
VisitStartBlock(block);
for (var i = 0; i < block.Children.Count; i++)
{
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)
{
}
@ -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 VisitAddTagHelperSpan(AddTagHelperChunkGenerator 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)
{
}

View File

@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
public override void Accept(ParserVisitor visitor, Span span)
{
visitor.VisitRemoveTagHelperSpan(this, span);
}
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)
{
visitor.VisitStartSectionBlock(this, block);
}
public override void AcceptEnd(ParserVisitor visitor, Block block)
{
visitor.VisitEndSectionBlock(this, block);
}
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)
{
visitor.VisitSetBaseTypeSpan(this, span);
}
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.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
@ -85,5 +83,13 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
//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)
{
visitor.VisitTagHelperPrefixSpan(this, span);
}
public override void GenerateChunk(Span target, ChunkGeneratorContext context)

View File

@ -7,18 +7,21 @@ using System;
namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
public class LoweringIntegrationTest
public class DefaultRazorIRLoweringPhaseIntegrationTest
{
[Fact]
public void Lower_EmptyDocument()
{
// Arrange
var codeDocument = TestRazorCodeDocument.CreateEmpty();
// Act
var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<MethodDeclarationIRNode>(@class);
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
var html = SingleChild<HtmlContentIRNode>(method);
Assert.Equal(string.Empty, html.Content);
@ -27,68 +30,118 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
[Fact]
public void Lower_HelloWorld()
{
// Arrange
var codeDocument = TestRazorCodeDocument.Create("Hello, World!");
// Act
var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<MethodDeclarationIRNode>(@class);
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
var html = SingleChild<HtmlContentIRNode>(method);
Assert.Equal("Hello, World!", html.Content);
}
[Fact]
public void Lower_HtmlWithAttributes()
public void Lower_HtmlWithDataDashAttributes()
{
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"
<html>
<body>
<span data-val=""@Hello"" />
</body>
</html>");
// Act
var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
var method = SingleChild<MethodDeclarationIRNode>(@class);
var method = SingleChild<RazorMethodDeclarationIRNode>(@class);
Children(method,
n => Html(Environment.NewLine, n),
n => Html("<html>", n),
n => Html(Environment.NewLine + " ", n),
n => Html("<body>", n),
n => Html(Environment.NewLine + " ", n),
n => Html("<span", n),
n => Html(" data-val=\"", n),
n => Html(
@"
<html>
<body>
<span data-val=""", n),
n => CSharpExpression("Hello", n),
n => Html("\"", n),
n => Html(" />", n),
n => Html(Environment.NewLine + " ", n),
n => Html("</body>", n),
n => Html(Environment.NewLine, n),
n => Html("</html>", n));
n => Html(@""" />
</body>
</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]
public void Lower_WithUsing()
{
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"@functions { public int Foo { get; set; }}");
// Act
var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
var @class = SingleChild<ClassDeclarationIRNode>(@namespace);
Children(@class,
n => Assert.IsType<MethodDeclarationIRNode>(n),
n => Assert.IsType<RazorMethodDeclarationIRNode>(n),
n => Assert.IsType<CSharpStatementIRNode>(n));
}
[Fact]
public void Lower_WithFunctions()
{
// Arrange
var codeDocument = TestRazorCodeDocument.Create(@"@using System");
// Act
var irDocument = Lower(codeDocument);
// Assert
var @namespace = SingleChild<NamespaceDeclarationIRNode>(irDocument);
Children(@namespace,
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)
{
try
@ -93,9 +147,9 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
var cSharp = Assert.IsType<CSharpExpressionIRNode>(node);
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());
@ -108,7 +162,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
private class IRAssertException : XunitException
{
public IRAssertException(RazorIRNode node, string userMessage)
public IRAssertException(RazorIRNode node, string userMessage)
: base(Format(node, null, userMessage))
{
Node = node;
@ -119,7 +173,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Intermediate
{
Node = node;
Nodes = nodes;
}
}
public IRAssertException(
RazorIRNode node,