Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation support #627

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft

Compilation support #627

wants to merge 12 commits into from

Conversation

sebastienros
Copy link
Owner

@sebastienros sebastienros commented Feb 16, 2024

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 a TextWriter to 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 Visit for each AST node type in the AstCompiler class. 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.RenderAsync is patched to support automatic compilation. There is a property TemplateOptions.TemplateCompilationThreshold that 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 the TemplateTests class, a nice test being ShouldNotEncodeBlocks. The generated code is overwriting %TEMP%\fluid.cs every time.

How do use visitors to detect specific patterns in a template:
Check how IdentifierIsAccessedVisitor can visit each MemberExpression to 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 ContinueOffsetVisitor which will tell if a ForStatement has a continue offset behavior.
These visitors let us know if we can omit specific construct once and for all. In the case of for loops knowing that the forloop property is not used anywhere allows the final compiled code to omit the creation and tracking of the forloop object (Index, First, Last ... properties).

NB: this optimization could also be added to the interpreter when visitors are available.

TODO:

  • Keep it compatible with main. NB: It's not, but shouldn't be hard to get it back. We might want to extract some of the things directly to main too, for instance visitors and the model changes (public types, public properties).
  • Support each AST node
  • Remember what the sebros/member_refactor branch which has the next commit I was working on is supposed to do. Probably found some issues with strongly typed member access.

@sebastienros
Copy link
Owner Author

@lahma I hope to get your attention, very challenging work

@lahma
Copy link
Collaborator

lahma commented Feb 17, 2024

Thanks for the heads up, a very interesting feature. I'm just afraid that I might have too much on my plate already...

@sebastienros
Copy link
Owner Author

The main branch has been updated to include the Visitor pattern from this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants