public Compile ( IEnumerable |
||
expressions | IEnumerable |
|
templatePath | string | |
return | object>.Action |
private Expression GetEnumerableIterator(Expression contextParameter, IteratorExpression iex) { var fb = new FunctionBuilder(CompilationContext.Configuration); return(Expression.Block( Expression.Assign(contextParameter, Expression.New( #if netstandard typeof(IteratorBindingContext).GetTypeInfo().GetConstructor(new[] { typeof(BindingContext) }), #else typeof(IteratorBindingContext).GetConstructor(new[] { typeof(BindingContext) }), #endif new Expression[] { CompilationContext.BindingContext })), Expression.Call( #if netstandard new Action <IteratorBindingContext, IEnumerable, Action <TextWriter, object>, Action <TextWriter, object> >(Iterate).GetMethodInfo(), #else new Action <IteratorBindingContext, IEnumerable, Action <TextWriter, object>, Action <TextWriter, object> >(Iterate).Method, #endif new Expression[] { Expression.Convert(contextParameter, typeof(IteratorBindingContext)), Expression.Convert(iex.Sequence, typeof(IEnumerable)), fb.Compile(new [] { iex.Template }, contextParameter), fb.Compile(new [] { iex.IfEmpty }, CompilationContext.BindingContext) }))); }
protected override Expression VisitBlockHelperExpression(BlockHelperExpression bhex) { var fb = new FunctionBuilder(CompilationContext.Configuration); var body = fb.Compile(((BlockExpression)bhex.Body).Expressions, CompilationContext.BindingContext); var inversion = fb.Compile(((BlockExpression)bhex.Inversion).Expressions, CompilationContext.BindingContext); var helper = CompilationContext.Configuration.BlockHelpers[bhex.HelperName.Replace("#", "")]; var arguments = new Expression[] { Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("TextWriter")), Expression.New( typeof(HelperOptions).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0], body, inversion), Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("Value")), Expression.NewArrayInit(typeof(object), bhex.Arguments) }; if (helper.Target != null) { return(Expression.Call( Expression.Constant(helper.Target), helper.Method, arguments)); } else { return(Expression.Call( helper.Method, arguments)); } }
protected override Expression VisitBlockHelperExpression(BlockHelperExpression bhex) { var fb = new FunctionBuilder(CompilationContext.Configuration); var body = fb.Compile(((BlockExpression)bhex.Body).Expressions, CompilationContext.BindingContext); var inversion = fb.Compile(((BlockExpression)bhex.Inversion).Expressions, CompilationContext.BindingContext); var helper = CompilationContext.Configuration.BlockHelpers[bhex.HelperName.Replace("#", "")]; var arguments = new Expression[] { Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("TextWriter")), Expression.New( typeof(HelperOptions).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0], body, inversion), Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("Value")), Expression.NewArrayInit(typeof(object), bhex.Arguments) }; if (helper.Target != null) { return Expression.Call( Expression.Constant(helper.Target), helper.Method, arguments); } else { return Expression.Call( helper.Method, arguments); } }
protected override Expression VisitBlockHelperExpression(BlockHelperExpression bhex) { var isInlinePartial = bhex.HelperName == "#*inline"; var fb = new FunctionBuilder(CompilationContext.Configuration); var bindingContext = isInlinePartial ? (Expression)CompilationContext.BindingContext : Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("Value")); var body = fb.Compile(((BlockExpression)bhex.Body).Expressions, CompilationContext.BindingContext); var inversion = fb.Compile(((BlockExpression)bhex.Inversion).Expressions, CompilationContext.BindingContext); var helper = CompilationContext.Configuration.BlockHelpers[bhex.HelperName.Replace("#", "")]; var arguments = new Expression[] { Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("TextWriter")), Expression.Property( CompilationContext.BindingContext, typeof(BindingContext).GetProperty("Root")), Expression.New( typeof(HelperOptions).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0], body, inversion), //this next arg is usually data, like { first: "Marc" } //but for inline partials this is the complete BindingContext. bindingContext, Expression.NewArrayInit(typeof(object), bhex.Arguments) }; if (helper.Target != null) { return(Expression.Call( Expression.Constant(helper.Target), #if netstandard helper.GetMethodInfo(), #else helper.Method, #endif arguments)); } else { return(Expression.Call( #if netstandard helper.GetMethodInfo(), #else helper.Method, #endif arguments)); } }
protected override Expression VisitPartialExpression(PartialExpression pex) { Expression bindingContext = CompilationContext.BindingContext; var fb = new FunctionBuilder(CompilationContext.Configuration); var partialBlockTemplate = pex.Fallback == null ? null : fb.Compile(new[] { pex.Fallback }, null, null); if (pex.Argument != null || partialBlockTemplate != null) { bindingContext = Expression.Call( bindingContext, typeof(BindingContext).GetMethod("CreateChildContext"), pex.Argument ?? Expression.Constant(null), partialBlockTemplate ?? Expression.Constant(null, typeof(Action <TextWriter, object>))); } var partialInvocation = Expression.Call( #if netstandard new Action <string, BindingContext, HandlebarsConfiguration>(InvokePartialWithFallback).GetMethodInfo(), #else new Action <string, BindingContext, HandlebarsConfiguration>(InvokePartialWithFallback).Method, #endif Expression.Convert(pex.PartialName, typeof(string)), bindingContext, Expression.Constant(CompilationContext.Configuration)); return(partialInvocation); }
public Action <TextWriter, object> Compile(TextReader source) { var tokens = _tokenizer.Tokenize(source).ToList(); var expressions = _expressionBuilder.ConvertTokensToExpressions(tokens); return(_functionBuilder.Compile(expressions)); }
protected override Expression VisitIteratorExpression(IteratorExpression iex) { var context = CompilationContext.Args.BindingContext; var writer = CompilationContext.Args.EncodedWriter; var template = FunctionBuilder.Compile(new[] { iex.Template }, CompilationContext.Configuration); var ifEmpty = FunctionBuilder.Compile(new[] { iex.IfEmpty }, CompilationContext.Configuration); if (iex.Sequence is PathExpression pathExpression) { pathExpression.Context = PathExpression.ResolutionContext.Parameter; } var compiledSequence = Arg <object>(FunctionBuilder.Reduce(iex.Sequence, CompilationContext)); var blockParamsValues = CreateBlockParams(); return(Call(() => Iterator.Iterate(context, writer, blockParamsValues, compiledSequence, template, ifEmpty) )); ExpressionContainer <ChainSegment[]> CreateBlockParams() { var parameters = iex.BlockParams?.BlockParam?.Parameters; if (parameters == null) { parameters = ArrayEx.Empty <ChainSegment>(); } return(Arg(parameters)); } }
protected override Expression VisitPartialExpression(PartialExpression pex) { var bindingContext = CompilationContext.Args.BindingContext; var writer = CompilationContext.Args.EncodedWriter; var partialBlockTemplate = pex.Fallback != null ? FunctionBuilder.Compile(new[] { pex.Fallback }, new CompilationContext(CompilationContext)) : null; if (pex.Argument != null || partialBlockTemplate != null) { var value = pex.Argument != null ? Arg<object>(FunctionBuilder.Reduce(pex.Argument, CompilationContext)) : bindingContext.Property(o => o.Value); var partialTemplate = Arg(partialBlockTemplate); bindingContext = bindingContext.Call(o => o.CreateChildContext(value, partialTemplate)); } var partialName = Cast<string>(pex.PartialName); var configuration = Arg(CompilationContext.Configuration); return Call(() => InvokePartialWithFallback(partialName, bindingContext, writer, (ICompiledHandlebarsConfiguration) configuration) ); }
internal Action <TextWriter, object> CompileView(string templatePath, InternalHandlebarsConfiguration configuration) { var fs = _configuration.FileSystem; if (fs == null) { throw new InvalidOperationException("Cannot compile view when configuration.FileSystem is not set"); } var template = fs.GetFileContent(templatePath); if (template == null) { throw new InvalidOperationException("Cannot find template at '" + templatePath + "'"); } IEnumerable <object> tokens; using (var sr = new StringReader(template)) { using (var reader = new ExtendedStringReader(sr)) { tokens = Tokenizer.Tokenize(reader).ToList(); } } var layoutToken = tokens.OfType <LayoutToken>().SingleOrDefault(); var expressionBuilder = new ExpressionBuilder(configuration); var expressions = expressionBuilder.ConvertTokensToExpressions(tokens); var compiledView = FunctionBuilder.Compile(expressions, configuration, templatePath); if (layoutToken == null) { return(compiledView); } var layoutPath = fs.Closest(templatePath, layoutToken.Value + ".hbs"); if (layoutPath == null) { throw new InvalidOperationException("Cannot find layout '" + layoutPath + "' for template '" + templatePath + "'"); } var compiledLayout = CompileView(layoutPath, configuration); return((tw, vm) => { string inner; using (var innerWriter = new PolledStringWriter(configuration.FormatProvider)) { compiledView(innerWriter, vm); inner = innerWriter.ToString(); } compiledLayout(tw, new DynamicViewModel(new[] { new { body = inner }, vm })); }); }
private Expression GetEnumerableIterator(Expression contextParameter, IteratorExpression iex) { var fb = new FunctionBuilder(CompilationContext.Configuration); return Expression.Block( Expression.Assign(contextParameter, Expression.New( typeof(IteratorBindingContext).GetConstructor(new[] { typeof(BindingContext) }), new Expression[] { CompilationContext.BindingContext })), Expression.Call( new Action<IteratorBindingContext, IEnumerable, Action<TextWriter, object>, Action<TextWriter, object>>(Iterate).Method, new Expression[] { Expression.Convert(contextParameter, typeof(IteratorBindingContext)), Expression.Convert(iex.Sequence, typeof(IEnumerable)), fb.Compile(new [] { iex.Template }, contextParameter), fb.Compile(new [] { iex.IfEmpty }, CompilationContext.BindingContext) })); }
private Expression[] GetDeferredSectionTemplates(DeferredSectionExpression dsex) { var fb = new FunctionBuilder(CompilationContext.Configuration); var body = fb.Compile(dsex.Body.Expressions, CompilationContext.BindingContext); var inversion = fb.Compile(dsex.Inversion.Expressions, CompilationContext.BindingContext); var sectionPrefix = dsex.Path.Path.Substring(0, 1); switch (sectionPrefix) { case "#": return new[] {body, inversion}; case "^": return new[] {inversion, body}; default: throw new HandlebarsCompilerException("Tried to compile a section expression that did not begin with # or ^"); } }
private Expression GetObjectIterator(Expression contextParameter, IteratorExpression iex) { var fb = new FunctionBuilder(CompilationContext.Configuration); return(Expression.Block( Expression.Assign(contextParameter, Expression.New( typeof(ObjectEnumeratorBindingContext).GetConstructor(new[] { typeof(BindingContext) }), new Expression[] { CompilationContext.BindingContext })), Expression.Call( new Action <ObjectEnumeratorBindingContext, object, Action <TextWriter, object>, Action <TextWriter, object> >(Iterate).Method, new Expression[] { Expression.Convert(contextParameter, typeof(ObjectEnumeratorBindingContext)), iex.Sequence, fb.Compile(new [] { iex.Template }, contextParameter), fb.Compile(new [] { iex.IfEmpty }, CompilationContext.BindingContext) }))); }
private Expression[] GetDeferredSectionTemplates(DeferredSectionExpression dsex) { var fb = new FunctionBuilder(CompilationContext.Configuration); var body = fb.Compile(dsex.Body.Expressions, CompilationContext.BindingContext); var inversion = fb.Compile(dsex.Inversion.Expressions, CompilationContext.BindingContext); var sectionPrefix = dsex.Path.Path.Substring(0, 1); switch (sectionPrefix) { case "#": return(new[] { body, inversion }); case "^": return(new[] { inversion, body }); default: throw new HandlebarsCompilerException("Tried to compile a section expression that did not begin with # or ^"); } }
protected override Expression VisitPartialExpression(PartialExpression pex) { Expression bindingContext = CompilationContext.BindingContext; if (pex.Argument != null) { bindingContext = Expression.Call( bindingContext, typeof(BindingContext).GetMethod("CreateChildContext"), pex.Argument); } var fb = new FunctionBuilder(CompilationContext.Configuration); var partialBlockTemplate = fb.Compile(pex.Fallback != null ? new[] { pex.Fallback } : Enumerable.Empty <Expression>(), bindingContext); var partialInvocation = Expression.Call( #if netstandard new Func <string, BindingContext, HandlebarsConfiguration, Action <TextWriter, object>, bool>(InvokePartial).GetMethodInfo(), #else new Func <string, BindingContext, HandlebarsConfiguration, Action <TextWriter, object>, bool>(InvokePartial).Method, #endif Expression.Convert(pex.PartialName, typeof(string)), bindingContext, Expression.Constant(CompilationContext.Configuration), partialBlockTemplate); var fallback = pex.Fallback; if (fallback == null) { fallback = Expression.Call( #if netstandard new Action <string>(HandleFailedInvocation).GetMethodInfo(), #else new Action <string>(HandleFailedInvocation).Method, #endif Expression.Convert(pex.PartialName, typeof(string))); } return(Expression.IfThen( Expression.Not(partialInvocation), fallback)); }
public static Action <TextWriter, object> Compile(ExtendedStringReader source, ICompiledHandlebarsConfiguration configuration) { var createdFeatures = configuration.Features; for (var index = 0; index < createdFeatures.Count; index++) { createdFeatures[index].OnCompiling(configuration); } var expressionBuilder = new ExpressionBuilder(configuration); var tokens = Tokenizer.Tokenize(source).ToList(); var expressions = expressionBuilder.ConvertTokensToExpressions(tokens); var action = FunctionBuilder.Compile(expressions, configuration); for (var index = 0; index < createdFeatures.Count; index++) { createdFeatures[index].CompilationCompleted(); } return(action); }
protected override Expression VisitIteratorExpression(IteratorExpression iex) { var context = CompilationContext.Args.BindingContext; var writer = CompilationContext.Args.EncodedWriter; var template = FunctionBuilder.Compile(new[] { iex.Template }, new CompilationContext(CompilationContext)); var ifEmpty = FunctionBuilder.Compile(new[] { iex.IfEmpty }, new CompilationContext(CompilationContext)); if (iex.Sequence is PathExpression pathExpression) { pathExpression.Context = PathExpression.ResolutionContext.Parameter; } var compiledSequence = Arg <object>(FunctionBuilder.Reduce(iex.Sequence, CompilationContext)); var blockParamsValues = CreateBlockParams(); return(iex.HelperName[0] switch { '#' => Call(() => Iterator.Iterate(context, writer, blockParamsValues, compiledSequence, template, ifEmpty)), '^' => Call(() => Iterator.Iterate(context, writer, blockParamsValues, compiledSequence, ifEmpty, template)), _ => throw new HandlebarsCompilerException($"Tried to convert {iex.HelperName} expression to iterator block", iex.Context) });
private Expression GetDynamicIterator(Expression contextParameter, IteratorExpression iex) { var fb = new FunctionBuilder(CompilationContext.Configuration); return Expression.Block( Expression.Assign(contextParameter, Expression.New( #if netstandard typeof(ObjectEnumeratorBindingContext).GetTypeInfo().GetConstructor(new[] { typeof(BindingContext) }), #else typeof(ObjectEnumeratorBindingContext).GetConstructor(new[] { typeof(BindingContext) }), #endif new Expression[] { CompilationContext.BindingContext })), Expression.Call( #if netstandard new Action<ObjectEnumeratorBindingContext, IDynamicMetaObjectProvider, Action<TextWriter, object>, Action<TextWriter, object>>(Iterate).GetMethodInfo(), #else new Action<ObjectEnumeratorBindingContext, IDynamicMetaObjectProvider, Action<TextWriter, object>, Action<TextWriter, object>>(Iterate).Method, #endif new Expression[] { Expression.Convert(contextParameter, typeof(ObjectEnumeratorBindingContext)), Expression.Convert(iex.Sequence, typeof(IDynamicMetaObjectProvider)), fb.Compile(new [] { iex.Template }, contextParameter), fb.Compile(new [] { iex.IfEmpty }, CompilationContext.BindingContext) })); }
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))); } } }