protected override Expression VisitHelperExpression(HelperExpression hex) { var pathInfo = PathInfoStore.Shared.GetOrAdd(hex.HelperName); if (!pathInfo.IsValidHelperLiteral && !CompilationContext.Configuration.Compatibility.RelaxedHelperNaming) { return(Expression.Empty()); } var helperName = pathInfo.TrimmedPath; var bindingContext = CompilationContext.Args.BindingContext; var options = New(() => new HelperOptions(bindingContext)); var textWriter = CompilationContext.Args.EncodedWriter; var contextValue = New(() => new Context(bindingContext)); var args = FunctionBinderHelpers.CreateArguments(hex.Arguments, CompilationContext); var configuration = CompilationContext.Configuration; if (configuration.Helpers.TryGetValue(pathInfo, out var helper)) { return(Call(() => helper.Value.Invoke(textWriter, options, contextValue, args))); } for (var index = 0; index < configuration.HelperResolvers.Count; index++) { var resolver = configuration.HelperResolvers[index]; if (resolver.TryResolveHelper(helperName, typeof(object), out var resolvedHelper)) { helper = new Ref <IHelperDescriptor <HelperOptions> >(resolvedHelper); configuration.Helpers.AddOrReplace(pathInfo, helper); return(Call(() => resolvedHelper.Invoke(textWriter, options, contextValue, args))); } } var lateBindDescriptor = new Ref <IHelperDescriptor <HelperOptions> >(new LateBindHelperDescriptor(pathInfo)); configuration.Helpers.AddOrReplace(pathInfo, lateBindDescriptor); return(Call(() => lateBindDescriptor.Value.Invoke(textWriter, options, contextValue, args))); }
protected override Expression VisitHelperExpression(HelperExpression hex) { var pathInfo = CompilationContext.Configuration.PathInfoStore.GetOrAdd(hex.HelperName); if (!pathInfo.IsValidHelperLiteral && !CompilationContext.Configuration.Compatibility.RelaxedHelperNaming) { return(Expression.Empty()); } var helperName = pathInfo.TrimmedPath; var bindingContext = CompilationContext.Args.BindingContext; var textWriter = CompilationContext.Args.EncodedWriter; var contextValue = bindingContext.Property(o => o.Value); var args = FunctionBinderHelpers.CreateArguments(hex.Arguments, CompilationContext); var configuration = CompilationContext.Configuration; if (configuration.Helpers.TryGetValue(pathInfo, out var helper)) { return(Call(() => helper.Value.WriteInvoke(bindingContext, textWriter, contextValue, args))); } for (var index = 0; index < configuration.HelperResolvers.Count; index++) { var resolver = configuration.HelperResolvers[index]; if (resolver.TryResolveHelper(helperName, typeof(object), out var resolvedHelper)) { helper = new StrongBox <HelperDescriptorBase>(resolvedHelper); configuration.Helpers.Add(pathInfo, helper); return(Call(() => resolvedHelper.WriteInvoke(bindingContext, textWriter, contextValue, args))); } } var lateBindDescriptor = new StrongBox <HelperDescriptorBase>(new LateBindHelperDescriptor(pathInfo, configuration)); configuration.Helpers.Add(pathInfo, lateBindDescriptor); return(Call(() => lateBindDescriptor.Value.WriteInvoke(bindingContext, textWriter, contextValue, args))); }
protected override Expression VisitBlockHelperExpression(BlockHelperExpression bhex) { var isInlinePartial = bhex.HelperName == "#*inline"; var pathInfo = PathInfoStore.Current.GetOrAdd(bhex.HelperName); var bindingContext = CompilationContext.Args.BindingContext; var context = isInlinePartial ? bindingContext.As <object>() : bindingContext.Property(o => o.Value); var readerContext = bhex.Context; var direct = Compile(bhex.Body); var inverse = Compile(bhex.Inversion); var args = FunctionBinderHelpers.CreateArguments(bhex.Arguments, CompilationContext); var direction = bhex.IsRaw || pathInfo.IsBlockHelper ? BlockHelperDirection.Direct : BlockHelperDirection.Inverse; var blockParams = CreateBlockParams(); var blockHelpers = CompilationContext.Configuration.BlockHelpers; if (blockHelpers.TryGetValue(pathInfo, out var descriptor)) { return(BindByRef(pathInfo, descriptor)); } var helperResolvers = CompilationContext.Configuration.HelperResolvers; for (var index = 0; index < helperResolvers.Count; index++) { var resolver = helperResolvers[index]; if (!resolver.TryResolveBlockHelper(pathInfo, out var resolvedDescriptor)) { continue; } descriptor = new Ref <IHelperDescriptor <BlockHelperOptions> >(resolvedDescriptor); blockHelpers.AddOrReplace(pathInfo, descriptor); return(BindByRef(pathInfo, descriptor)); } var lateBindBlockHelperDescriptor = new LateBindBlockHelperDescriptor(pathInfo); var lateBindBlockHelperRef = new Ref <IHelperDescriptor <BlockHelperOptions> >(lateBindBlockHelperDescriptor); blockHelpers.AddOrReplace(pathInfo, lateBindBlockHelperRef); return(BindByRef(pathInfo, lateBindBlockHelperRef)); ExpressionContainer <ChainSegment[]> CreateBlockParams() { var parameters = bhex.BlockParams?.BlockParam?.Parameters; parameters ??= ArrayEx.Empty <ChainSegment>(); return(Arg(parameters)); } TemplateDelegate Compile(Expression expression) { var blockExpression = (BlockExpression)expression; return(FunctionBuilder.Compile(blockExpression.Expressions, new CompilationContext(CompilationContext))); } Expression BindByRef(PathInfo name, Ref <IHelperDescriptor <BlockHelperOptions> > helperBox) { var writer = CompilationContext.Args.EncodedWriter; var helperOptions = direction switch { BlockHelperDirection.Direct => New(() => new BlockHelperOptions(name, direct, inverse, blockParams, bindingContext)), BlockHelperDirection.Inverse => New(() => new BlockHelperOptions(name, inverse, direct, blockParams, bindingContext)), _ => throw new HandlebarsCompilerException("Helper referenced with unknown prefix", readerContext) }; var callContext = New(() => new Context(bindingContext, context)); return(Call(() => helperBox.Value.Invoke(writer, helperOptions, callContext, args))); } } }