Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
This is a PR showing the current progress on Liquid compilation support. It doesn't work but this needs to be saved to I salvaged it from my laptop before it's too late. I wrote this a year ago and I don't remember much of the details of the implementation, I will ty to write it down as I re-understand how everything works.
The idea is that currently Fluid parses a template to generate an AST (
IFluidTemplate). This AST is processed by evaluating all its statements and "writing" them on aTextWriterto render it. Many things have to be checked or computed every time the AST is evaluated, boolean expressions, math operations, for loops, ... It also has some overhead because of stack depths and extra method calls. Compilation helps with rendering performance as some conditions can be evaluated once at compiled time to generate the code that needs to be executed. It can also remove the need of reflection to access properties. Finally it allows to generate compiled templates statically if the template is known (strongly typed model) at the project compile time, even though we can still compile dynamically a random template.Part of this PR is the creation of a visitor pattern resembling the one in Roslyn (and Esprima-dotnet) that allows to alter the AST. This could be something that is extracted before the PR is finalized as it could be useful even today. This was done to be able to move the compilation code out of each AST element.
This PR contains a source code generator project that allows to create compiled templates statically. I don't remember if it works, it might since the code is there.
The remaining work consists of implementing the
Visitfor each AST node type in theAstCompilerclass. This means generating the source code that will render the template once compiled.Once the work is done, Fluid will be the fastest Liquid templates parser, will be able to interpret template quickly, detect syntax errors and optimizations (visitor) and compile templates for the fastest rendering experience possible (even compared to Razor).
How to work with this branch:
FluidTemplate.RenderAsyncis patched to support automatic compilation. There is a propertyTemplateOptions.TemplateCompilationThresholdthat will trigger the compilation automatically when a template is rendered more than that number of times. It's set to 1 such that templates are always compiled automatically on the first use. This way running the tests will run the compiled version always. I suggest trying theTemplateTestsclass, a nice test beingShouldNotEncodeBlocks. The generated code is overwriting%TEMP%\fluid.csevery time.How do use visitors to detect specific patterns in a template:
Check how
IdentifierIsAccessedVisitorcan visit eachMemberExpressionto detect if the first segment matches a specific identifier. If one does then this identifier is used somewhere in the template.Another example of such visitor is
ContinueOffsetVisitorwhich will tell if aForStatementhas a continue offset behavior.These visitors let us know if we can omit specific construct once and for all. In the case of
forloops knowing that theforloopproperty is not used anywhere allows the final compiled code to omit the creation and tracking of theforloopobject (Index,First,Last... properties).NB: this optimization could also be added to the interpreter when visitors are available.
TODO:
main. NB: It's not, but shouldn't be hard to get it back. We might want to extract some of the things directly tomaintoo, for instance visitors and the model changes (public types, public properties).sebros/member_refactorbranch which has the next commit I was working on is supposed to do. Probably found some issues with strongly typed member access.