protected override Expression VisitStaticExpression(StaticExpression stex)
        {
            var context = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var value   = ExpressionShortcuts.Arg(stex.Value);

            return(context.Call(o => o.TextWriter.Write(value, false)));
        }
        public T Compile <T>(Expression <T> expression) where T : class
        {
            expression = (Expression <T>)_expressionMiddleware.Aggregate((Expression)expression, (e, m) => m.Invoke(e));

            if (_closureFeature == null)
            {
                return(expression.CompileFast());
            }

            expression = (Expression <T>)_closureFeature.ExpressionMiddleware.Invoke(expression);

            var parameters = new[] { _closure }.Concat(expression.Parameters).ToArray();
            var lambda               = Expression.Lambda(expression.Body, parameters);
            var compiledDelegateType = Expression.GetDelegateType(parameters.Select(o => o.Type).Concat(new[] { lambda.ReturnType }).ToArray());

            var method = typeof(FastExpressionCompiler)
                         .GetMethod(nameof(CompileGeneric), BindingFlags.Static | BindingFlags.NonPublic)
                         ?.MakeGenericMethod(compiledDelegateType);

            var compiledLambda = method?.Invoke(null, new object[] { lambda }) ?? throw new InvalidOperationException("lambda cannot be compiled");

            var outerParameters = expression.Parameters.Select(o => Expression.Parameter(o.Type, o.Name)).ToArray();

            var store       = ExpressionShortcuts.Arg(_templateClosure).Property(o => o.Store);
            var outerLambda = Expression.Lambda <T>(
                Expression.Invoke(Expression.Constant(compiledLambda), new[] { store.Expression }.Concat(outerParameters)),
                outerParameters);

            return(outerLambda.CompileFast());
        }
示例#3
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)))
                      );
            })));
        }
示例#4
0
        protected override Expression VisitPathExpression(PathExpression pex)
        {
            var context  = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var pathInfo = pex.PathInfo;

            return(ExpressionShortcuts.Call(() => PathResolver.ResolvePath(context, ref pathInfo)));
        }
示例#5
0
        private Expression HandleInvocationExpression(InvocationExpression invocation)
        {
            if (invocation.Type != typeof(void))
            {
                return(invocation.Update(invocation.Expression,
                                         ReplaceValuesOf <TextWriter>(invocation.Arguments, ExpressionShortcuts.Null <TextWriter>()).Select(Visit)
                                         ));
            }

            var context = ExpressionShortcuts.Var <BindingContext>();
            var writer  = ExpressionShortcuts.Var <TextWriter>();

            invocation = invocation.Update(ExpressionUtils.ReplaceParameters(invocation.Expression, context),
                                           ExpressionUtils.ReplaceParameters(
                                               ReplaceValuesOf <TextWriter>(invocation.Arguments, writer), new Expression[] { context }
                                               ).Select(Visit)
                                           );

            var formatProvider = ExpressionShortcuts.Arg(CompilationContext.Configuration.FormatProvider);
            var block          = ExpressionShortcuts.Block()
                                 .Parameter(writer, ExpressionShortcuts.New(() => new PolledStringWriter((IFormatProvider)formatProvider)))
                                 .Line(writer.Using((o, body) =>
                                                    body.Line(invocation)
                                                    .Line(o.Call(x => (object)x.ToString()))
                                                    ));

            var continuation = _expressionCompiler.Compile(Expression.Lambda <Func <BindingContext, object> >(block, (ParameterExpression)context));

            return(ExpressionShortcuts.Arg <object>(Expression.Invoke(Expression.Constant(continuation), CompilationContext.BindingContext)));
        }
        protected override Expression VisitBoolishExpression(BoolishExpression bex)
        {
            var condition = Visit(bex.Condition);

            condition = FunctionBuilder.Reduce(condition, _compilationContext);
            var @object = ExpressionShortcuts.Arg <object>(condition);

            return(ExpressionShortcuts.Call(() => HandlebarsUtils.IsTruthyOrNonEmpty(@object)));
        }
