213 lines
8.2 KiB
C#
213 lines
8.2 KiB
C#
// 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.Razor.Evolution.Legacy;
|
|
|
|
namespace Microsoft.AspNetCore.Razor.Evolution
|
|
{
|
|
internal class DefaultRazorDesignTimeCSharpLoweringPhase : RazorCSharpLoweringPhaseBase
|
|
{
|
|
protected override void ExecuteCore(RazorCodeDocument codeDocument)
|
|
{
|
|
var irDocument = codeDocument.GetIRDocument();
|
|
ThrowForMissingDependency(irDocument);
|
|
|
|
var syntaxTree = codeDocument.GetSyntaxTree();
|
|
ThrowForMissingDependency(syntaxTree);
|
|
|
|
var renderingContext = new CSharpRenderingContext()
|
|
{
|
|
Writer = new CSharpCodeWriter(),
|
|
SourceDocument = codeDocument.Source,
|
|
Options = syntaxTree.Options,
|
|
};
|
|
var visitor = new CSharpRenderer(renderingContext);
|
|
visitor.VisitDocument(irDocument);
|
|
var csharpDocument = new RazorCSharpDocument()
|
|
{
|
|
GeneratedCode = renderingContext.Writer.GenerateCode(),
|
|
LineMappings = renderingContext.LineMappings,
|
|
};
|
|
|
|
codeDocument.SetCSharpDocument(csharpDocument);
|
|
}
|
|
|
|
private class CSharpRenderer : PageStructureCSharpRenderer
|
|
{
|
|
public CSharpRenderer(CSharpRenderingContext context) : base(context)
|
|
{
|
|
}
|
|
|
|
public override void VisitCSharpToken(CSharpTokenIRNode node)
|
|
{
|
|
Context.Writer.Write(node.Content);
|
|
}
|
|
|
|
public override void VisitCSharpExpression(CSharpExpressionIRNode node)
|
|
{
|
|
if (node.Children.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (node.SourceRange != null)
|
|
{
|
|
using (new LinePragmaWriter(Context.Writer, node.SourceRange))
|
|
{
|
|
var padding = BuildOffsetPadding(RazorDesignTimeIRPass.DesignTimeVariable.Length, node.SourceRange, Context);
|
|
|
|
Context.Writer
|
|
.Write(padding)
|
|
.WriteStartAssignment(RazorDesignTimeIRPass.DesignTimeVariable);
|
|
|
|
for (var i = 0; i < node.Children.Count; i++)
|
|
{
|
|
var childNode = node.Children[i];
|
|
|
|
if (childNode is CSharpTokenIRNode)
|
|
{
|
|
AddLineMappingFor(childNode);
|
|
}
|
|
|
|
childNode.Accept(this);
|
|
}
|
|
|
|
Context.Writer.WriteLine(";");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Context.Writer.WriteStartAssignment(RazorDesignTimeIRPass.DesignTimeVariable);
|
|
VisitDefault(node);
|
|
Context.Writer.WriteLine(";");
|
|
}
|
|
}
|
|
|
|
public override void VisitUsingStatement(UsingStatementIRNode node)
|
|
{
|
|
Context.Writer.WriteUsing(node.Content);
|
|
}
|
|
|
|
public override void VisitCSharpStatement(CSharpStatementIRNode node)
|
|
{
|
|
if (node.SourceRange != null)
|
|
{
|
|
using (new LinePragmaWriter(Context.Writer, node.SourceRange))
|
|
{
|
|
var padding = BuildOffsetPadding(0, node.SourceRange, Context);
|
|
Context.Writer.Write(padding);
|
|
|
|
AddLineMappingFor(node);
|
|
Context.Writer.Write(node.Content);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Context.Writer.WriteLine(node.Content);
|
|
}
|
|
}
|
|
|
|
public override void VisitDirectiveToken(DirectiveTokenIRNode node)
|
|
{
|
|
const string TypeHelper = "__typeHelper";
|
|
|
|
var tokenKind = node.Descriptor.Kind;
|
|
if (node.SourceRange == null || node.Descriptor.Kind == DirectiveTokenKind.Literal)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Wrap the directive token in a lambda to isolate variable names.
|
|
Context.Writer
|
|
.Write("((")
|
|
.Write(typeof(Action).FullName)
|
|
.Write(")(");
|
|
using (Context.Writer.BuildLambda(endLine: false))
|
|
{
|
|
var originalIndent = Context.Writer.CurrentIndent;
|
|
Context.Writer.ResetIndent();
|
|
switch (tokenKind)
|
|
{
|
|
case DirectiveTokenKind.Type:
|
|
|
|
AddLineMappingFor(node);
|
|
Context.Writer
|
|
.Write(node.Content)
|
|
.Write(" ")
|
|
.WriteStartAssignment(TypeHelper)
|
|
.WriteLine("null;");
|
|
break;
|
|
case DirectiveTokenKind.Member:
|
|
Context.Writer
|
|
.Write(typeof(object).FullName)
|
|
.Write(" ");
|
|
|
|
AddLineMappingFor(node);
|
|
Context.Writer
|
|
.Write(node.Content)
|
|
.WriteLine(" = null;");
|
|
break;
|
|
case DirectiveTokenKind.String:
|
|
Context.Writer
|
|
.Write(typeof(object).FullName)
|
|
.Write(" ")
|
|
.WriteStartAssignment(TypeHelper);
|
|
|
|
if (node.Content.StartsWith("\"", StringComparison.Ordinal))
|
|
{
|
|
AddLineMappingFor(node);
|
|
Context.Writer.Write(node.Content);
|
|
}
|
|
else
|
|
{
|
|
Context.Writer.Write("\"");
|
|
AddLineMappingFor(node);
|
|
Context.Writer
|
|
.Write(node.Content)
|
|
.Write("\"");
|
|
}
|
|
|
|
Context.Writer.WriteLine(";");
|
|
break;
|
|
}
|
|
Context.Writer.SetIndent(originalIndent);
|
|
}
|
|
Context.Writer.WriteLine("))();");
|
|
|
|
}
|
|
|
|
public override void VisitTemplate(TemplateIRNode node)
|
|
{
|
|
const string ItemParameterName = "item";
|
|
const string TemplateWriterName = "__razor_template_writer";
|
|
|
|
Context.Writer
|
|
.Write(ItemParameterName).Write(" => ")
|
|
.WriteStartNewObject("HelperResult" /* ORIGINAL: TemplateTypeName */);
|
|
|
|
var initialRenderingConventions = Context.RenderingConventions;
|
|
var redirectConventions = new CSharpRedirectRenderingConventions(TemplateWriterName, Context.Writer);
|
|
Context.RenderingConventions = redirectConventions;
|
|
using (Context.Writer.BuildAsyncLambda(endLine: false, parameterNames: TemplateWriterName))
|
|
{
|
|
VisitDefault(node);
|
|
}
|
|
Context.RenderingConventions = initialRenderingConventions;
|
|
|
|
Context.Writer.WriteEndMethodInvocation(endLine: false);
|
|
}
|
|
|
|
private void AddLineMappingFor(RazorIRNode node)
|
|
{
|
|
var sourceLocation = node.SourceRange;
|
|
var generatedLocation = new MappingLocation(Context.Writer.GetCurrentSourceLocation(), node.SourceRange.ContentLength);
|
|
var lineMapping = new LineMapping(sourceLocation, generatedLocation);
|
|
|
|
Context.LineMappings.Add(lineMapping);
|
|
}
|
|
}
|
|
}
|
|
}
|