Start to add a CodeTree codegen.

This addition will eventually replace CodeDOM to allow for the k10 project to build.  It is a new type of codegeneration method that is highly extensible.
This commit is contained in:
N. Taylor Mullen 2014-01-19 21:06:04 -08:00
parent 67c3b2b080
commit 521a5c8517
69 changed files with 2570 additions and 43 deletions

View File

@ -5,6 +5,7 @@ using System.Linq;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
@ -19,6 +20,19 @@ namespace Microsoft.AspNet.Razor.Generator
public string Namespace { get; private set; }
public int NamespaceKeywordLength { get; set; }
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
string ns = Namespace;
if (!String.IsNullOrEmpty(ns) && Char.IsWhiteSpace(ns[0]))
{
ns = ns.Substring(1);
}
// TODO: Verify namespace hasn't already been added.
codeTreeBuilder.AddUsingChunk(ns, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
// Try to find the namespace in the existing imports
@ -43,6 +57,9 @@ namespace Microsoft.AspNet.Razor.Generator
// Attach our info to the existing/new import.
import.LinePragma = context.GenerateLinePragma(target);
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -5,6 +5,7 @@ using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
@ -21,12 +22,22 @@ namespace Microsoft.AspNet.Razor.Generator
public LocationTagged<string> Prefix { get; private set; }
public LocationTagged<string> Suffix { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
CodeAttributeChunk chunk = codeTreeBuilder.StartChunkBlock<CodeAttributeChunk>(target, context);
chunk.Attribute = Name;
chunk.Prefix = Prefix;
chunk.Suffix = Suffix;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
if (context.Host.DesignTimeMode)
{
return; // Don't generate anything!
}
context.FlushBufferedStatement();
context.AddStatement(context.BuildCodeString(cw =>
{
@ -49,6 +60,14 @@ namespace Microsoft.AspNet.Razor.Generator
// In VB, we need a line continuation
cw.WriteLineContinuation();
}));
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
@ -57,12 +76,16 @@ namespace Microsoft.AspNet.Razor.Generator
{
return; // Don't generate anything!
}
context.FlushBufferedStatement();
context.AddStatement(context.BuildCodeString(cw =>
{
cw.WriteEndMethodInvoke();
cw.WriteEndStatement();
}));
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -12,12 +12,13 @@ using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Utils;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
public class CodeGeneratorContext
{
private const string DesignTimeHelperMethodName = "__RazorDesignTimeHelpers__";
internal const string DesignTimeHelperMethodName = "__RazorDesignTimeHelpers__";
private int _nextDesignTimePragmaId = 1;
private bool _expressionHelperVariableWriten;
@ -44,6 +45,8 @@ namespace Microsoft.AspNet.Razor.Generator
public string TargetWriterName { get; set; }
public CodeMemberMethod TargetMethod { get; set; }
public CodeTreeBuilder CodeTreeBuilder { get; set; }
public string CurrentBufferedStatement
{
get { return _currentBuffer == null ? String.Empty : _currentBuffer.Builder.ToString(); }
@ -58,6 +61,7 @@ namespace Microsoft.AspNet.Razor.Generator
{
CodeGeneratorContext context = new CodeGeneratorContext()
{
CodeTreeBuilder = new CodeTreeBuilder(),
Host = host,
CodeWriterFactory = writerFactory,
SourceFile = shouldGenerateLinePragmas ? sourceFile : null,
@ -103,6 +107,7 @@ namespace Microsoft.AspNet.Razor.Generator
_designTimeHelperMethod.Statements.Insert(_designTimeHelperMethod.Statements.Count - 1, statement);
}
[SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", MessageId = "generatedCodeStart+1", Justification = "There is no risk of overflow in this case")]
public int AddCodeMapping(SourceLocation sourceLocation, int generatedCodeStart, int generatedCodeLength)
{

View File

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpCodeBuilder : CodeBuilder
{
public CSharpCodeBuilder(CodeTree codeTree, string rootNamespace, RazorEngineHost host, string sourceFile)
: base(codeTree)
{
Host = host;
RootNamespace = rootNamespace;
SourceFile = sourceFile;
}
public RazorEngineHost Host { get; private set; }
public string RootNamespace { get; private set; }
public string SourceFile { get; private set; }
public override CodeBuilderResult Build()
{
var writer = new CSharpCodeWriter();
// TODO: Combine into one string (perf)
writer.WriteComment(new string('-', 78))
.WriteComment("<auto-generated>")
.WriteComment(" This code was generated by a tool.")
.WriteComment(" Runtime Version: " + Assembly.GetExecutingAssembly().ImageRuntimeVersion)
.WriteComment("")
.WriteComment(" Changes to this file may cause incorrect behavior and will be lost if")
.WriteComment(" the code is regenerated.")
.WriteComment("</auto-generated>")
.WriteComment(new string('-', 78))
.WriteLine();
using (writer.BuildNamespace(RootNamespace))
{
// Write out using directives
AddImports(Tree, writer, Host.NamespaceImports);
// TODO: Include current projects namespace? Does that happen to be included in the namespace imports?
var baseTypeVisitor = new CSharpBaseTypeVisitor(writer);
baseTypeVisitor.Accept(Tree.Chunks);
string baseType = baseTypeVisitor.CurrentBaseType ?? Host.DefaultBaseClass;
// Separate the usings and the class
writer.WriteLine();
new CSharpClassAttributeVisitor(writer).Accept(Tree.Chunks);
using (writer.BuildClassDeclaration("public", Host.DefaultClassName, String.IsNullOrEmpty(baseType) ? new string[0] : new string[]{baseType}))
{
if (Host.DesignTimeMode)
{
writer.WriteLine("private static object @__o;");
}
new CSharpHelperVisitor(writer, Host, SourceFile).Accept(Tree.Chunks);
new CSharpTypeMemberVisitor(writer, SourceFile).Accept(Tree.Chunks);
new CSharpDesignTimeHelpersVisitor(writer, Host, SourceFile).Accept(Tree);
// TODO: resolve variable declarations
writer.WriteLineHiddenDirective();
using (writer.BuildConstructor(Host.DefaultClassName))
{
// Any constructor based logic that we need to add?
};
// Add space inbetween constructor and method body
writer.WriteLine();
using (writer.BuildMethodDeclaration("public override", "void", Host.GeneratedClassContext.ExecuteMethodName))
{
new CSharpCodeVisitor(writer, Host, SourceFile).Accept(Tree.Chunks);
}
}
}
return new CodeBuilderResult(writer.ToString(), writer.LineMappingManager.Mappings);
}
private void AddImports(CodeTree codeTree, CSharpCodeWriter writer, IEnumerable<string> defaultImports)
{
// Write out using directives
var usingVisitor = new CSharpUsingVisitor(writer, SourceFile);
foreach (Chunk chunk in Tree.Chunks)
{
usingVisitor.Accept(chunk);
}
defaultImports = defaultImports.Except(usingVisitor.ImportedUsings);
foreach (string import in defaultImports)
{
writer.WriteUsing(import);
}
}
}
}

View File

@ -0,0 +1,405 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpCodeWriter : CodeWriter
{
public CSharpCodeWriter()
{
LineMappingManager = new LineMappingManager();
}
public LineMappingManager LineMappingManager { get; private set; }
public CSharpCodeWriter Write(string data)
{
return (CSharpCodeWriter)base.Write(data);
}
public CSharpCodeWriter Indent(int size)
{
return (CSharpCodeWriter)base.Indent(size);
}
public CSharpCodeWriter SetIndent(int size)
{
return (CSharpCodeWriter)base.SetIndent(size);
}
public CSharpCodeWriter IncreaseIndent(int size)
{
return (CSharpCodeWriter)base.IncreaseIndent(size);
}
public CSharpCodeWriter DecreaseIndent(int size)
{
return (CSharpCodeWriter)base.DecreaseIndent(size);
}
public CSharpCodeWriter WriteLine(string data)
{
return (CSharpCodeWriter)base.WriteLine(data);
}
public CSharpCodeWriter WriteLine()
{
return (CSharpCodeWriter)base.WriteLine();
}
public CSharpCodeWriter WriteVariableDeclaration(string type, string name, string value)
{
Write(type).Write(" ").Write(name);
if (!String.IsNullOrEmpty(value))
{
Write(" = ").Write(value);
}
else
{
Write(" = null");
}
WriteLine(";");
return this;
}
public CSharpCodeWriter WriteComment(string comment)
{
return Write("// ").WriteLine(comment);
}
public CSharpCodeWriter WriteBooleanLiteral(bool value)
{
return Write(value.ToString().ToLowerInvariant());
}
public CSharpCodeWriter WriteStartAssignment(string name)
{
return Write(name).Write(" = ");
}
public CSharpCodeWriter WriteParameterSeparator()
{
return Write(", ");
}
public CSharpCodeWriter WriteStartNewObject(string typeName)
{
return Write("new ").Write(typeName).Write("(");
}
public CSharpCodeWriter WriteLocationTaggedString(LocationTagged<string> value)
{
WriteStartMethodInvocation("Tuple.Create");
WriteStringLiteral(value.Value);
WriteParameterSeparator();
Write(value.Location.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
WriteEndMethodInvocation(false);
return this;
}
public CSharpCodeWriter WriteStringLiteral(string literal)
{
if (literal.Length >= 256 && literal.Length <= 1500 && literal.IndexOf('\0') == -1)
{
WriteVerbatimStringLiteral(literal);
}
else
{
WriteCStyleStringLiteral(literal);
}
return this;
}
public CSharpCodeWriter WriteLineHiddenDirective()
{
return WriteLine("#line hidden");
}
public CSharpCodeWriter WritePragma(string value)
{
return Write("#pragma ").WriteLine(value);
}
public CSharpCodeWriter WriteUsing(string name)
{
int throwAway;
return WriteUsing(name, out throwAway);
}
public CSharpCodeWriter WriteUsing(string name, out int writeSize)
{
string output = String.Format("using {0};", name);
writeSize = output.Length;
return WriteLine(output);
}
public CSharpCodeWriter WriteLineDefaultDirective()
{
return WriteLine("#line default");
}
public CSharpCodeWriter WriteStartReturn()
{
return Write("return ");
}
public CSharpCodeWriter WriteReturn(string value)
{
return WriteReturn(value, endLine: true);
}
public CSharpCodeWriter WriteReturn(string value, bool endLine)
{
Write("return ").Write(value);
if (endLine)
{
Write(";");
}
return WriteLine();
}
public CSharpCodeWriter WriteLineNumberDirective(int lineNumber, string file)
{
return Write("#line ").Write(lineNumber.ToString()).Write(" \"").Write(file).WriteLine("\"");
}
public CSharpCodeWriter WriteStartMethodInvocation(string methodName)
{
return WriteStartMethodInvocation(methodName, new string[0]);
}
public CSharpCodeWriter WriteStartMethodInvocation(string methodName, string[] genericArguments)
{
Write(methodName);
if (genericArguments.Length > 0)
{
Write("<").Write(string.Join(", ", genericArguments)).Write(">");
}
return Write("(");
}
public CSharpCodeWriter WriteEndMethodInvocation()
{
return WriteEndMethodInvocation(endLine: true);
}
public CSharpCodeWriter WriteEndMethodInvocation(bool endLine)
{
Write(")");
if (endLine)
{
WriteLine(";");
}
return this;
}
public CSharpCodeWriter WriteMethodInvocation(string methodName, params string[] parameters)
{
return WriteMethodInvocation(methodName, endLine: true, parameters: parameters);
}
public CSharpCodeWriter WriteMethodInvocation(string methodName, bool endLine, params string[] parameters)
{
return WriteStartMethodInvocation(methodName).Write(string.Join(", ", parameters)).WriteEndMethodInvocation(endLine);
}
public CSharpDisableWarningScope BuildDisableWarningScope()
{
return new CSharpDisableWarningScope(this, 219);
}
public CSharpDisableWarningScope BuildDisableWarningScope(int warning)
{
return new CSharpDisableWarningScope(this, warning);
}
public CSharpCodeWritingScope BuildScope()
{
return new CSharpCodeWritingScope(this);
}
public CSharpCodeWritingScope BuildLambda(params string[] parameterNames)
{
return BuildLambda(true, parameterNames);
}
public CSharpCodeWritingScope BuildLambda(bool endLine, params string[] parameterNames)
{
Write("(").Write(string.Join(", ", parameterNames)).Write(") => ");
var scope = new CSharpCodeWritingScope(this);
if (endLine)
{
// End the lambda with a semicolon
scope.OnClose += () =>
{
WriteLine(";");
};
}
return scope;
}
public CSharpCodeWritingScope BuildNamespace(string name)
{
Write("namespace ").WriteLine(name);
return new CSharpCodeWritingScope(this);
}
public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name)
{
return BuildClassDeclaration(accessibility, name, Enumerable.Empty<string>());
}
public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name, string baseType)
{
return BuildClassDeclaration(accessibility, name, new string[] { baseType });
}
public CSharpCodeWritingScope BuildClassDeclaration(string accessibility, string name, IEnumerable<string> baseTypes)
{
Write(accessibility).Write(" class ").Write(name);
if (baseTypes.Count() > 0)
{
Write(" : ");
Write(string.Join(", ", baseTypes));
}
WriteLine();
return new CSharpCodeWritingScope(this);
}
public CSharpCodeWritingScope BuildConstructor(string name)
{
return BuildConstructor("public", name);
}
public CSharpCodeWritingScope BuildConstructor(string accessibility, string name)
{
return BuildConstructor(accessibility, name, Enumerable.Empty<KeyValuePair<string, string>>());
}
public CSharpCodeWritingScope BuildConstructor(string accessibility, string name, IEnumerable<KeyValuePair<string, string>> parameters)
{
Write(accessibility).Write(" ").Write(name).Write("(").Write(string.Join(", ", parameters.Select(p => p.Key + " " + p.Value))).WriteLine(")");
return new CSharpCodeWritingScope(this);
}
public CSharpCodeWritingScope BuildMethodDeclaration(string accessibility, string returnType, string name)
{
return BuildMethodDeclaration(accessibility, returnType, name, Enumerable.Empty<KeyValuePair<string, string>>());
}
public CSharpCodeWritingScope BuildMethodDeclaration(string accessibility, string returnType, string name, IEnumerable<KeyValuePair<string, string>> parameters)
{
Write(accessibility).Write(" ").Write(returnType).Write(" ").Write(name).Write("(").Write(string.Join(", ", parameters.Select(p => p.Key + " " + p.Value))).WriteLine(")");
return new CSharpCodeWritingScope(this);
}
// TODO: Do I need to look at the document content to determine its mapping length?
public CSharpLineMappingWriter BuildLineMapping(SourceLocation documentLocation, int contentLength, string sourceFilename)
{
return new CSharpLineMappingWriter(this, documentLocation, contentLength, sourceFilename);
}
private void WriteVerbatimStringLiteral(string literal)
{
Write("@\"");
foreach (char c in literal)
{
if (c == '\"')
{
Write("\"\"");
}
else
{
Write(c.ToString());
}
}
Write("\"");
}
private void WriteCStyleStringLiteral(string literal)
{
// From CSharpCodeGenerator.QuoteSnippetStringCStyle in CodeDOM
Write("\"");
for (int i = 0; i < literal.Length; i++)
{
switch (literal[i])
{
case '\r':
Write("\\r");
break;
case '\t':
Write("\\t");
break;
case '\"':
Write("\\\"");
break;
case '\'':
Write("\\\'");
break;
case '\\':
Write("\\\\");
break;
case '\0':
Write("\\\0");
break;
case '\n':
Write("\\n");
break;
case '\u2028':
case '\u2029':
Write("\\u");
Write(((int)literal[i]).ToString("X4", CultureInfo.InvariantCulture));
break;
default:
Write(literal[i].ToString());
break;
}
if (i > 0 && i % 80 == 0)
{
// If current character is a high surrogate and the following
// character is a low surrogate, don't break them.
// Otherwise when we write the string to a file, we might lose
// the characters.
if (Char.IsHighSurrogate(literal[i])
&& (i < literal.Length - 1)
&& Char.IsLowSurrogate(literal[i + 1]))
{
Write(literal[++i].ToString());
}
Write("\" +");
Write(Environment.NewLine);
Write("\"");
}
}
Write("\"");
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public struct CSharpCodeWritingScope : IDisposable
{
private CodeWriter _writer;
private bool _autoSpace;
private int _tabSize;
private int _startIndent;
public CSharpCodeWritingScope(CodeWriter writer) : this(writer, true) { }
public CSharpCodeWritingScope(CodeWriter writer, int tabSize) : this(writer, tabSize, true) { }
// TODO: Make indents (tabs) environment specific
public CSharpCodeWritingScope(CodeWriter writer, bool autoSpace) : this(writer, 4, autoSpace) { }
public CSharpCodeWritingScope(CodeWriter writer, int tabSize, bool autoSpace)
{
_writer = writer;
_autoSpace = true;
_tabSize = tabSize;
_startIndent = -1; // Set in WriteStartScope
OnClose = () => { };
WriteStartScope();
}
public event Action OnClose;
public void Dispose()
{
WriteEndScope();
OnClose();
}
private void WriteStartScope()
{
TryAutoSpace(" ");
_writer.WriteLine("{").IncreaseIndent(_tabSize);
_startIndent = _writer.CurrentIndent;
}
private void WriteEndScope()
{
TryAutoSpace(Environment.NewLine);
// Ensure the scope hasn't been modified
if (_writer.CurrentIndent == _startIndent)
{
_writer.DecreaseIndent(_tabSize);
}
_writer.WriteLine("}");
}
private void TryAutoSpace(string spaceCharacter)
{
if (_autoSpace && !Char.IsWhiteSpace(_writer.LastWrite.Last()))
{
_writer.Write(spaceCharacter);
}
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public struct CSharpDisableWarningScope : IDisposable
{
private CSharpCodeWriter _writer;
int _warningNumber;
public CSharpDisableWarningScope(CSharpCodeWriter writer) : this(writer, 219)
{ }
public CSharpDisableWarningScope(CSharpCodeWriter writer, int warningNumber)
{
_writer = writer;
_warningNumber = warningNumber;
_writer.WritePragma("warning disable " + _warningNumber);
}
public void Dispose()
{
_writer.WritePragma("warning restore " + _warningNumber);
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpLineMappingWriter : IDisposable
{
private CSharpCodeWriter _writer;
private MappingLocation _documentMapping;
private SourceLocation _generatedLocation;
private int _startIndent;
private int _generatedContentLength;
public CSharpLineMappingWriter(CSharpCodeWriter writer, SourceLocation documentLocation, int contentLength, string sourceFilename)
{
_writer = writer;
_documentMapping = new MappingLocation(documentLocation, contentLength);
_startIndent = _writer.CurrentIndent;
_generatedContentLength = 0;
_writer.ResetIndent();
// TODO: Should this just be '\n'?
if (_writer.LastWrite.Last() != '\n')
{
_writer.WriteLine();
}
_writer.WriteLineNumberDirective(documentLocation.LineIndex + 1, sourceFilename);
_generatedLocation = _writer.GetCurrentSourceLocation();
}
public void MarkLineMappingStart()
{
_generatedLocation = _writer.GetCurrentSourceLocation();
}
public void MarkLineMappingEnd()
{
_generatedContentLength = _writer.ToString().Length - _generatedLocation.AbsoluteIndex;
}
public void Dispose()
{
// Verify that the generated length has not already been calculated
if (_generatedContentLength == 0)
{
_generatedContentLength = _writer.ToString().Length - _generatedLocation.AbsoluteIndex;
}
var generatedLocation = new MappingLocation(_generatedLocation, _generatedContentLength);
if(_documentMapping.ContentLength == -1)
{
_documentMapping.ContentLength = generatedLocation.ContentLength;
}
_writer.LineMappingManager.AddMapping(
documentLocation: _documentMapping,
generatedLocation: new MappingLocation(_generatedLocation, _generatedContentLength));
if (_writer.LastWrite.Last() != '\n')
{
_writer.WriteLine();
}
_writer.WriteLineDefaultDirective();
_writer.WriteLineHiddenDirective();
// Reset indent back to when it was started
_writer.SetIndent(_startIndent);
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpBaseTypeVisitor : CodeVisitor
{
private CSharpCodeWriter _writer;
public CSharpBaseTypeVisitor(CSharpCodeWriter writer)
{
_writer = writer;
}
public string CurrentBaseType { get; set; }
protected override void Visit(SetBaseTypeChunk chunk)
{
CurrentBaseType = chunk.TypeName;
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpClassAttributeVisitor : CodeVisitor
{
private CSharpCodeWriter _writer;
public CSharpClassAttributeVisitor(CSharpCodeWriter writer)
{
_writer = writer;
}
protected override void Visit(SessionStateChunk chunk)
{
_writer.Write("[")
.Write(typeof(RazorDirectiveAttribute).FullName)
.Write("(")
.WriteStringLiteral(SyntaxConstants.CSharp.SessionStateKeyword)
.WriteParameterSeparator()
.WriteStringLiteral(chunk.Value)
.WriteLine(")]");
}
}
}

View File

@ -0,0 +1,309 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpCodeVisitor : CodeVisitor
{
private const string ValueWriterName = "__razor_attribute_value_writer";
private CSharpCodeWriter _writer;
// TODO: No need for the entire host
private RazorEngineHost _host;
private string _sourceFile;
public CSharpCodeVisitor(CSharpCodeWriter writer, RazorEngineHost host, string sourceFile)
{
_writer = writer;
_host = host;
_sourceFile = sourceFile;
}
protected override void Visit(SetLayoutChunk chunk)
{
if (!_host.DesignTimeMode && !String.IsNullOrEmpty(_host.GeneratedClassContext.LayoutPropertyName))
{
_writer.Write(_host.GeneratedClassContext.LayoutPropertyName)
.Write(" = ")
.WriteStringLiteral(chunk.Layout)
.WriteLine(";");
}
}
protected override void Visit(TemplateChunk chunk)
{
_writer.Write(TemplateBlockCodeGenerator.ItemParameterName).Write(" => ")
.WriteStartNewObject(_host.GeneratedClassContext.TemplateTypeName);
using (_writer.BuildLambda(endLine: false, parameterNames: TemplateBlockCodeGenerator.TemplateWriterName))
{
Visit((ChunkBlock)chunk);
}
_writer.WriteEndMethodInvocation(false).WriteLine();
}
protected override void Visit(ResolveUrlChunk chunk)
{
if (!_host.DesignTimeMode && String.IsNullOrEmpty(chunk.Url))
{
return;
}
// TODO: Add instrumentation
if (!String.IsNullOrEmpty(chunk.Url) && !_host.DesignTimeMode)
{
if (chunk.RenderingMode == ExpressionRenderingMode.WriteToOutput)
{
if (!String.IsNullOrEmpty(chunk.WriterName))
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralToMethodName)
.Write(chunk.WriterName)
.WriteParameterSeparator();
}
else
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralMethodName);
}
}
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.ResolveUrlMethodName)
.WriteStringLiteral(chunk.Url)
.WriteEndMethodInvocation(endLine: false);
if (chunk.RenderingMode == ExpressionRenderingMode.WriteToOutput)
{
_writer.WriteEndMethodInvocation();
}
}
}
protected override void Visit(LiteralChunk chunk)
{
if (!_host.DesignTimeMode && String.IsNullOrEmpty(chunk.Text))
{
return;
}
// TODO: Add instrumentation
if (!String.IsNullOrEmpty(chunk.Text) && !_host.DesignTimeMode)
{
if (!String.IsNullOrEmpty(chunk.WriterName))
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralToMethodName)
.Write(chunk.WriterName)
.WriteParameterSeparator();
}
else
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteLiteralMethodName);
}
_writer.WriteStringLiteral(chunk.Text)
.WriteEndMethodInvocation();
}
// TODO: Add instrumentation
}
protected override void Visit(ExpressionBlockChunk chunk)
{
// TODO: Handle instrumentation
// TODO: Refactor
if (!_host.DesignTimeMode && chunk.RenderingMode == ExpressionRenderingMode.InjectCode)
{
Visit((ChunkBlock)chunk);
}
else
{
if (_host.DesignTimeMode)
{
_writer.WriteStartAssignment("__o");
}
else if (chunk.RenderingMode == ExpressionRenderingMode.WriteToOutput)
{
// TODO: Abstract padding out?
if (!String.IsNullOrEmpty(chunk.WriterName))
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteToMethodName)
.Write(chunk.WriterName)
.WriteParameterSeparator();
}
else
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteMethodName);
}
}
Visit((ChunkBlock)chunk);
if (_host.DesignTimeMode)
{
_writer.WriteLine(";");
}
else if (chunk.RenderingMode == ExpressionRenderingMode.WriteToOutput)
{
_writer.WriteEndMethodInvocation();
}
}
}
protected override void Visit(ExpressionChunk chunk)
{
using (_writer.BuildLineMapping(chunk.Start, chunk.Code.Value.Length, _sourceFile))
{
_writer.Indent(chunk.Start.CharacterIndex)
.Write(chunk.Code.Value);
}
}
protected override void Visit(StatementChunk chunk)
{
foreach (Snippet snippet in chunk.Code)
{
using (_writer.BuildLineMapping(chunk.Start, snippet.Value.Length, _sourceFile))
{
_writer.Indent(chunk.Start.CharacterIndex);
_writer.WriteLine(snippet.Value);
}
}
}
protected override void Visit(DynamicCodeAttributeChunk chunk)
{
if (_host.DesignTimeMode)
{
return; // Don't generate anything!
}
Chunk code = chunk.Children.FirstOrDefault();
_writer.WriteParameterSeparator()
.WriteLine();
if (code is ExpressionChunk || code is ExpressionBlockChunk)
{
_writer.WriteStartMethodInvocation("Tuple.Create")
.WriteLocationTaggedString(chunk.Prefix)
.WriteParameterSeparator()
.WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" });
Accept(code);
_writer.WriteParameterSeparator()
.Write(chunk.Start.AbsoluteIndex.ToString(CultureInfo.CurrentCulture))
.WriteEndMethodInvocation(false)
.WriteParameterSeparator()
.WriteBooleanLiteral(false)
.WriteEndMethodInvocation(false);
}
else
{
_writer.WriteStartMethodInvocation("Tuple.Create")
.WriteLocationTaggedString(chunk.Prefix)
.WriteParameterSeparator()
.WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" })
.WriteStartNewObject(_host.GeneratedClassContext.TemplateTypeName);
using (_writer.BuildLambda(endLine: false, parameterNames: ValueWriterName))
{
Visit((ChunkBlock)chunk);
}
_writer.WriteEndMethodInvocation(false)
.WriteParameterSeparator()
.Write(chunk.Start.AbsoluteIndex.ToString(CultureInfo.CurrentCulture))
.WriteEndMethodInvocation(endLine: false)
.WriteParameterSeparator()
.WriteBooleanLiteral(false)
.WriteEndMethodInvocation(false);
}
}
protected override void Visit(LiteralCodeAttributeChunk chunk)
{
if (_host.DesignTimeMode)
{
return; // Don't generate anything!
}
_writer.WriteParameterSeparator()
.WriteStartMethodInvocation("Tuple.Create")
.WriteLocationTaggedString(chunk.Prefix)
.WriteParameterSeparator();
if (chunk.Children.Count > 0 || chunk.Value == null)
{
_writer.WriteStartMethodInvocation("Tuple.Create", new string[] { "System.Object", "System.Int32" });
Visit((ChunkBlock)chunk);
_writer.WriteParameterSeparator()
.Write(chunk.ValueLocation.AbsoluteIndex.ToString(CultureInfo.CurrentCulture))
.WriteEndMethodInvocation(false)
.WriteParameterSeparator()
.WriteBooleanLiteral(false)
.WriteEndMethodInvocation(false);
}
else
{
_writer.WriteLocationTaggedString(chunk.Value)
.WriteParameterSeparator()
.WriteBooleanLiteral(true)
.WriteEndMethodInvocation(false);
}
}
protected override void Visit(CodeAttributeChunk chunk)
{
if (_host.DesignTimeMode)
{
return; // Don't generate anything!
}
if (!String.IsNullOrEmpty(chunk.WriterName))
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteAttributeToMethodName)
.Write(chunk.WriterName)
.WriteParameterSeparator();
}
else
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.WriteAttributeMethodName);
}
_writer.WriteStringLiteral(chunk.Attribute)
.WriteParameterSeparator()
.WriteLocationTaggedString(chunk.Prefix)
.WriteParameterSeparator()
.WriteLocationTaggedString(chunk.Suffix);
Visit((ChunkBlock)chunk);
_writer.WriteEndMethodInvocation();
}
protected override void Visit(SectionChunk chunk)
{
_writer.WriteStartMethodInvocation(_host.GeneratedClassContext.DefineSectionMethodName)
.WriteStringLiteral(chunk.Name)
.WriteParameterSeparator();
using (_writer.BuildLambda(false))
{
Visit((ChunkBlock)chunk);
}
_writer.WriteEndMethodInvocation();
}
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpDesignTimeHelpersVisitor : CodeVisitor
{
private const string InheritsHelper = "__inheritsHelper";
private CSharpCodeWriter _writer;
// TODO: No need for the entire host
private RazorEngineHost _host;
private string _sourceFile;
public CSharpDesignTimeHelpersVisitor(CSharpCodeWriter writer, RazorEngineHost host, string sourceFile)
{
_writer = writer;
_host = host;
_sourceFile = sourceFile;
}
public void Accept(CodeTree tree)
{
if(_host.DesignTimeMode)
{
using(_writer.BuildMethodDeclaration("private","void", "@"+CodeGeneratorContext.DesignTimeHelperMethodName))
{
using (_writer.BuildDisableWarningScope())
{
Accept(tree.Chunks);
}
}
}
}
protected override void Visit(SetBaseTypeChunk chunk)
{
if (_host.DesignTimeMode)
{
using (CSharpLineMappingWriter lineMappingWriter = _writer.BuildLineMapping(chunk.Start, chunk.TypeName.Length, _sourceFile))
{
_writer.Indent(chunk.Start.CharacterIndex);
lineMappingWriter.MarkLineMappingStart();
_writer.Write(chunk.TypeName);
lineMappingWriter.MarkLineMappingEnd();
_writer.Write(" ").Write(InheritsHelper).Write(" = null;");
}
}
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpHelperVisitor : CodeVisitor
{
private const string HelperWriterName = "__razor_helper_writer";
private CSharpCodeWriter _writer;
private string _sourceFile;
private RazorEngineHost _host;
private CSharpCodeVisitor _codeVisitor;
public CSharpHelperVisitor(CSharpCodeWriter writer, RazorEngineHost host, string sourceFile)
{
_writer = writer;
_sourceFile = sourceFile;
_host = host;
_codeVisitor = new CSharpCodeVisitor(writer, host, sourceFile);
}
protected override void Visit(HelperChunk chunk)
{
IDisposable lambdaScope = null;
using (CSharpLineMappingWriter mappingWriter = _writer.BuildLineMapping(chunk.Signature.Location, chunk.Signature.Value.Length, _sourceFile))
{
string accessibility = "public " + (_host.StaticHelpers ? "static" : String.Empty);
_writer.Write(accessibility).Write(" ").Write(_host.GeneratedClassContext.TemplateTypeName).Write(" ");
mappingWriter.MarkLineMappingStart();
_writer.Write(chunk.Signature);
mappingWriter.MarkLineMappingEnd();
}
if(chunk.HeaderComplete)
{
_writer.WriteStartReturn()
.WriteStartNewObject(_host.GeneratedClassContext.TemplateTypeName);
lambdaScope = _writer.BuildLambda(endLine: false, parameterNames: HelperWriterName);
}
// Generate children code
_codeVisitor.Accept(chunk.Children);
if (chunk.HeaderComplete)
{
lambdaScope.Dispose();
_writer.WriteEndMethodInvocation();
}
if(chunk.Footer != null && !String.IsNullOrEmpty(chunk.Footer.Value))
{
using(_writer.BuildLineMapping(chunk.Footer.Location, chunk.Footer.Value.Length, _sourceFile))
{
_writer.Write(chunk.Footer);
}
}
_writer.WriteLine();
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
public class CSharpTypeMemberVisitor : CodeVisitor
{
private CSharpCodeWriter _writer;
private string _sourceFile;
public CSharpTypeMemberVisitor(CSharpCodeWriter writer, string sourceFile)
{
_writer = writer;
_sourceFile = sourceFile;
}
protected override void Visit(TypeMemberChunk chunk)
{
Snippet code = chunk.Code.FirstOrDefault();
if (code != null)
{
using (_writer.BuildLineMapping(chunk.Start, code.Value.Length, _sourceFile))
{
_writer.WriteLine(code.Value);
}
}
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
// TODO: This class shares a lot of the same properties as the other CSharpCodeVisitor, make common base?
public class CSharpUsingVisitor : CodeVisitor
{
private CSharpCodeWriter _writer;
private string _sourceFile;
public CSharpUsingVisitor(CSharpCodeWriter writer, string sourceFile)
{
_writer = writer;
_sourceFile = sourceFile;
ImportedUsings = new List<string>();
}
public IList<string> ImportedUsings { get; set; }
protected override void Visit(UsingChunk chunk)
{
using (_writer.BuildLineMapping(chunk.Start, chunk.Association.Length, _sourceFile))
{
ImportedUsings.Add(chunk.Namespace);
_writer.WriteUsing(chunk.Namespace);
}
}
}
}

View File

@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public abstract class ChunkVisitor : IChunkVisitor
{
public void Accept(IList<Chunk> chunks)
{
if (chunks == null)
{
throw new ArgumentNullException("chunks");
}
foreach (Chunk chunk in chunks)
{
Accept(chunk);
}
}
public void Accept(Chunk chunk)
{
if (chunk == null)
{
throw new ArgumentNullException("chunk");
}
if (chunk is LiteralChunk)
{
Visit((LiteralChunk)chunk);
}
else if (chunk is ExpressionBlockChunk)
{
Visit((ExpressionBlockChunk)chunk);
}
else if (chunk is ExpressionChunk)
{
Visit((ExpressionChunk)chunk);
}
else if (chunk is StatementChunk)
{
Visit((StatementChunk)chunk);
}
else if(chunk is SetLayoutChunk)
{
Visit((SetLayoutChunk)chunk);
}
else if (chunk is ResolveUrlChunk)
{
Visit((ResolveUrlChunk)chunk);
}
else if (chunk is TypeMemberChunk)
{
Visit((TypeMemberChunk)chunk);
}
else if (chunk is UsingChunk)
{
Visit((UsingChunk)chunk);
}
else if(chunk is HelperChunk)
{
Visit((HelperChunk)chunk);
}
else if (chunk is SetBaseTypeChunk)
{
Visit((SetBaseTypeChunk)chunk);
}
else if (chunk is DynamicCodeAttributeChunk)
{
Visit((DynamicCodeAttributeChunk)chunk);
}
else if (chunk is LiteralCodeAttributeChunk)
{
Visit((LiteralCodeAttributeChunk)chunk);
}
else if (chunk is CodeAttributeChunk)
{
Visit((CodeAttributeChunk)chunk);
}
else if (chunk is SectionChunk)
{
Visit((SectionChunk)chunk);
}
else if (chunk is TemplateChunk)
{
Visit((TemplateChunk)chunk);
}
else if (chunk is ChunkBlock)
{
Visit((ChunkBlock)chunk);
}
else if(chunk is SessionStateChunk)
{
Visit((SessionStateChunk)chunk);
}
else
{
throw new InvalidOperationException("Unknown chunk type " + chunk.GetType().Name);
}
}
protected abstract void Visit(LiteralChunk chunk);
protected abstract void Visit(ExpressionChunk chunk);
protected abstract void Visit(StatementChunk chunk);
protected abstract void Visit(UsingChunk chunk);
protected abstract void Visit(ChunkBlock chunk);
protected abstract void Visit(DynamicCodeAttributeChunk chunk);
protected abstract void Visit(LiteralCodeAttributeChunk chunk);
protected abstract void Visit(CodeAttributeChunk chunk);
protected abstract void Visit(HelperChunk chunk);
protected abstract void Visit(SectionChunk chunk);
protected abstract void Visit(TypeMemberChunk chunk);
protected abstract void Visit(ResolveUrlChunk chunk);
protected abstract void Visit(SetBaseTypeChunk chunk);
protected abstract void Visit(TemplateChunk chunk);
protected abstract void Visit(SetLayoutChunk chunk);
protected abstract void Visit(ExpressionBlockChunk chunk);
protected abstract void Visit(SessionStateChunk chunk);
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeBuilder
{
protected CodeTree Tree;
public CodeBuilder(CodeTree codeTree)
{
Tree = codeTree;
}
public virtual CodeBuilderResult Build()
{
return null;
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeBuilderResult
{
public CodeBuilderResult(string code, IList<LineMapping> designTimeLineMappings)
{
Code = code;
DesignTimeLineMappings = designTimeLineMappings;
}
public string Code { get; private set; }
public IList<LineMapping> DesignTimeLineMappings { get; private set; }
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeVisitor : ChunkVisitor
{
protected override void Visit(LiteralChunk chunk)
{
}
protected override void Visit(ExpressionBlockChunk chunk)
{
}
protected override void Visit(ExpressionChunk chunk)
{
}
protected override void Visit(StatementChunk chunk)
{
}
protected override void Visit(UsingChunk chunk)
{
}
protected override void Visit(ChunkBlock chunk)
{
Accept(chunk.Children);
}
protected override void Visit(DynamicCodeAttributeChunk chunk)
{
}
protected override void Visit(LiteralCodeAttributeChunk chunk)
{
}
protected override void Visit(CodeAttributeChunk chunk)
{
}
protected override void Visit(HelperChunk chunk)
{
}
protected override void Visit(SectionChunk chunk)
{
}
protected override void Visit(TypeMemberChunk chunk)
{
}
protected override void Visit(ResolveUrlChunk chunk)
{
}
protected override void Visit(SetBaseTypeChunk chunk)
{
}
protected override void Visit(TemplateChunk chunk)
{
}
protected override void Visit(SetLayoutChunk chunk)
{
}
protected override void Visit(SessionStateChunk chunk)
{
}
}
}

View File

@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeWriter
{
protected StringWriter Writer;
private bool _newLine;
private string _cache;
private bool _dirty;
public CodeWriter()
{
Writer = new StringWriter();
_dirty = true;
}
public string LastWrite { get; private set; }
public int CurrentIndent { get; private set; }
public CodeWriter ResetIndent()
{
return SetIndent(0);
}
public CodeWriter IncreaseIndent(int size)
{
CurrentIndent += size;
return this;
}
public CodeWriter DecreaseIndent(int size)
{
CurrentIndent -= size;
return this;
}
public CodeWriter SetIndent(int size)
{
CurrentIndent = size;
return this;
}
public CodeWriter Indent(int size)
{
if (_newLine)
{
Writer.Write(new string(' ', size));
Flush();
_dirty = true;
_newLine = false;
}
return this;
}
public CodeWriter Write(string data)
{
Indent(CurrentIndent);
Writer.Write(data);
Flush();
LastWrite = data;
_dirty = true;
_newLine = false;
return this;
}
public CodeWriter WriteLine()
{
LastWrite = Environment.NewLine;
Writer.WriteLine();
Flush();
_dirty = true;
_newLine = true;
return this;
}
public CodeWriter WriteLine(string data)
{
return Write(data).WriteLine();
}
public CodeWriter Flush()
{
Writer.Flush();
return this;
}
public override string ToString()
{
if (_dirty)
{
_cache = Writer.ToString();
}
return _cache;
}
public SourceLocation GetCurrentSourceLocation()
{
string output = ToString();
string unescapedOutput = output.Replace("\\r", String.Empty).Replace("\\n", String.Empty);
return new SourceLocation(
absoluteIndex: output.Length,
lineIndex: (unescapedOutput.Length - unescapedOutput.Replace(Environment.NewLine, String.Empty).Length) / Environment.NewLine.Length,
characterIndex: unescapedOutput.Length - (unescapedOutput.LastIndexOf(Environment.NewLine) + Environment.NewLine.Length));
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public interface IChunkVisitor
{
void Accept(IList<Chunk> chunks);
void Accept(Chunk chunk);
}
}

View File

@ -0,0 +1,13 @@
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class Chunk
{
public SourceLocation Start { get; set; }
public SyntaxTreeNode Association { get; set; }
public string WriterName { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class ChunkBlock : Chunk
{
public ChunkBlock()
{
Children = new List<Chunk>();
}
public IList<Chunk> Children { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeAttributeChunk : ChunkBlock
{
public string Attribute { get; set; }
public LocationTagged<string> Prefix { get; set; }
public LocationTagged<string> Suffix { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class DynamicCodeAttributeChunk : ChunkBlock
{
public LocationTagged<string> Prefix { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class ExpressionBlockChunk : ChunkBlock
{
public ExpressionRenderingMode RenderingMode { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class ExpressionChunk : Chunk
{
public Snippet Code { get; set; }
public ExpressionRenderingMode RenderingMode { get; set; }
public override string ToString()
{
return Start + " = " + Code;
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class HelperChunk : ChunkBlock
{
public LocationTagged<string> Signature { get; set; }
public LocationTagged<string> Footer { get; set; }
// TODO: Can these properties be taken out?
public bool HeaderComplete { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class LiteralChunk : Chunk
{
public string Text { get; set; }
public override string ToString()
{
return Start + " = " + Text;
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class LiteralCodeAttributeChunk : ChunkBlock
{
public Snippet Code { get; set; }
public LocationTagged<string> Prefix { get; set; }
public LocationTagged<string> Value { get; set; }
public SourceLocation ValueLocation { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class ResolveUrlChunk : Chunk
{
public string Url { get; set; }
public ExpressionRenderingMode RenderingMode { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class SectionChunk : ChunkBlock
{
public string Name { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class SessionStateChunk : Chunk
{
public string Value { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class SetBaseTypeChunk : Chunk
{
public string TypeName { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class SetLayoutChunk : Chunk
{
public string Layout { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class StatementChunk : Chunk
{
public Snippets Code { get; set; }
public override string ToString()
{
return Start + " = " + Code;
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class TemplateChunk : ChunkBlock
{
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class TypeMemberChunk : Chunk
{
public Snippets Code { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class UsingChunk : Chunk
{
public string Namespace { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeTree
{
public CodeTree()
{
Chunks = new List<Chunk>();
}
public IList<Chunk> Chunks { get; set; }
}
}

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class CodeTreeBuilder
{
private Chunk _lastChunk;
private Stack<ChunkBlock> _blockChain;
public CodeTreeBuilder()
{
CodeTree = new CodeTree();
_blockChain = new Stack<ChunkBlock>();
}
public CodeTree CodeTree { get; private set; }
public void AddChunk(Chunk chunk, SyntaxTreeNode association, CodeGeneratorContext context, bool topLevel = false)
{
_lastChunk = chunk;
chunk.Start = association.Start;
chunk.Association = association;
chunk.WriterName = context.TargetWriterName;
// If we're not in the middle of a chunk block
if (_blockChain.Count == 0 || topLevel == true)
{
CodeTree.Chunks.Add(chunk);
}
else
{
_blockChain.Peek().Children.Add(chunk);
}
}
public void AddLiteralChunk(string literal, SyntaxTreeNode association, CodeGeneratorContext context)
{
if (_lastChunk is LiteralChunk)
{
((LiteralChunk)_lastChunk).Text += literal;
}
else
{
AddChunk(new LiteralChunk
{
Text = literal,
}, association, context);
}
}
public void AddExpressionChunk(string expression, ExpressionRenderingMode renderingMode, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new ExpressionChunk
{
Code = new Snippet(expression),
RenderingMode = renderingMode
}, association, context);
}
public void AddStatementChunk(string code, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new StatementChunk
{
Code = new Snippets(code),
}, association, context);
}
public void AddUsingChunk(string usingNamespace, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new UsingChunk
{
Namespace = usingNamespace,
}, association, context, topLevel: true);
}
public void AddTypeMemberChunk(string code, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new TypeMemberChunk
{
Code = new Snippets(code),
}, association, context, topLevel: true);
}
public void AddLiteralCodeAttributeChunk(string code, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new LiteralCodeAttributeChunk
{
Code = new Snippet(code),
}, association, context);
}
public void AddResolveUrlChunk(string url, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new ResolveUrlChunk
{
Url = url,
RenderingMode = context.ExpressionRenderingMode
}, association, context);
}
public void AddSetLayoutChunk(string layout, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new SetLayoutChunk
{
Layout = layout
}, association, context);
}
public void AddSetBaseTypeChunk(string typeName, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new SetBaseTypeChunk
{
TypeName = typeName.Trim()
}, association, context, topLevel: true);
}
public void AddSessionStateChunk(string value, SyntaxTreeNode association, CodeGeneratorContext context)
{
AddChunk(new SessionStateChunk
{
Value = value
}, association, context, topLevel: true);
}
public T StartChunkBlock<T>(SyntaxTreeNode association, CodeGeneratorContext context) where T : ChunkBlock
{
return StartChunkBlock<T>(association, context, topLevel: false);
}
public T StartChunkBlock<T>(SyntaxTreeNode association, CodeGeneratorContext context, bool topLevel) where T : ChunkBlock
{
T chunk = (T)Activator.CreateInstance(typeof(T));
AddChunk(chunk, association, context, topLevel);
_blockChain.Push(chunk);
return chunk;
}
public void EndChunkBlock()
{
_lastChunk = _blockChain.Pop();
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class Snippet
{
public Snippet() {}
public Snippet(string value)
{
Value = value;
}
public string Value { get; set; }
public SourceSpan View { get; set; }
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class Snippets : List<Snippet>
{
public Snippets() {}
public Snippets(int capacity)
: base(capacity) {}
public Snippets(IEnumerable<Snippet> collection)
: base(collection) {}
public Snippets(Snippets collection)
: base(collection) {}
public Snippets(string value)
: base(new[] { new Snippet { Value = value } }) {}
public override string ToString()
{
return string.Concat(this.Select(s => s.Value).ToArray());
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class LineMapping
{
public MappingLocation DocumentLocation { get; set; }
public MappingLocation GeneratedLocation { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class LineMappingManager
{
public LineMappingManager()
{
Mappings = new List<LineMapping>();
}
public List<LineMapping> Mappings { get; private set; }
public void AddMapping(MappingLocation documentLocation, MappingLocation generatedLocation)
{
Mappings.Add(new LineMapping
{
DocumentLocation = documentLocation,
GeneratedLocation = generatedLocation
});
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler
{
public class MappingLocation
{
public MappingLocation() : base() { }
public MappingLocation(SourceLocation location, int contentLength)
{
ContentLength = contentLength;
AbsoluteIndex = location.AbsoluteIndex;
LineIndex = location.LineIndex;
CharacterIndex = location.CharacterIndex;
}
public int ContentLength { get; set; }
public int AbsoluteIndex { get; set; }
public int LineIndex { get; set; }
public int CharacterIndex { get; set; }
}
}

View File

@ -6,6 +6,7 @@ using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
@ -30,6 +31,13 @@ namespace Microsoft.AspNet.Razor.Generator
public LocationTagged<string> Prefix { get; private set; }
public SourceLocation ValueStart { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
DynamicCodeAttributeChunk chunk = codeTreeBuilder.StartChunkBlock<DynamicCodeAttributeChunk>(target, context);
chunk.Start = ValueStart;
chunk.Prefix = Prefix;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
if (context.Host.DesignTimeMode)
@ -74,6 +82,14 @@ namespace Microsoft.AspNet.Razor.Generator
_oldTargetWriter = context.TargetWriterName;
context.TargetWriterName = ValueWriterName;
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
@ -118,6 +134,10 @@ namespace Microsoft.AspNet.Razor.Generator
context.AddStatement(generatedCode);
context.TargetWriterName = _oldTargetWriter;
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -2,12 +2,19 @@
using System;
using System.Linq;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class ExpressionCodeGenerator : HybridCodeGenerator
{
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
ExpressionBlockChunk chunk = codeTreeBuilder.StartChunkBlock<ExpressionBlockChunk>(target, context);
chunk.RenderingMode = context.ExpressionRenderingMode;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
if (context.Host.EnableInstrumentation && context.ExpressionRenderingMode == ExpressionRenderingMode.WriteToOutput)
@ -47,6 +54,14 @@ namespace Microsoft.AspNet.Razor.Generator
context.BufferStatementFragment(writeInvocation);
context.MarkStartOfGeneratedCode();
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
@ -83,6 +98,14 @@ namespace Microsoft.AspNet.Razor.Generator
context.AddContextCall(contentSpan, context.Host.GeneratedClassContext.EndContextMethodName, false);
}
}
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddExpressionChunk(target.Content, context.ExpressionRenderingMode, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
@ -93,6 +116,9 @@ namespace Microsoft.AspNet.Razor.Generator
sourceSpan = target;
}
context.BufferStatementFragment(target.Content, sourceSpan);
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -6,6 +6,7 @@ using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
@ -27,6 +28,15 @@ namespace Microsoft.AspNet.Razor.Generator
public LocationTagged<string> Footer { get; set; }
public bool HeaderComplete { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
HelperChunk chunk = codeTreeBuilder.StartChunkBlock<HelperChunk>(target, context, topLevel: true);
chunk.Signature = Signature;
chunk.Footer = Footer;
chunk.HeaderComplete = HeaderComplete;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
_writer = context.CreateCodeWriter();
@ -53,6 +63,14 @@ namespace Microsoft.AspNet.Razor.Generator
_statementCollectorToken = context.ChangeStatementCollector(AddStatementToHelper);
_oldWriter = context.TargetWriterName;
context.TargetWriterName = HelperWriterName;
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
@ -75,6 +93,9 @@ namespace Microsoft.AspNet.Razor.Generator
context.GeneratedClass.Members.Add(new CodeSnippetTypeMember(_writer.Content));
context.TargetWriterName = _oldWriter;
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
public override bool Equals(object obj)

View File

@ -5,6 +5,7 @@ using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Internal.Web.Utils;
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
@ -32,6 +33,16 @@ namespace Microsoft.AspNet.Razor.Generator
{
return;
}
LiteralCodeAttributeChunk chunk = context.CodeTreeBuilder.StartChunkBlock<LiteralCodeAttributeChunk>(target, context);
chunk.Prefix = Prefix;
chunk.Value = Value;
if (ValueGenerator != null)
{
chunk.ValueLocation = ValueGenerator.Location;
}
ExpressionRenderingMode oldMode = context.ExpressionRenderingMode;
context.BufferStatementFragment(context.BuildCodeString(cw =>
{
@ -63,6 +74,8 @@ namespace Microsoft.AspNet.Razor.Generator
context.ExpressionRenderingMode = oldMode;
context.AddStatement(context.BuildCodeString(cw =>
{
chunk.ValueLocation = ValueGenerator.Location;
cw.WriteParameterSeparator();
cw.WriteSnippet(ValueGenerator.Location.AbsoluteIndex.ToString(CultureInfo.CurrentCulture));
cw.WriteEndMethodInvoke();
@ -79,6 +92,8 @@ namespace Microsoft.AspNet.Razor.Generator
{
context.FlushBufferedStatement();
}
context.CodeTreeBuilder.EndChunkBlock();
}
public override string ToString()

View File

@ -1,12 +1,18 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class MarkupCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddLiteralChunk(target.Content, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
if (!context.Host.DesignTimeMode && String.IsNullOrEmpty(target.Content))
@ -44,6 +50,9 @@ namespace Microsoft.AspNet.Razor.Generator
{
context.AddContextCall(target, context.Host.GeneratedClassContext.EndContextMethodName, isLiteral: true);
}
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -2,6 +2,8 @@
using System;
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
@ -23,6 +25,14 @@ namespace Microsoft.AspNet.Razor.Generator
public string Value { get; private set; }
public void GenerateCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
if(Name == SyntaxConstants.CSharp.SessionStateKeyword)
{
codeTreeBuilder.AddSessionStateChunk(Value, target, context);
}
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
var attributeType = new CodeTypeReference(typeof(RazorDirectiveAttribute));
@ -31,6 +41,9 @@ namespace Microsoft.AspNet.Razor.Generator
new CodeAttributeArgument(new CodePrimitiveExpression(Name)),
new CodeAttributeArgument(new CodePrimitiveExpression(Value)));
context.GeneratedClass.CustomAttributes.Add(attributeDeclaration);
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -1,12 +1,18 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class ResolveUrlCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddResolveUrlChunk(target.Content, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
// Check if the host supports it
@ -73,6 +79,9 @@ namespace Microsoft.AspNet.Razor.Generator
{
context.AddContextCall(target, context.Host.GeneratedClassContext.EndContextMethodName, isLiteral: false);
}
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -3,6 +3,7 @@
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.Internal.Web.Utils;
using System;
using Microsoft.AspNet.Razor.Generator.Compiler;
namespace Microsoft.AspNet.Razor.Generator
{
@ -15,6 +16,13 @@ namespace Microsoft.AspNet.Razor.Generator
public string SectionName { get; private set; }
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
SectionChunk chunk = codeTreeBuilder.StartChunkBlock<SectionChunk>(target, context);
chunk.Name = SectionName;
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
string startBlock = context.BuildCodeString(cw =>
@ -25,6 +33,14 @@ namespace Microsoft.AspNet.Razor.Generator
cw.WriteStartLambdaDelegate();
});
context.AddStatement(startBlock);
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
@ -36,6 +52,9 @@ namespace Microsoft.AspNet.Razor.Generator
cw.WriteEndStatement();
});
context.AddStatement(startBlock);
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
public override bool Equals(object obj)

View File

@ -2,6 +2,7 @@
using System;
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
@ -15,6 +16,11 @@ namespace Microsoft.AspNet.Razor.Generator
public string BaseType { get; private set; }
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddSetBaseTypeChunk(target.Content, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
context.GeneratedClass.BaseTypes.Clear();
@ -38,6 +44,9 @@ namespace Microsoft.AspNet.Razor.Generator
};
context.AddDesignTimeHelperStatement(stmt);
}
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
protected virtual string ResolveType(CodeGeneratorContext context, string baseType)

View File

@ -2,6 +2,7 @@
using System;
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
@ -15,6 +16,11 @@ namespace Microsoft.AspNet.Razor.Generator
public string LayoutPath { get; set; }
public void GenerateCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddSetLayoutChunk(LayoutPath, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
if (!context.Host.DesignTimeMode && !String.IsNullOrEmpty(context.Host.GeneratedClassContext.LayoutPropertyName))
@ -24,6 +30,9 @@ namespace Microsoft.AspNet.Razor.Generator
new CodePropertyReferenceExpression(null, context.Host.GeneratedClassContext.LayoutPropertyName),
new CodePrimitiveExpression(LayoutPath)));
}
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
@ -7,6 +8,11 @@ namespace Microsoft.AspNet.Razor.Generator
{
public class StatementCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddStatementChunk(target.Content, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
context.FlushBufferedStatement();
@ -23,6 +29,9 @@ namespace Microsoft.AspNet.Razor.Generator
context.AddStatement(
generatedCode,
context.GenerateLinePragma(target, paddingCharCount));
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -1,16 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class TemplateBlockCodeGenerator : BlockCodeGenerator
{
private const string TemplateWriterName = "__razor_template_writer";
private const string ItemParameterName = "item";
internal const string TemplateWriterName = "__razor_template_writer";
internal const string ItemParameterName = "item";
private string _oldTargetWriter;
public void GenerateStartBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.StartChunkBlock<TemplateChunk>(target, context);
}
public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context)
{
string generatedCode = context.BuildCodeString(cw =>
@ -26,6 +32,14 @@ namespace Microsoft.AspNet.Razor.Generator
_oldTargetWriter = context.TargetWriterName;
context.TargetWriterName = TemplateWriterName;
// TODO: Make this generate the primary generator
GenerateStartBlockCode(target, context.CodeTreeBuilder, context);
}
public void GenerateEndBlockCode(SyntaxTreeNode target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.EndChunkBlock();
}
public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context)
@ -39,6 +53,9 @@ namespace Microsoft.AspNet.Razor.Generator
context.BufferStatementFragment(generatedCode);
context.TargetWriterName = _oldTargetWriter;
// TODO: Make this generate the primary generator
GenerateEndBlockCode(target, context.CodeTreeBuilder, context);
}
}
}

View File

@ -2,12 +2,18 @@
using System.CodeDom;
using System.Diagnostics.Contracts;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Generator
{
public class TypeMemberCodeGenerator : SpanCodeGenerator
{
public void GenerateCode(Span target, CodeTreeBuilder codeTreeBuilder, CodeGeneratorContext context)
{
codeTreeBuilder.AddTypeMemberChunk(target.Content, target, context);
}
public override void GenerateCode(Span target, CodeGeneratorContext context)
{
string generatedCode = context.BuildCodeString(cw =>
@ -25,6 +31,9 @@ namespace Microsoft.AspNet.Razor.Generator
{
LinePragma = context.GenerateLinePragma(target, paddingCharCount)
});
// TODO: Make this generate the primary generator
GenerateCode(target, context.CodeTreeBuilder, context);
}
public override string ToString()

View File

@ -1,55 +1,44 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.CodeDom;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor
{
/// <summary>
/// Represents results from code generation (and parsing, since that is a pre-requisite of code generation)
/// </summary>
/// <remarks>
/// Since this inherits from ParserResults, it has all the data from ParserResults, and simply adds code generation data
/// </remarks>
public class GeneratorResults : ParserResults
{
public GeneratorResults(ParserResults parserResults,
CodeCompileUnit generatedCode,
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings)
: this(parserResults.Document, parserResults.ParserErrors, generatedCode, designTimeLineMappings)
public GeneratorResults(ParserResults parserResults,
CodeBuilderResult codeBuilderResult)
: this(parserResults.Document, parserResults.ParserErrors, codeBuilderResult)
{
}
public GeneratorResults(Block document,
IList<RazorError> parserErrors,
CodeCompileUnit generatedCode,
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings)
: this(parserErrors.Count == 0, document, parserErrors, generatedCode, designTimeLineMappings)
CodeBuilderResult codeBuilderResult)
: this(parserErrors.Count == 0, document, parserErrors, codeBuilderResult)
{
}
protected GeneratorResults(bool success,
Block document,
IList<RazorError> parserErrors,
CodeCompileUnit generatedCode,
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings)
CodeBuilderResult codeBuilderResult)
: base(success, document, parserErrors)
{
GeneratedCode = generatedCode;
DesignTimeLineMappings = designTimeLineMappings;
GeneratedCode = codeBuilderResult.Code;
DesignTimeLineMappings = codeBuilderResult.DesignTimeLineMappings;
}
/// <summary>
/// The generated code
/// </summary>
public CodeCompileUnit GeneratedCode { get; private set; }
public string GeneratedCode { get; private set; }
public IList<LineMapping> DesignTimeLineMappings { get; private set; }
/// <summary>
/// If design-time mode was used in the Code Generator, this will contain the dictionary
/// of design-time generated code mappings
/// </summary>
public IDictionary<int, GeneratedCodeMapping> DesignTimeLineMappings { get; private set; }
public CodeCompileUnit CCU { get; set; }
internal CodeTree CT { get; set; }
}
}

View File

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator.Compiler;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor
{
/// <summary>
/// Represents results from code generation (and parsing, since that is a pre-requisite of code generation)
/// </summary>
/// <remarks>
/// Since this inherits from ParserResults, it has all the data from ParserResults, and simply adds code generation data
/// </remarks>
public class GeneratorResultsOLD : ParserResults
{
public GeneratorResultsOLD(ParserResults parserResults,
CodeCompileUnit generatedCode,
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings)
: this(parserResults.Document, parserResults.ParserErrors, generatedCode, designTimeLineMappings)
{
}
public GeneratorResultsOLD(Block document,
IList<RazorError> parserErrors,
CodeCompileUnit generatedCode,
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings)
: this(parserErrors.Count == 0, document, parserErrors, generatedCode, designTimeLineMappings)
{
}
protected GeneratorResultsOLD(bool success,
Block document,
IList<RazorError> parserErrors,
CodeCompileUnit generatedCode,
IDictionary<int, GeneratedCodeMapping> designTimeLineMappings)
: base(success, document, parserErrors)
{
GeneratedCode = generatedCode;
DesignTimeLineMappings = designTimeLineMappings;
}
public CodeTree CodeTree { get; set; }
/// <summary>
/// The generated code
/// </summary>
public CodeCompileUnit GeneratedCode { get; private set; }
/// <summary>
/// If design-time mode was used in the Code Generator, this will contain the dictionary
/// of design-time generated code mappings
/// </summary>
public IDictionary<int, GeneratedCodeMapping> DesignTimeLineMappings { get; private set; }
}
}

View File

@ -7,6 +7,8 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Text;
@ -175,8 +177,15 @@ namespace Microsoft.AspNet.Razor
designTimeLineMappings = generator.Context.CodeMappings;
}
var builder = new CSharpCodeBuilder(generator.Context.CodeTreeBuilder.CodeTree, rootNamespace, Host, sourceFileName);
CodeBuilderResult builderResult = builder.Build();
// Collect results and return
return new GeneratorResults(results, generator.Context.CompileUnit, designTimeLineMappings);
return new GeneratorResults(results, builderResult)
{
CCU = generator.Context.CompileUnit,
CT = generator.Context.CodeTreeBuilder.CodeTree
};
}
protected internal virtual RazorCodeGenerator CreateCodeGenerator(string className, string rootNamespace, string sourceFileName)

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Text
{
public class SourceSpan
{
public SourceLocation Begin { get; set; }
public SourceLocation End { get; set; }
}
}

View File

@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Razor.Test.Editor
// Assert
MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait);
string generatedCode = capturedArgs.GeneratorResults.GeneratedCode.GenerateCode<CSharpCodeProvider>();
string generatedCode = capturedArgs.GeneratorResults.CCU.GenerateCode<CSharpCodeProvider>();
Assert.Equal(
SimpleCSHTMLDocumentGenerated.ReadAllText(),

View File

@ -0,0 +1,27 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class CodeTreeGenerationTest : CSharpRazorCodeGeneratorTest
{
[Fact]
public void CodeTreeComparisonTest()
{
RunTest("CodeTree", onResults: (results, codDOMOutput) =>
{
File.WriteAllText("./testfile_ct.cs", results.GeneratedCode);
File.WriteAllText("./testfile_cd.cs", codDOMOutput);
}, designTimeMode: false);
}
}
}

View File

@ -39,7 +39,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator
IList<GeneratedCodeMapping> expectedDesignTimePragmas = null,
TestSpan[] spans = null,
TabTest tabTest = TabTest.Both,
Action<RazorEngineHost> hostConfig = null)
Action<RazorEngineHost> hostConfig = null,
Action<GeneratorResults, string> onResults = null)
{
bool testRun = false;
@ -56,7 +57,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator
expectedDesignTimePragmas: expectedDesignTimePragmas,
spans: spans,
withTabs: true,
hostConfig: hostConfig);
hostConfig: hostConfig,
onResults: onResults);
}
testRun = true;
@ -75,7 +77,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator
expectedDesignTimePragmas: expectedDesignTimePragmas,
spans: spans,
withTabs: false,
hostConfig: hostConfig);
hostConfig: hostConfig,
onResults: onResults);
}
testRun = true;
@ -91,7 +94,8 @@ namespace Microsoft.AspNet.Razor.Test.Generator
IList<GeneratedCodeMapping> expectedDesignTimePragmas,
TestSpan[] spans,
bool withTabs,
Action<RazorEngineHost> hostConfig)
Action<RazorEngineHost> hostConfig,
Action<GeneratorResults, string> onResults = null)
{
// Load the test files
if (baselineName == null)
@ -99,6 +103,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
baselineName = name;
}
string sourceLocation = String.Format("/CodeGenerator/{1}/Source/{0}.{2}", name, LanguageName, FileExtension);
string source = TestFile.Create(String.Format("CodeGenerator.{1}.Source.{0}.{2}", name, LanguageName, FileExtension)).ReadAllText();
string expectedOutput = TestFile.Create(String.Format("CodeGenerator.{1}.Output.{0}.{2}", baselineName, LanguageName, BaselineExtension)).ReadAllText();
@ -137,10 +142,10 @@ namespace Microsoft.AspNet.Razor.Test.Generator
using (StringTextBuffer buffer = new StringTextBuffer(source))
{
results = engine.GenerateCode(buffer, className: name, rootNamespace: TestRootNamespaceName, sourceFileName: generatePragmas ? String.Format("{0}.{1}", name, FileExtension) : null);
}
}
// Generate code
CodeCompileUnit ccu = results.GeneratedCode;
CodeCompileUnit ccu = results.CCU;
CodeDomProvider codeProvider = (CodeDomProvider)Activator.CreateInstance(host.CodeLanguage.CodeDomProviderType);
CodeGeneratorOptions options = new CodeGeneratorOptions();
@ -162,9 +167,15 @@ namespace Microsoft.AspNet.Razor.Test.Generator
#if !GENERATE_BASELINES
string textOutput = MiscUtils.StripRuntimeVersion(output.ToString());
if (onResults != null)
{
onResults(results, textOutput);
}
//// Verify code against baseline
Assert.Equal(expectedOutput, textOutput);
#endif
#endif
IEnumerable<Span> generatedSpans = results.Document.Flatten();
@ -186,13 +197,13 @@ namespace Microsoft.AspNet.Razor.Test.Generator
Assert.True(results.DesignTimeLineMappings != null && results.DesignTimeLineMappings.Count > 0);
Assert.Equal(expectedDesignTimePragmas.Count, results.DesignTimeLineMappings.Count);
/*
Assert.Equal(
expectedDesignTimePragmas.ToArray(),
results.DesignTimeLineMappings
.OrderBy(p => p.Key)
.Select(p => p.Value)
.ToArray());
.ToArray());*/
}
}
}

View File

@ -13,6 +13,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<Prefer32Bit>false</Prefer32Bit>
<DefineConstants>
</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
@ -49,6 +51,7 @@
<Compile Include="Framework\TestSpanBuilder.cs" />
<Compile Include="Framework\VBHtmlCodeParserTestBase.cs" />
<Compile Include="Framework\VBHtmlMarkupParserTestBase.cs" />
<Compile Include="Generator\CodeTree\CodeTreeGenerationTest.cs" />
<Compile Include="Generator\GeneratedCodeMappingTest.cs" />
<Compile Include="Generator\PaddingTest.cs" />
<Compile Include="Generator\TabTest.cs" />
@ -160,6 +163,7 @@
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\SimpleUnspacedIf.DesignTime.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HtmlCommentWithQuote_Single.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HtmlCommentWithQuote_Double.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\CodeTree.cs" />
<Compile Include="Text\LineTrackingStringBufferTest.cs" />
<Compile Include="Tokenizer\VBTokenizerLiteralTest.cs" />
<Compile Include="Tokenizer\VBTokenizerIdentifierTest.cs" />
@ -411,6 +415,7 @@
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\SimpleUnspacedIf.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HtmlCommentWithQuote_Double.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HtmlCommentWithQuote_Single.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\CodeTree.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Blocks.vb" />

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Razor.Test.TestFiles.CodeGenerator.CS.Output
{
public class CodeTree
{
}
}

View File

@ -0,0 +1,14 @@
@helper foo(int bar)
{
<div>@bar</div>
}
@helper foo2(string bar)
{
<div>@bar</div>
<script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
}
<span>Hello WOrld</span>
<script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>