示例#7
0
        protected override Expression VisitStatementExpression(StatementExpression sex)
        {
            if (!(sex.Body is PathExpression))
            {
                return(Visit(sex.Body));
            }

            var context = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var value   = ExpressionShortcuts.Arg <object>(Visit(sex.Body));

            return(context.Call(o => o.TextWriter.Write(value)));
        }
        protected override Expression VisitStatementExpression(StatementExpression sex)
        {
            var context          = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var suppressEncoding = context.Property(o => o.SuppressEncoding);

            if (!sex.IsEscaped)
            {
                return(ExpressionShortcuts.Block(typeof(void))
                       .Line(suppressEncoding.Assign(true))
                       .Line(sex)
                       .Line(suppressEncoding.Assign(false))
                       .Line(Expression.Empty()));
            }

            return(sex);
        }
示例#9
0
        public static Expression <Action <BindingContext, TextWriter, object> > Bind(CompilationContext context, Expression body, string templatePath)
        {
            var configuration = ExpressionShortcuts.Arg(context.Configuration);

            var writerParameter = ExpressionShortcuts.Parameter <TextWriter>("buffer");
            var objectParameter = ExpressionShortcuts.Parameter <object>("data");

            var bindingContext          = ExpressionShortcuts.Arg <BindingContext>(context.BindingContext);
            var inlinePartialsParameter = ExpressionShortcuts.Null <IDictionary <string, Action <TextWriter, object> > >();
            var textEncoder             = configuration.Property(o => o.TextEncoder);
            var encodedWriterExpression = ExpressionShortcuts.Call(() => EncodedTextWriter.From(writerParameter, (ITextEncoder)textEncoder));
            var parentContextArg        = ExpressionShortcuts.Var <BindingContext>("parentContext");

            var newBindingContext = ExpressionShortcuts.Call(
                () => BindingContext.Create(configuration, objectParameter, encodedWriterExpression, parentContextArg, templatePath, (IDictionary <string, Action <TextWriter, object> >)inlinePartialsParameter)
                );

            var shouldDispose = ExpressionShortcuts.Var <bool>("shouldDispose");

            Expression blockBuilder = ExpressionShortcuts.Block()
                                      .Parameter(bindingContext)
                                      .Parameter(shouldDispose)
                                      .Line(ExpressionShortcuts.Condition()
                                            .If(objectParameter.Is <BindingContext>(),
                                                bindingContext.Assign(objectParameter.As <BindingContext>())
                                                )
                                            .Else(block =>
            {
                block.Line(shouldDispose.Assign(true));
                block.Line(bindingContext.Assign(newBindingContext));
            })
                                            )
                                      .Line(ExpressionShortcuts.Try()
                                            .Body(block => block.Lines(((BlockExpression)body).Expressions))
                                            .Finally(ExpressionShortcuts.Condition()
                                                     .If(shouldDispose, bindingContext.Call(o => o.Dispose()))
                                                     )
                                            );

            return(Expression.Lambda <Action <BindingContext, TextWriter, object> >(blockBuilder, (ParameterExpression)parentContextArg.Expression, (ParameterExpression)writerParameter.Expression, (ParameterExpression)objectParameter.Expression));
        }
