/// <inheritdoc/> protected override void Write(CompilationRenderer renderer, InterpolationToken obj, CompilerContext context) { var member = obj.Content.ToString(); var expression = context.Lookup(member); if (!context.CompilationSettings.SkipHtmlEncoding && obj.EscapeResult && expression != null) { var isValueType = expression.Type.GetIsValueType(); var stringExpression = expression.Type == typeof(string) ? expression : Expression.Call( isValueType ? expression : Expression.Coalesce(expression, Expression.Constant(string.Empty)), expression.Type.GetMethod("ToString", Type.EmptyTypes)); expression = Expression.Call(null, MethodInfos.Instance.HtmlEncode, stringExpression); } if (obj.Indent > 0) { var append = Expression.Call(renderer.Builder, MethodInfos.Instance.StringBuilderAppendString, Expression.Constant(new string(' ', obj.Indent))); renderer.AddExpressionToScope(append); } if (expression != null) { var appendMethod = typeof(StringBuilder).GetMethod("Append", new[] { expression.Type }); var append = Expression.Call(renderer.Builder, appendMethod, expression); renderer.AddExpressionToScope(append); } }
/// <inheritdoc/> protected override async Task WriteAsync(CompilationRenderer renderer, SectionToken obj, CompilerContext context) { var value = context.Lookup(obj.SectionName); if (value == null) { return; } Expression expression = null; if (typeof(IEnumerable).IsAssignableFrom(value.Type) && !EnumerableBlacklist.Any(x => x.IsAssignableFrom(value.Type))) { var innerType = value.Type.GetElementTypeOfIEnumerable(); var param = Expression.Parameter(innerType); var sectionContent = (await renderer.RenderAsync(obj, context.Push(innerType, param))) as List <Expression>; if (sectionContent.Count > 0) { expression = WriteIEnumerable(value, param, innerType, sectionContent); } } else if (typeof(IEnumerator).IsAssignableFrom(value.Type)) { var innerType = value.Type.GetElementTypeOfIEnumerable() ?? typeof(object); var param = Expression.Parameter(innerType); var sectionContent = (await renderer.RenderAsync(obj, context.Push(innerType, param))) as List <Expression>; if (sectionContent.Count > 0) { expression = WriteIEnumerator(value, param, innerType, sectionContent); } } else if (typeof(IDictionary).IsAssignableFrom(value.Type) || value != null) { var param = Expression.Parameter(value.Type); var assignment = Expression.Assign(param, value); var sectionContent = await renderer.RenderAsync(obj, context.Push(value.Type, param)) as List <Expression>; if (sectionContent.Count > 0) { expression = Expression.Block(new[] { param }, new[] { assignment }.Concat(sectionContent)); } } if (expression != null) { var truthy = context.GetTruthyExpression(value); var ex = truthy != null ? Expression.IfThen(truthy, expression) : expression; renderer.AddExpressionToScope(ex); } }
private async ValueTask <Func <T, string> > CompileAsync <T>(string template, Type viewType, IDictionary <string, string> partials, CompilationSettings settings) { var loadedTemplate = await CompilerSettings.TemplateLoader.LoadAsync(template); if (loadedTemplate == null) { throw new UnknownTemplateException("No template was found with the name '" + template + "'"); } var document = CompilerSettings.Parser.Parse(loadedTemplate, CompilerSettings.DefaultTags, pipeline: CompilerSettings.ParserPipeline); var renderer = new CompilationRenderer <T>(CompilerSettings.RendererPipeline, CompilerSettings.MaxRecursionDepth); var compilationContext = BuildCompilerContext(viewType, partials, settings); return(await renderer.CompileAsync(document, compilationContext) as Func <T, string>); }
/// <inheritdoc/> protected override void Write(CompilationRenderer renderer, InterpolationToken obj, CompilerContext context) { var member = obj.Content.ToString(); var expression = context.Lookup(member); if (!context.CompilationSettings.SkipHtmlEncoding && obj.EscapeResult && expression != null) { Expression stringExpression; if (expression.Type == typeof(string)) { stringExpression = expression; } else { var formattedToString = expression.Type .GetMethod(nameof(object.ToString), formatProviderTypeArgs); var item = expression.Type.GetIsValueType() ? expression : Expression.Coalesce(expression, Expression.Constant(string.Empty)); stringExpression = formattedToString is object ?Expression.Call(item, formattedToString, Expression.Constant(context.CompilationSettings.CultureInfo)) : Expression.Call(item, expression.Type.GetMethod(nameof(object.ToString), Type.EmptyTypes)); } expression = Expression.Invoke(context.CompilerSettings.EncodingFuction, stringExpression); } if (obj.Indent > 0) { var append = Expression.Call(renderer.Builder, MethodInfos.Instance.StringBuilderAppendString, Expression.Constant(new string(' ', obj.Indent))); renderer.AddExpressionToScope(append); } if (expression != null) { var appendMethod = typeof(StringBuilder).GetMethod("Append", new[] { expression.Type }); var append = Expression.Call(renderer.Builder, appendMethod, expression); renderer.AddExpressionToScope(append); } }
/// <inheritdoc/> protected override async Task WriteAsync(CompilationRenderer renderer, PartialToken obj, CompilerContext context) { var partialName = obj.Content; string template = null; if (context.PartialLoader != null) { template = await context.PartialLoader.LoadAsync(partialName.ToString()); } if (template != null) { var sourceDatas = context.GetNestedSourceData().ToArray(); var key = PartialLambdaExpressionDefinition.GetKey(template, context.SourceData.Type); // Recursive calls use the existing variable to call the partial lambda. if (renderer.PartialExpressionCache.TryGetValue(key, out var partialVariable)) { renderer.AddExpressionToScope(Expression.Invoke(partialVariable.Variable, context.SourceData)); return; } var sourceData = sourceDatas.Select(s => s.Type).ToArray(); if (sourceData.Length > 16) { throw new StubbleException("Cannot call a partial with more than 16 parameters.\nThis is likely due to a large amount of section scopes"); } var actionType = Expression.GetActionType(sourceData); var definition = new PartialLambdaExpressionDefinition { Variable = Expression.Parameter(actionType) }; renderer.PartialExpressionCache.Add(key, definition); var partialContent = await renderer.RenderAsync(context.CompilerSettings.Parser.Parse(template, lineIndent: obj.LineIndent), context) as List <Expression>; renderer.AddExpressionToScope(AddLambdaDefinition(definition, partialContent, actionType, sourceDatas)); } }
/// <inheritdoc/> protected override void Write(CompilationRenderer renderer, LiteralToken obj, CompilerContext context) { var builder = new StringBuilder(); for (var i = 0; i < obj.Content.Length; i++) { var item = obj.Content[i]; if (obj.Indent > 0 && !item.IsEmptyOrWhitespace()) { builder.Append(' ', obj.Indent); } builder.Append(item.ToString()); } var append = Expression.Call(renderer.Builder, MethodInfos.Instance.StringBuilderAppendString, Expression.Constant(builder.ToString())); renderer.AddExpressionToScope(append); }
/// <inheritdoc/> protected override async Task WriteAsync(CompilationRenderer renderer, InvertedSectionToken obj, CompilerContext context) { Expression expression = null; if (await renderer.RenderAsync(obj, context) is List <Expression> sectionContent && sectionContent.Count > 0) { expression = Expression.Block(sectionContent); } var value = context.Lookup(obj.SectionName); if (value != null && expression != null) { expression = Expression.IfThen(Expression.Not(context.GetTruthyExpression(value)), expression); } if (expression != null) { renderer.AddExpressionToScope(expression); } }
/// <inheritdoc/> protected override Task WriteAsync(CompilationRenderer renderer, InterpolationToken obj, CompilerContext context) { Write(renderer, obj, context); return(TaskHelpers.CompletedTask); }