// 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.Globalization; using System.Linq; using System.Web.Razor.Parser.SyntaxTree; using System.Web.Razor.Text; using Microsoft.Internal.Web.Utils; namespace System.Web.Razor.Generator { public class DynamicAttributeBlockCodeGenerator : BlockCodeGenerator { private const string ValueWriterName = "__razor_attribute_value_writer"; private string _oldTargetWriter; private bool _isExpression; private ExpressionRenderingMode _oldRenderingMode; public DynamicAttributeBlockCodeGenerator(LocationTagged prefix, int offset, int line, int col) : this(prefix, new SourceLocation(offset, line, col)) { } public DynamicAttributeBlockCodeGenerator(LocationTagged prefix, SourceLocation valueStart) { Prefix = prefix; ValueStart = valueStart; } public LocationTagged Prefix { get; private set; } public SourceLocation ValueStart { get; private set; } public override void GenerateStartBlockCode(Block target, CodeGeneratorContext context) { if (context.Host.DesignTimeMode) { return; // Don't generate anything! } // What kind of block is nested within string generatedCode; Block child = target.Children.Where(n => n.IsBlock).Cast().FirstOrDefault(); if (child != null && child.Type == BlockType.Expression) { _isExpression = true; generatedCode = context.BuildCodeString(cw => { cw.WriteParameterSeparator(); cw.WriteStartMethodInvoke("Tuple.Create"); cw.WriteLocationTaggedString(Prefix); cw.WriteParameterSeparator(); cw.WriteStartMethodInvoke("Tuple.Create", "System.Object", "System.Int32"); }); _oldRenderingMode = context.ExpressionRenderingMode; context.ExpressionRenderingMode = ExpressionRenderingMode.InjectCode; } else { generatedCode = context.BuildCodeString(cw => { cw.WriteParameterSeparator(); cw.WriteStartMethodInvoke("Tuple.Create"); cw.WriteLocationTaggedString(Prefix); cw.WriteParameterSeparator(); cw.WriteStartMethodInvoke("Tuple.Create", "System.Object", "System.Int32"); cw.WriteStartConstructor(context.Host.GeneratedClassContext.TemplateTypeName); cw.WriteStartLambdaDelegate(ValueWriterName); }); } context.MarkEndOfGeneratedCode(); context.BufferStatementFragment(generatedCode); _oldTargetWriter = context.TargetWriterName; context.TargetWriterName = ValueWriterName; } public override void GenerateEndBlockCode(Block target, CodeGeneratorContext context) { if (context.Host.DesignTimeMode) { return; // Don't generate anything! } string generatedCode; if (_isExpression) { generatedCode = context.BuildCodeString(cw => { cw.WriteParameterSeparator(); cw.WriteSnippet(ValueStart.AbsoluteIndex.ToString(CultureInfo.CurrentCulture)); cw.WriteEndMethodInvoke(); cw.WriteParameterSeparator(); // literal: false - This attribute value is not a literal value, it is dynamically generated cw.WriteBooleanLiteral(false); cw.WriteEndMethodInvoke(); cw.WriteLineContinuation(); }); context.ExpressionRenderingMode = _oldRenderingMode; } else { generatedCode = context.BuildCodeString(cw => { cw.WriteEndLambdaDelegate(); cw.WriteEndConstructor(); cw.WriteParameterSeparator(); cw.WriteSnippet(ValueStart.AbsoluteIndex.ToString(CultureInfo.CurrentCulture)); cw.WriteEndMethodInvoke(); cw.WriteParameterSeparator(); // literal: false - This attribute value is not a literal value, it is dynamically generated cw.WriteBooleanLiteral(false); cw.WriteEndMethodInvoke(); cw.WriteLineContinuation(); }); } context.AddStatement(generatedCode); context.TargetWriterName = _oldTargetWriter; } public override string ToString() { return String.Format(CultureInfo.CurrentCulture, "DynAttr:{0:F}", Prefix); } public override bool Equals(object obj) { DynamicAttributeBlockCodeGenerator other = obj as DynamicAttributeBlockCodeGenerator; return other != null && Equals(other.Prefix, Prefix); } public override int GetHashCode() { return HashCodeCombiner.Start() .Add(Prefix) .CombinedHash; } } }