示例#10
0
        protected override Expression VisitPartialExpression(PartialExpression pex)
        {
            var bindingContext       = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var partialBlockTemplate = pex.Fallback != null
                ? FunctionBuilder.CompileCore(new[] { pex.Fallback }, CompilationContext.Configuration)
                : null;

            if (pex.Argument != null || partialBlockTemplate != null)
            {
                var value           = ExpressionShortcuts.Arg <object>(FunctionBuilder.Reduce(pex.Argument, CompilationContext));
                var partialTemplate = ExpressionShortcuts.Arg(partialBlockTemplate);
                bindingContext = bindingContext.Call(o => o.CreateChildContext(value, partialTemplate));
            }

            var partialName   = ExpressionShortcuts.Cast <string>(pex.PartialName);
            var configuration = ExpressionShortcuts.Arg(CompilationContext.Configuration);

            return(ExpressionShortcuts.Call(() =>
                                            InvokePartialWithFallback(partialName, bindingContext, (ICompiledHandlebarsConfiguration)configuration)
                                            ));
        }
        protected override Expression VisitHelperExpression(HelperExpression hex)
        {
            var helperName     = hex.HelperName;
            var bindingContext = ExpressionShortcuts.Arg <BindingContext>(CompilationContext.BindingContext);
            var textWriter     = bindingContext.Property(o => o.TextWriter);
            var arguments      = hex.Arguments.Select(o => FunctionBuilder.Reduce(o, CompilationContext));
            var args           = ExpressionShortcuts.Array <object>(arguments);

            var configuration = CompilationContext.Configuration;

            if (configuration.Helpers.TryGetValue(helperName, out var helper))
            {
                return(ExpressionShortcuts.Call(() => helper(textWriter, bindingContext, args)));
            }

            if (configuration.ReturnHelpers.TryGetValue(helperName, out var returnHelper))
            {
                return(ExpressionShortcuts.Call(() =>
                                                CaptureResult(textWriter, ExpressionShortcuts.Call(() => returnHelper(bindingContext, args)))
                                                ));
            }

            var pureHelperName = helperName.Substring(1);

            foreach (var resolver in configuration.HelperResolvers)
            {
                if (resolver.TryResolveReturnHelper(pureHelperName, typeof(object), out var resolvedHelper))
                {
                    return(ExpressionShortcuts.Call(() =>
                                                    CaptureResult(textWriter, ExpressionShortcuts.Call(() => resolvedHelper(bindingContext, args)))
                                                    ));
                }
            }

            return(ExpressionShortcuts.Call(() =>
                                            CaptureResult(textWriter, ExpressionShortcuts.Call(() =>
                                                                                               LateBindHelperExpression(bindingContext, helperName, args)
                                                                                               ))
                                            ));
        }
示例#12
0
        public void FuncCallTest()
        {
            Func <IMock, string> func = m => m.MethodWithReturn();

            var expected = _faker.Random.String();

            _mock.MethodWithReturn().Returns(expected);
            var mock   = ExpressionShortcuts.Arg(_mock);
            var data   = ExpressionShortcuts.Var <IMock>();
            var action = ExpressionShortcuts.Block()
                         .Parameter(data, mock)
                         .Line(ExpressionShortcuts.Call(() => func((IMock)data)))
                         .Lambda <Func <string> >()
                         .Compile();

            _mock.DidNotReceive().MethodWithReturn();

            var actual = action();

            Assert.Equal(expected, actual);

            _mock.Received(1).MethodWithReturn();
        }
            public T Compile <T>(Expression <T> expression) where T : class
            {
                expression = (Expression <T>)_expressionMiddleware.Aggregate((Expression)expression, (e, m) => m.Invoke(e));

                if (_closureFeature == null)
                {
                    return(expression.Compile());
                }

                expression = (Expression <T>)_closureFeature.ExpressionMiddleware.Invoke(expression);

                var parameters = new[] { (ParameterExpression)_closure }.Concat(expression.Parameters);
                var lambda         = Expression.Lambda(expression.Body, parameters);
                var compiledLambda = lambda.Compile();

                var outerParameters = expression.Parameters.Select(o => Expression.Parameter(o.Type, o.Name)).ToArray();

                var store       = ExpressionShortcuts.Arg(_templateClosure).Property(o => o.Store);
                var outerLambda = Expression.Lambda <T>(
                    Expression.Invoke(Expression.Constant(compiledLambda), new[] { store.Expression }.Concat(outerParameters)),
                    outerParameters);

                return(outerLambda.Compile());
            }
        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)))
                      );
            })));
        }