Example #1
0
        protected override Expression VisitIteratorExpression(IteratorExpression iex)
        {
            var context  = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var sequence = ExpressionShortcuts.Var <object>("sequence");

            var template = FunctionBuilder.CompileCore(new[] { iex.Template }, CompilationContext.Configuration);
            var ifEmpty  = FunctionBuilder.CompileCore(new[] { iex.IfEmpty }, CompilationContext.Configuration);

            var compiledSequence       = ExpressionShortcuts.Arg <object>(FunctionBuilder.Reduce(iex.Sequence, CompilationContext));
            var blockParams            = ExpressionShortcuts.Arg <BlockParam>(iex.BlockParams);
            var blockParamsProvider    = ExpressionShortcuts.Call(() => BlockParamsValueProvider.Create(context, blockParams));
            var blockParamsProviderVar = ExpressionShortcuts.Var <BlockParamsValueProvider>();

            return(ExpressionShortcuts.Block()
                   .Parameter(sequence, compiledSequence)
                   .Parameter(blockParamsProviderVar, blockParamsProvider)
                   .Line(blockParamsProviderVar.Using((self, builder) =>
            {
                builder
                .Line(context.Call(o => o.RegisterValueProvider((IValueProvider)self)))
                .Line(ExpressionShortcuts.Try()
                      .Body(ExpressionShortcuts.Call(() =>
                                                     Iterator.Iterate(context, self, sequence, template, ifEmpty)
                                                     ))
                      .Finally(context.Call(o => o.UnregisterValueProvider((IValueProvider)self)))
                      );
            })));
        }
        private static void RenderSection(
            object value,
            BindingContext context,
            Action <BindingContext, TextWriter, object> body,
            Action <BindingContext, TextWriter, object> inversion,
            BlockParamsValueProvider blockParamsValueProvider
            )
        {
            switch (value)
            {
            case bool boolValue when boolValue:
                body(context, context.TextWriter, context);
                return;

            case null:
            case object _ when HandlebarsUtils.IsFalsyOrEmpty(value):
                inversion(context, context.TextWriter, context);

                return;

            case string _:
                body(context, context.TextWriter, value);
                return;

            case IEnumerable enumerable:
                Iterator.Iterate(context, blockParamsValueProvider, enumerable, body, inversion);
                break;

            default:
                body(context, context.TextWriter, value);
                break;
            }
        }
Example #3
0
        private static void IterateEnumerable(BindingContext context,
                                              BlockParamsValueProvider blockParamsValueProvider,
                                              IEnumerable target,
                                              Action <BindingContext, TextWriter, object> template,
                                              Action <BindingContext, TextWriter, object> ifEmpty)
        {
            using (var iterator = IteratorValueProvider.Create())
            {
                blockParamsValueProvider?.Configure(BlockParamsEnumerableConfiguration, iterator);

                iterator.Index = 0;
                var  enumerable = new ExtendedEnumerable <object>(target);
                bool enumerated = false;

                foreach (var enumerableValue in enumerable)
                {
                    enumerated     = true;
                    iterator.Value = enumerableValue.Value;
                    iterator.First = enumerableValue.IsFirst;
                    iterator.Last  = enumerableValue.IsLast;

                    using (var innerContext = context.CreateChildContext(iterator.Value))
                    {
                        innerContext.RegisterValueProvider(iterator);
                        template(context, context.TextWriter, innerContext);
                        innerContext.UnregisterValueProvider(iterator);
                    }
                }

                if (iterator.Index == 0 && !enumerated)
                {
                    ifEmpty(context, context.TextWriter, context.Value);
                }
            }
        }
Example #4
0
        private static void IterateList(BindingContext context,
                                        BlockParamsValueProvider blockParamsValueProvider,
                                        IList target,
                                        Action <BindingContext, TextWriter, object> template,
                                        Action <BindingContext, TextWriter, object> ifEmpty)
        {
            using (var iterator = IteratorValueProvider.Create())
            {
                blockParamsValueProvider?.Configure(BlockParamsEnumerableConfiguration, iterator);

                var count = target.Count;
                for (iterator.Index = 0; iterator.Index < count; iterator.Index++)
                {
                    iterator.Value = target[iterator.Index];
                    iterator.First = iterator.Index == 0;
                    iterator.Last  = iterator.Index == count - 1;

                    using (var innerContext = context.CreateChildContext(iterator.Value))
                    {
                        innerContext.RegisterValueProvider(iterator);
                        template(context, context.TextWriter, innerContext);
                        innerContext.UnregisterValueProvider(iterator);
                    }
                }

                if (iterator.Index == 0)
                {
                    ifEmpty(context, context.TextWriter, context.Value);
                }
            }
        }
 public static void Helper(BindingContext context, char prefix, object value,
                           Action <BindingContext, TextWriter, object> body, Action <BindingContext, TextWriter, object> inverse,
                           BlockParamsValueProvider blockParamsValueProvider)
 {
     if (prefix == '#')
     {
         RenderSection(value, context, body, inverse, blockParamsValueProvider);
     }
     else
     {
         RenderSection(value, context, inverse, body, blockParamsValueProvider);
     }
 }
        private static void LateBoundCall(
            string helperName,
            char helperPrefix,
            BindingContext bindingContext,
            IReaderContext readerContext,
            TextWriter output,
            HelperOptions options,
            Action <BindingContext, TextWriter, object> body,
            Action <BindingContext, TextWriter, object> inverse,
            dynamic context,
            BlockParamsValueProvider blockParamsValueProvider,
            params object[] arguments
            )
        {
            try
            {
                if (bindingContext.Configuration.BlockHelpers.TryGetValue(helperName, out var helper))
                {
                    helper(output, options, context, arguments);
                    return;
                }

                foreach (var resolver in bindingContext.Configuration.HelperResolvers)
                {
                    if (!resolver.TryResolveBlockHelper(helperName, out helper))
                    {
                        continue;
                    }

                    helper(output, options, context, arguments);

                    return;
                }

                var segment = ChainSegment.Create(helperName);
                bindingContext.TryGetContextVariable(ref segment, out var value);
                DeferredSectionBlockHelper.Helper(bindingContext, helperPrefix, value, body, inverse, blockParamsValueProvider);
            }
            catch (Exception e)
            {
                throw new HandlebarsRuntimeException($"Error occured while executing `{helperName}.`", e, readerContext);
            }
        }
