Add IR phase
This change adds a phase which runs IR passes. Design and code are almost exactly the same as the existing SyntaxTree phase. However all of this is public because the IR is public API.
This commit is contained in:
parent
518378f499
commit
46018f9512
|
|
@ -2,7 +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.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// 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.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
internal class DefaultRazorIRPhase : RazorEnginePhaseBase
|
||||
{
|
||||
public IRazorIRPass[] Passes { get; private set; }
|
||||
|
||||
protected override void OnIntialized()
|
||||
{
|
||||
Passes = Engine.Features.OfType<IRazorIRPass>().OrderBy(p => p.Order).ToArray();
|
||||
}
|
||||
|
||||
protected override void ExecuteCore(RazorCodeDocument codeDocument)
|
||||
{
|
||||
var irDocument = codeDocument.GetIRDocument();
|
||||
ThrowForMissingDependency(irDocument);
|
||||
|
||||
foreach (var pass in Passes)
|
||||
{
|
||||
irDocument = pass.Execute(codeDocument, irDocument);
|
||||
}
|
||||
|
||||
codeDocument.SetIRDocument(irDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// 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 Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
public interface IRazorIRPass : IRazorEngineFeature
|
||||
{
|
||||
int Order { get; }
|
||||
|
||||
DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
public interface IRazorIRPhase : IRazorEnginePhase
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
builder.Phases.Add(new DefaultRazorParsingPhase());
|
||||
builder.Phases.Add(new DefaultRazorSyntaxTreePhase());
|
||||
builder.Phases.Add(new DefaultRazorIRLoweringPhase());
|
||||
builder.Phases.Add(new DefaultRazorIRPhase());
|
||||
|
||||
builder.Features.Add(new TagHelperBinderSyntaxTreePass());
|
||||
builder.Features.Add(new HtmlNodeOptimizationPass());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
// 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 Microsoft.AspNetCore.Razor.Evolution.Intermediate;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution
|
||||
{
|
||||
public class DefaultRazorIRPhaseTest
|
||||
{
|
||||
[Fact]
|
||||
public void OnInitialized_OrdersPassesInAscendingOrder()
|
||||
{
|
||||
// Arrange & Act
|
||||
var phase = new DefaultRazorIRPhase();
|
||||
|
||||
var first = Mock.Of<IRazorIRPass>(p => p.Order == 15);
|
||||
var second = Mock.Of<IRazorIRPass>(p => p.Order == 17);
|
||||
|
||||
var engine = RazorEngine.CreateEmpty(b =>
|
||||
{
|
||||
b.Phases.Add(phase);
|
||||
|
||||
b.Features.Add(second);
|
||||
b.Features.Add(first);
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
phase.Passes,
|
||||
p => Assert.Same(first, p),
|
||||
p => Assert.Same(second, p));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ThrowsForMissingDependency()
|
||||
{
|
||||
// Arrange
|
||||
var phase = new DefaultRazorIRPhase();
|
||||
|
||||
var engine = RazorEngine.CreateEmpty(b => b.Phases.Add(phase));
|
||||
|
||||
var codeDocument = TestRazorCodeDocument.CreateEmpty();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.Throws<InvalidOperationException>(
|
||||
() => phase.Execute(codeDocument),
|
||||
$"The '{nameof(DefaultRazorIRPhase)}' phase requires a '{nameof(DocumentIRNode)}' " +
|
||||
$"provided by the '{nameof(RazorCodeDocument)}'.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ExecutesPhasesInOrder()
|
||||
{
|
||||
// Arrange
|
||||
var codeDocument = TestRazorCodeDocument.CreateEmpty();
|
||||
|
||||
// We're going to set up mocks to simulate a sequence of passes. We don't care about
|
||||
// what's in the nodes, we're just going to look at the identity via strict mocks.
|
||||
var originalNode = new DocumentIRNode();
|
||||
var firstPassNode = new DocumentIRNode();
|
||||
var secondPassNode = new DocumentIRNode();
|
||||
codeDocument.SetIRDocument(originalNode);
|
||||
|
||||
var firstPass = new Mock<IRazorIRPass>(MockBehavior.Strict);
|
||||
firstPass.SetupGet(m => m.Order).Returns(0);
|
||||
firstPass.SetupProperty(m => m.Engine);
|
||||
firstPass.Setup(m => m.Execute(codeDocument, originalNode)).Returns(firstPassNode);
|
||||
|
||||
var secondPass = new Mock<IRazorIRPass>(MockBehavior.Strict);
|
||||
secondPass.SetupGet(m => m.Order).Returns(1);
|
||||
secondPass.SetupProperty(m => m.Engine);
|
||||
secondPass.Setup(m => m.Execute(codeDocument, firstPassNode)).Returns(secondPassNode);
|
||||
|
||||
var phase = new DefaultRazorIRPhase();
|
||||
|
||||
var engine = RazorEngine.CreateEmpty(b =>
|
||||
{
|
||||
b.Phases.Add(phase);
|
||||
|
||||
b.Features.Add(firstPass.Object);
|
||||
b.Features.Add(secondPass.Object);
|
||||
});
|
||||
|
||||
// Act
|
||||
phase.Execute(codeDocument);
|
||||
|
||||
// Assert
|
||||
Assert.Same(secondPassNode, codeDocument.GetIRDocument());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -86,7 +85,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
phases,
|
||||
phase => Assert.IsType<DefaultRazorParsingPhase>(phase),
|
||||
phase => Assert.IsType<DefaultRazorSyntaxTreePhase>(phase),
|
||||
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase));
|
||||
phase => Assert.IsType<DefaultRazorIRLoweringPhase>(phase),
|
||||
phase => Assert.IsType<DefaultRazorIRPhase>(phase));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue