예제 #1
0
        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)));
            }
        }
    }