Example #7
0
        public static void Iterate(BindingContext context,
                                   BlockParamsValueProvider blockParamsValueProvider,
                                   object target,
                                   Action <BindingContext, TextWriter, object> template,
                                   Action <BindingContext, TextWriter, object> ifEmpty)
        {
            if (!HandlebarsUtils.IsTruthy(target))
            {
                ifEmpty(context, context.TextWriter, context.Value);
                return;
            }

            var targetType = target.GetType();

            if (!(context.Configuration.ObjectDescriptorProvider.CanHandleType(targetType) &&
                  context.Configuration.ObjectDescriptorProvider.TryGetDescriptor(targetType, out var descriptor)))
            {
                ifEmpty(context, context.TextWriter, context.Value);
                return;
            }

            if (!descriptor.ShouldEnumerate)
            {
                var properties = descriptor.GetProperties(target);
                if (properties is IList propertiesList)
                {
                    IterateObjectWithStaticProperties(context, descriptor, blockParamsValueProvider, target, propertiesList, targetType, template, ifEmpty);
                    return;
                }

                IterateObject(context, descriptor, blockParamsValueProvider, target, properties, targetType, template, ifEmpty);
                return;
            }

            if (target is IList list)
            {
                IterateList(context, blockParamsValueProvider, list, template, ifEmpty);
                return;
            }

            IterateEnumerable(context, blockParamsValueProvider, (IEnumerable)target, template, ifEmpty);
        }
Example #8
0
        private static void IterateObject(BindingContext context,
                                          ObjectDescriptor descriptor,
                                          BlockParamsValueProvider blockParamsValueProvider,
                                          object target,
                                          IEnumerable <object> properties,
                                          Type targetType,
                                          Action <BindingContext, TextWriter, object> template,
                                          Action <BindingContext, TextWriter, object> ifEmpty)
        {
            using (var iterator = ObjectEnumeratorValueProvider.Create(context.Configuration))
            {
                blockParamsValueProvider?.Configure(BlockParamsObjectEnumeratorConfiguration, iterator);

                iterator.Index = 0;
                var  accessor   = descriptor.MemberAccessor;
                var  enumerable = new ExtendedEnumerable <object>(properties);
                bool enumerated = false;

                foreach (var enumerableValue in enumerable)
                {
                    enumerated   = true;
                    iterator.Key = enumerableValue.Value.ToString();
                    var key = iterator.Key.Intern();
                    iterator.Value = accessor.TryGetValue(target, targetType, key, out var value) ? value : null;
                    iterator.First = enumerableValue.IsFirst;
                    iterator.Last  = enumerableValue.IsLast;
                    iterator.Index = enumerableValue.Index;

                    using (var innerContext = context.CreateChildContext(iterator.Value))
                    {
                        innerContext.RegisterValueProvider(iterator);
                        template(context, context.TextWriter, innerContext);
                        innerContext.UnregisterValueProvider(iterator);
                    }
                }

                if (iterator.Index == 0 && !enumerated)
                {
                    ifEmpty(context, context.TextWriter, context.Value);
                }
            }
        }
