use of com.google.template.soy.jbcsrc.restricted.FieldRef in project closure-templates by google.
the class SoyNodeCompiler method renderCallNode.
/**
* Renders a {@link com.google.template.soy.jbcsrc.shared.CompiledTemplate} incrementally.
*
* <p>Similar to {@link #renderIncrementally(Expression, List, Label)}, we need to:
*
* <ul>
* <li>Stash the CompiledTemplate in a field {@code $currentCallee}, so that if we detach
* halfway through rendering we don't lose the value. Note, we could use the scope/variable
* system of {@link TemplateVariableManager} to manage this value, but we know there will
* only ever be 1 live at a time, so we can just manage the single special field ourselves.
* <li>Either apply all the streaming autoescapers to the current appendable and, stash it in
* the {@code $currentAppendable} field for the same reasons as above, or call {@link
* JbcSrcRuntime#applyEscapers} to apply non-streaming print directives.
* <li>Invoke {@link com.google.template.soy.jbcsrc.shared.CompiledTemplate#render} with the
* standard detach logic.
* <li>Clear the two fields once rendering is complete.
* </ul>
*
* @param parametersReattachPoint The label where execution should resume if we need to detach
* while calculating parameters.
* @param node The call node
* @param calleeExpression The expression that resolves to a constructed instance of the template
* @return A statement rendering the template.
*/
private Statement renderCallNode(Label parametersReattachPoint, CallNode node, Expression calleeExpression) {
Statement initAppendable = Statement.NULL_STATEMENT;
Statement clearAppendable = Statement.NULL_STATEMENT;
Expression appendable;
FieldRef currentCalleeField = variables.getCurrentCalleeField();
// CallDelegateNodes because there is no guarantee that we can tell what the kind is.
if (!areAllPrintDirectivesStreamable(node)) {
calleeExpression = MethodRef.RUNTIME_APPLY_ESCAPERS.invoke(calleeExpression, getEscapingDirectivesList(node));
appendable = appendableExpression;
} else {
AppendableAndOptions wrappedAppendable = applyStreamingEscapingDirectives(node.getEscapingDirectives(), appendableExpression, parameterLookup.getRenderContext(), variables);
FieldRef currentAppendableField = variables.getCurrentAppendable();
initAppendable = currentAppendableField.putInstanceField(thisVar, wrappedAppendable.appendable());
appendable = currentAppendableField.accessor(thisVar);
clearAppendable = currentAppendableField.putInstanceField(thisVar, constantNull(LOGGING_ADVISING_APPENDABLE_TYPE));
if (wrappedAppendable.closeable()) {
// make sure to call close before clearing
clearAppendable = Statement.concat(// LoggingAdvisingAppendable
currentAppendableField.accessor(thisVar).checkedCast(BytecodeUtils.CLOSEABLE_TYPE).invokeVoid(MethodRef.CLOSEABLE_CLOSE), clearAppendable);
}
}
Statement initCallee = currentCalleeField.putInstanceField(thisVar, calleeExpression).labelStart(parametersReattachPoint);
Expression callRender = currentCalleeField.accessor(thisVar).invoke(MethodRef.COMPILED_TEMPLATE_RENDER, appendable, parameterLookup.getRenderContext());
Statement callCallee = detachState.detachForRender(callRender);
Statement clearCallee = currentCalleeField.putInstanceField(thisVar, BytecodeUtils.constantNull(COMPILED_TEMPLATE_TYPE));
return Statement.concat(initAppendable, initCallee, callCallee, clearCallee, clearAppendable);
}
use of com.google.template.soy.jbcsrc.restricted.FieldRef in project closure-templates by google.
the class SoyNodeCompiler method renderIncrementally.
/**
* Renders a {@link SoyValueProvider} incrementally via {@link SoyValueProvider#renderAndResolve}
*
* <p>The strategy is to:
*
* <ul>
* <li>Stash the SoyValueProvider in a field {@code $currentRenderee}, so that if we detach
* halfway through rendering we don't lose the value. Note, we could use the scope/variable
* system of {@link TemplateVariableManager} to manage this value, but we know there will
* only ever be 1 live at a time, so we can just manage the single special field ourselves.
* <li>Apply all the streaming autoescapers to the current appendable. Also, stash it in the
* {@code $currentAppendable} field for the same reasons as above.
* <li>Invoke {@link SoyValueProvider#renderAndResolve} with the standard detach logic.
* <li>Clear the two fields once rendering is complete.
* </ul>
*
* <p>TODO(lukes): if the expression is a param, then this is kind of silly since it looks like
*
* <pre>{@code
* SoyValueProvider localParam = this.param;
* this.currentRenderee = localParam;
* SoyValueProvider localRenderee = this.currentRenderee;
* localRenderee.renderAndResolve();
* }</pre>
*
* <p>In this case we could elide the currentRenderee altogether if we knew the soyValueProvider
* expression was just a field read... And this is the _common_case for .renderAndResolve calls.
* to actually do this we could add a mechanism similar to the SaveStrategy enum for expressions,
* kind of like {@link Expression#isCheap()} which isn't that useful in practice.
*
* @param soyValueProvider The value to render incrementally
* @param directives The streaming print directives applied to the expression
* @param reattachPoint The point where execution should resume if the soyValueProvider detaches
* while being evaluated.
* @return a statement for the full render.
*/
private Statement renderIncrementally(Expression soyValueProvider, List<PrintDirectiveNode> directives, Label reattachPoint) {
// In this case we want to render the SoyValueProvider via renderAndResolve which will
// enable incremental rendering of parameters for lazy transclusions!
// This actually ends up looking a lot like how calls work so we use the same strategy.
FieldRef currentRendereeField = variables.getCurrentRenderee();
Statement initRenderee = currentRendereeField.putInstanceField(thisVar, soyValueProvider).labelStart(reattachPoint);
Statement clearRenderee = currentRendereeField.putInstanceField(thisVar, constantNull(SOY_VALUE_PROVIDER_TYPE));
// TODO(lukes): we should have similar logic for calls and message escaping
Statement initAppendable = Statement.NULL_STATEMENT;
Statement clearAppendable = Statement.NULL_STATEMENT;
Expression appendable = appendableExpression;
if (!directives.isEmpty()) {
Label printDirectiveArgumentReattachPoint = new Label();
AppendableAndOptions wrappedAppendable = applyStreamingPrintDirectives(directives, appendable, exprCompiler.asBasicCompiler(printDirectiveArgumentReattachPoint), parameterLookup.getRenderContext(), variables);
FieldRef currentAppendableField = variables.getCurrentAppendable();
initAppendable = currentAppendableField.putInstanceField(thisVar, wrappedAppendable.appendable()).labelStart(printDirectiveArgumentReattachPoint);
appendable = currentAppendableField.accessor(thisVar);
clearAppendable = currentAppendableField.putInstanceField(thisVar, constantNull(LOGGING_ADVISING_APPENDABLE_TYPE));
if (wrappedAppendable.closeable()) {
// make sure to call close before clearing
clearAppendable = Statement.concat(// LoggingAdvisingAppendable
currentAppendableField.accessor(thisVar).checkedCast(BytecodeUtils.CLOSEABLE_TYPE).invokeVoid(MethodRef.CLOSEABLE_CLOSE), clearAppendable);
}
}
Expression callRenderAndResolve = currentRendereeField.accessor(thisVar).invoke(MethodRef.SOY_VALUE_PROVIDER_RENDER_AND_RESOLVE, appendable, // TODO(lukes): pass a real value here when we have expression use analysis.
constant(false));
Statement doCall = detachState.detachForRender(callRenderAndResolve);
return Statement.concat(initRenderee, initAppendable, doCall, clearAppendable, clearRenderee);
}
use of com.google.template.soy.jbcsrc.restricted.FieldRef in project closure-templates by google.
the class TemplateVariableManager method addStaticField.
@Override
public FieldRef addStaticField(String proposedName, Expression initializer) {
String name = fieldNames.generateName(proposedName);
FieldRef ref = FieldRef.create(owner, name, initializer.resultType(), Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE, !initializer.isNonNullable());
staticFields.add(new AutoValue_TemplateVariableManager_StaticFieldVariable(ref, initializer));
return ref;
}
use of com.google.template.soy.jbcsrc.restricted.FieldRef in project closure-templates by google.
the class TemplateCompiler method compile.
/**
* Returns the list of classes needed to implement this template.
*
* <p>For each template, we generate:
*
* <ul>
* <li>A {@link com.google.template.soy.jbcsrc.shared.CompiledTemplate.Factory}
* <li>A {@link CompiledTemplate}
* <li>A DetachableSoyValueProvider subclass for each {@link LetValueNode} and {@link
* CallParamValueNode}
* <li>A DetachableContentProvider subclass for each {@link LetContentNode} and {@link
* CallParamContentNode}
* <p>Note: This will <em>not</em> generate classes for other templates, only the template
* configured in the constructor. But it will generate classes that <em>reference</em> the
* classes that are generated for other templates. It is the callers responsibility to
* ensure that all referenced templates are generated and available in the classloader that
* ultimately loads the returned classes.
*/
Iterable<ClassData> compile() {
List<ClassData> classes = new ArrayList<>();
// first generate the factory
if (template.node().getVisibility() != Visibility.PRIVATE) {
// Don't generate factory if the template is private. The factories are only
// useful to instantiate templates for calls from java. Soy->Soy calls should invoke
// constructors directly.
new TemplateFactoryCompiler(template, innerClasses).compile();
}
writer = SoyClassWriter.builder(template.typeInfo()).setAccess(Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER + Opcodes.ACC_FINAL).implementing(TEMPLATE_TYPE).sourceFileName(template.node().getSourceLocation().getFileName()).build();
generateTemplateMetadata();
generateKindMethod();
stateField.defineField(writer);
paramsField.defineField(writer);
ijField.defineField(writer);
for (FieldRef field : paramFields.values()) {
field.defineField(writer);
}
Statement fieldInitializers = generateRenderMethod();
generateConstructor(fieldInitializers);
innerClasses.registerAllInnerClasses(writer);
writer.visitEnd();
classes.add(writer.toClassData());
classes.addAll(innerClasses.getInnerClassData());
writer = null;
return classes;
}
Aggregations