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; } }
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); } } }
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); } }
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); }
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); } } }
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))) ); }))); }