Example #9
0
        private static void IterateObjectWithStaticProperties(BindingContext context,
                                                              ObjectDescriptor descriptor,
                                                              BlockParamsValueProvider blockParamsValueProvider,
                                                              object target,
                                                              IList properties,
                                                              Type targetType,
                                                              Action <BindingContext, TextWriter, object> template,
                                                              Action <BindingContext, TextWriter, object> ifEmpty)
        {
            using (var iterator = ObjectEnumeratorValueProvider.Create(context.Configuration))
            {
                blockParamsValueProvider?.Configure(BlockParamsObjectEnumeratorConfiguration, iterator);

                var accessor = descriptor.MemberAccessor;

                var count = properties.Count;
                for (iterator.Index = 0; iterator.Index < count; iterator.Index++)
                {
                    iterator.Key   = properties[iterator.Index].ToString();
                    iterator.Value = accessor.TryGetValue(target, targetType, iterator.Key, out var value) ? value : null;
                    iterator.First = iterator.Index == 0;
                    iterator.Last  = iterator.Index == count - 1;

                    using (var innerContext = context.CreateChildContext(iterator.Value))
                    {
                        innerContext.RegisterValueProvider(iterator);
                        template(context, context.TextWriter, innerContext);
                        innerContext.UnregisterValueProvider(iterator);
                    }
                }

                if (iterator.Index == 0)
                {
                    ifEmpty(context, context.TextWriter, context.Value);
                }
            }
        }
        protected override Expression VisitBlockHelperExpression(BlockHelperExpression bhex)
        {
            var isInlinePartial = bhex.HelperName == "#*inline";

            var context        = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var bindingContext = isInlinePartial
                ? context.Cast <object>()
                : context.Property(o => o.Value);

            var readerContext = ExpressionShortcuts.Arg(bhex.Context);
            var body          = FunctionBuilder.CompileCore(((BlockExpression)bhex.Body).Expressions, CompilationContext.Configuration);
            var inverse       = FunctionBuilder.CompileCore(((BlockExpression)bhex.Inversion).Expressions, CompilationContext.Configuration);
            var helperName    = bhex.HelperName.TrimStart('#', '^');
            var textWriter    = context.Property(o => o.TextWriter);
            var arguments     = ExpressionShortcuts.Array <object>(bhex.Arguments.Select(o => FunctionBuilder.Reduce(o, CompilationContext)));
            var configuration = ExpressionShortcuts.Arg(CompilationContext.Configuration);

            var reducerNew = ExpressionShortcuts.New(() => new LambdaReducer(context, body, inverse));
            var reducer    = ExpressionShortcuts.Var <LambdaReducer>();

            var blockParamsProvider   = ExpressionShortcuts.Var <BlockParamsValueProvider>();
            var blockParamsExpression = ExpressionShortcuts.Call(
                () => BlockParamsValueProvider.Create(context, ExpressionShortcuts.Arg <BlockParam>(bhex.BlockParams))
                );

            var helperOptions = ExpressionShortcuts.New(
                () => new HelperOptions(
                    reducer.Property(o => o.Direct),
                    reducer.Property(o => o.Inverse),
                    blockParamsProvider,
                    configuration)
                );

            var blockHelpers = CompilationContext.Configuration.BlockHelpers;

            if (blockHelpers.TryGetValue(helperName, out var helper))
            {
                return(ExpressionShortcuts.Block()
                       .Parameter(reducer, reducerNew)
                       .Parameter(blockParamsProvider, blockParamsExpression)
                       .Line(blockParamsProvider.Using((self, builder) =>
                {
                    builder
                    .Line(context.Call(o => o.RegisterValueProvider((IValueProvider)self)))
                    .Line(ExpressionShortcuts.Try()
                          .Body(ExpressionShortcuts.Call(
                                    () => helper(textWriter, helperOptions, bindingContext, arguments)
                                    ))
                          .Finally(context.Call(o => o.UnregisterValueProvider((IValueProvider)self)))
                          );
                })));
            }

            foreach (var resolver in CompilationContext.Configuration.HelperResolvers)
            {
                if (resolver.TryResolveBlockHelper(helperName, out helper))
                {
                    return(ExpressionShortcuts.Block()
                           .Parameter(reducer, reducerNew)
                           .Parameter(blockParamsProvider, blockParamsExpression)
                           .Line(blockParamsProvider.Using((self, builder) =>
                    {
                        builder
                        .Line(context.Call(o => o.RegisterValueProvider((IValueProvider)self)))
                        .Line(ExpressionShortcuts.Try()
                              .Body(ExpressionShortcuts.Call(
                                        () => helper(textWriter, helperOptions, bindingContext, arguments)
                                        ))
                              .Finally(context.Call(o => o.UnregisterValueProvider((IValueProvider)self)))
                              );
                    })));
                }
            }

            var helperPrefix = bhex.HelperName[0];

            return(ExpressionShortcuts.Block()
                   .Parameter(reducer, reducerNew)
                   .Parameter(blockParamsProvider, blockParamsExpression)
                   .Line(blockParamsProvider.Using((self, builder) =>
            {
                builder
                .Line(context.Call(o => o.RegisterValueProvider((IValueProvider)self)))
                .Line(ExpressionShortcuts.Try()
                      .Body(ExpressionShortcuts.Call(
                                () => LateBoundCall(
                                    helperName,
                                    helperPrefix,
                                    context,
                                    (IReaderContext)readerContext,
                                    textWriter, helperOptions,
                                    body,
                                    inverse,
                                    bindingContext,
                                    self,
                                    arguments
                                    )
                                ))
                      .Finally(context.Call(o => o.UnregisterValueProvider((IValueProvider)self)))
                      );
            })));
        }