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

Eager expression node #548

Merged
merged 15 commits into from
Dec 9, 2020
Merged

Eager expression node #548

merged 15 commits into from
Dec 9, 2020

Conversation

jasmith-hs
Copy link
Contributor

@jasmith-hs jasmith-hs commented Nov 24, 2020

Part of #532

This PR adds in the functionality that is necessary to interpret an expression node when doing eager execution. The expression node needs to get treated similarly to a PrintTag, and it has nearly the same logic, save for the possibility for nested interpretation. Because of this, several static methods from the EagerTagDecorator are used to partially or fully evaluate the expression within the node.

It uses the chunk resolver in a child context to evaluate the expression in chunks. For more detail on how the chunk resolver works, see #525. If the interpretation is run in protectedMode, then if any values on the context are updated, a SetTag is pre-pended to the output to preserve the state of the context. In other words, performing the sort of speculative execution done when unsure which branch of an IfTag to execute, the values should be preserved on the context. Quick example:

{% set list = ['foo'] %}
{% if deferred %}
{{ list }}
{{ list.append('a') }}
{% else %}
{{ list }}
{{ list.append('b') }}
{% endif %}

When executing these expressions, since the value of list gets updated via append() and protectedMode would be true, then the desired output would be something like:

{% if deferred %}
['foo']
{% set list = ['foo'] %}{{ list.append('a') }}
{% else %}
['foo']
{% set list = ['foo'] %}{{ list.append('b') }}
{% endif %}

The IfTag functionality has not been PR'd yet, but it helps demonstrate the purpose of protectedMode. (Again, this functionality is similar to pre-pending a SetTag after interpreting certain tags as well.


Somewhat similar to the set tag pre-pending, if an expression node references a macro function which must be deferred such as {{ some_macro(deferred) }}, then the macro function's image must be pre-pended as well as described in #547.

We use chunkResolver.getDeferredWords().isEmpty() to determine if the expression was able to be completely evaluated. If there are any deferred words, then we know that the expression node must be "reconstructed", and the partially evaluated result gets wrapped in double curly braces. If there are no words, however, then the logic continues similarly to the DefaultExpressionStrategy, although we must keep in mind that the output may need to be wrapped in a raw tag if nested interpretation is disabled. Ex: {{ 'this is an expression' + '{{ foo }}' }} would need to be output as: {% raw %}this is an expression {{ foo }}{% endraw %} to prevent evaluation on a second rendering pass if the execution mode specifies isPreserveRawTags() == true.

cc @boulter @Joeoh @gobimcp feel free to bring up any questions or comments you may have about this alternate strategy for processing expression nodes (see #544 for how I added the strategy pattern into the expression node logic, allowing for different approaches to the logic for an ExpressionNode)

Base automatically changed from eager-tag-decorator-full to master November 30, 2020 19:50
@jasmith-hs jasmith-hs mentioned this pull request Nov 30, 2020
32 tasks
JinjavaInterpreter interpreter
) {
if (
interpreter.getConfig().getExecutionMode().isPreserveRawTags() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to a create a variable for interpreter.getConfig() to shorten up these lines.

@@ -0,0 +1,3 @@
{{ '{{ foo }}' }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd inline all of these test files for readability.

@jasmith-hs jasmith-hs merged commit a1d6b42 into master Dec 9, 2020
@jasmith-hs jasmith-hs deleted the eager-expression-node branch December 9, 2020 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants