// 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.CodeDom; using System.Globalization; using System.Web.Razor.Parser.SyntaxTree; using System.Web.Razor.Text; using Microsoft.Internal.Web.Utils; namespace System.Web.Razor.Generator { public class HelperCodeGenerator : BlockCodeGenerator { private const string HelperWriterName = "__razor_helper_writer"; private CodeWriter _writer; private string _oldWriter; private IDisposable _statementCollectorToken; public HelperCodeGenerator(LocationTagged signature, bool headerComplete) { Signature = signature; HeaderComplete = headerComplete; } public LocationTagged Signature { get; private set; } public LocationTagged Footer { get; set; } public bool HeaderComplete { get; private set; } public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context) { _writer = context.CreateCodeWriter(); string prefix = context.BuildCodeString( cw => cw.WriteHelperHeaderPrefix(context.Host.GeneratedClassContext.TemplateTypeName, context.Host.StaticHelpers)); _writer.WriteLinePragma( context.GenerateLinePragma(Signature.Location, prefix.Length, Signature.Value.Length)); _writer.WriteSnippet(prefix); _writer.WriteSnippet(Signature); if (HeaderComplete) { _writer.WriteHelperHeaderSuffix(context.Host.GeneratedClassContext.TemplateTypeName); } _writer.WriteLinePragma(null); if (HeaderComplete) { _writer.WriteReturn(); _writer.WriteStartConstructor(context.Host.GeneratedClassContext.TemplateTypeName); _writer.WriteStartLambdaDelegate(HelperWriterName); } _statementCollectorToken = context.ChangeStatementCollector(AddStatementToHelper); _oldWriter = context.TargetWriterName; context.TargetWriterName = HelperWriterName; } public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context) { _statementCollectorToken.Dispose(); if (HeaderComplete) { _writer.WriteEndLambdaDelegate(); _writer.WriteEndConstructor(); _writer.WriteEndStatement(); } if (Footer != null && !String.IsNullOrEmpty(Footer.Value)) { _writer.WriteLinePragma( context.GenerateLinePragma(Footer.Location, 0, Footer.Value.Length)); _writer.WriteSnippet(Footer); _writer.WriteLinePragma(); } _writer.WriteHelperTrailer(); context.GeneratedClass.Members.Add(new CodeSnippetTypeMember(_writer.Content)); context.TargetWriterName = _oldWriter; } public override bool Equals(object obj) { HelperCodeGenerator other = obj as HelperCodeGenerator; return other != null && base.Equals(other) && HeaderComplete == other.HeaderComplete && Equals(Signature, other.Signature); } public override int GetHashCode() { return HashCodeCombiner.Start() .Add(base.GetHashCode()) .Add(Signature) .CombinedHash; } public override string ToString() { return "Helper:" + Signature.ToString("F", CultureInfo.CurrentCulture) + ";" + (HeaderComplete ? "C" : "I"); } private void AddStatementToHelper(string statement, CodeLinePragma pragma) { if (pragma != null) { _writer.WriteLinePragma(pragma); } _writer.WriteSnippet(statement); _writer.InnerWriter.WriteLine(); // CodeDOM normally inserts an extra line so we need to do so here. if (pragma != null) { _writer.WriteLinePragma(); } } } }