Search in sources :

Example 6 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.

the class SoyNodeCompiler method visitVeLogNode.

@Override
protected Statement visitVeLogNode(VeLogNode node) {
    final Label restartPoint = new Label();
    final Expression hasLogger = parameterLookup.getRenderContext().hasLogger();
    final boolean hasLogonlyExpression = node.getLogonlyExpression() != null;
    final Expression logonlyExpression = hasLogonlyExpression ? exprCompiler.compile(node.getLogonlyExpression(), restartPoint).unboxAs(boolean.class) : BytecodeUtils.constant(false);
    final Statement enterStatement = appendableExpression.enterLoggableElement(MethodRef.LOG_STATEMENT_CREATE.invoke(BytecodeUtils.constant(node.getLoggingId()), node.getConfigExpression() == null ? BytecodeUtils.constantNull(BytecodeUtils.MESSAGE_TYPE) : exprCompiler.compile(node.getConfigExpression(), restartPoint).unboxAs(Message.class), logonlyExpression)).toStatement();
    final Statement body = Statement.concat(visitChildren(node));
    final Statement exitStatement = appendableExpression.exitLoggableElement().toStatement();
    return new Statement() {

        @Override
        protected void doGen(CodeBuilder cb) {
            Label noLogger = new Label();
            hasLogger.gen(cb);
            cb.ifZCmp(EQ, noLogger);
            enterStatement.gen(cb);
            if (hasLogonlyExpression) {
                Label bodyLabel = new Label();
                cb.goTo(bodyLabel);
                cb.mark(noLogger);
                // if we get here then we have a logonly expression and no logger.
                logonlyExpression.gen(cb);
                cb.ifZCmp(EQ, bodyLabel);
                cb.throwException(BytecodeUtils.ILLEGAL_STATE_EXCEPTION_TYPE, "Cannot set logonly=\"true\" unless there is a logger configured");
                cb.mark(bodyLabel);
            } else {
                cb.mark(noLogger);
            }
            body.gen(cb);
            Label end = new Label();
            hasLogger.gen(cb);
            cb.ifZCmp(EQ, end);
            exitStatement.gen(cb);
            cb.mark(end);
        }
    }.labelStart(restartPoint);
}
Also used : SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement) Label(org.objectweb.asm.Label) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Example 7 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.

the class SoyNodeCompiler method visitSwitchNode.

@Override
protected Statement visitSwitchNode(SwitchNode node) {
    // A few special cases:
    // 1. only a {default} block.  In this case we can skip all the switch logic and temporaries
    // 2. no children.  Just return the empty statement
    // Note that in both of these cases we do not evalutate (or generate code) for the switch
    // expression.
    List<BlockNode> children = node.getChildren();
    if (children.isEmpty()) {
        return Statement.NULL_STATEMENT;
    }
    if (children.size() == 1 && children.get(0) instanceof SwitchDefaultNode) {
        return visitChildrenInNewScope(children.get(0));
    }
    // otherwise we need to evaluate the switch variable and generate dispatching logic.
    SoyExpression switchVar = exprCompiler.compile(node.getExpr());
    Scope scope = variables.enterScope();
    Variable variable = scope.createSynthetic(SyntheticVarName.forSwitch(node), switchVar, STORE);
    Statement initializer = variable.initializer();
    switchVar = switchVar.withSource(variable.local());
    List<IfBlock> cases = new ArrayList<>();
    Optional<Statement> defaultBlock = Optional.absent();
    for (SoyNode child : children) {
        if (child instanceof SwitchCaseNode) {
            SwitchCaseNode caseNode = (SwitchCaseNode) child;
            Label reattachPoint = new Label();
            List<Expression> comparisons = new ArrayList<>();
            for (ExprRootNode caseExpr : caseNode.getExprList()) {
                comparisons.add(compareSoyEquals(switchVar, exprCompiler.compile(caseExpr, reattachPoint)));
            }
            Expression condition = BytecodeUtils.logicalOr(comparisons).labelStart(reattachPoint);
            Statement block = visitChildrenInNewScope(caseNode);
            cases.add(IfBlock.create(condition, block));
        } else {
            SwitchDefaultNode defaultNode = (SwitchDefaultNode) child;
            defaultBlock = Optional.of(visitChildrenInNewScope(defaultNode));
        }
    }
    Statement exitScope = scope.exitScope();
    // generation that we could maybe use
    return Statement.concat(initializer, ControlFlow.ifElseChain(cases, defaultBlock), exitScope);
}
Also used : BlockNode(com.google.template.soy.soytree.SoyNode.BlockNode) SoyNode(com.google.template.soy.soytree.SoyNode) Variable(com.google.template.soy.jbcsrc.TemplateVariableManager.Variable) Statement(com.google.template.soy.jbcsrc.restricted.Statement) ArrayList(java.util.ArrayList) Label(org.objectweb.asm.Label) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode) SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Scope(com.google.template.soy.jbcsrc.TemplateVariableManager.Scope) SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) SwitchCaseNode(com.google.template.soy.soytree.SwitchCaseNode) IfBlock(com.google.template.soy.jbcsrc.ControlFlow.IfBlock) SwitchDefaultNode(com.google.template.soy.soytree.SwitchDefaultNode)

Example 8 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.

the class SoyNodeCompiler method compile.

CompiledMethodBody compile(RenderUnitNode node) {
    Statement templateBody = visitChildrenInNewScope(node);
    // Tag the content with the kind
    if (node.getContentKind() != null) {
        templateBody = Statement.concat(appendableExpression.setSanitizedContentKind(node.getContentKind()).toStatement(), appendableExpression.setSanitizedContentDirectionality(ContentKind.valueOf(node.getContentKind().name()).getDefaultDir()).toStatement(), templateBody);
    }
    Statement jumpTable = detachState.generateReattachTable();
    return CompiledMethodBody.create(Statement.concat(jumpTable, templateBody), detachState.getNumberOfDetaches());
}
Also used : Statement(com.google.template.soy.jbcsrc.restricted.Statement)

Example 9 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement 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);
}
Also used : FieldRef(com.google.template.soy.jbcsrc.restricted.FieldRef) SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement) AppendableAndOptions(com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions) Label(org.objectweb.asm.Label)

Example 10 with Statement

use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.

the class DetachState method createExpressionDetacher.

/**
 * Returns a {@link ExpressionDetacher} that can be used to instrument an expression with detach
 * reattach logic.
 */
@Override
public ExpressionDetacher createExpressionDetacher(Label reattachPoint) {
    SaveRestoreState saveRestoreState = variables.saveRestoreState();
    Statement restore = saveRestoreState.restore();
    int state = addState(reattachPoint, restore);
    Statement saveState = stateField.putInstanceField(thisExpr, BytecodeUtils.constant(state));
    return new ExpressionDetacher.BasicDetacher(Statement.concat(saveRestoreState.save(), saveState));
}
Also used : SaveRestoreState(com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState) Statement(com.google.template.soy.jbcsrc.restricted.Statement)

Aggregations

Statement (com.google.template.soy.jbcsrc.restricted.Statement)30 Expression (com.google.template.soy.jbcsrc.restricted.Expression)15 Label (org.objectweb.asm.Label)14 CodeBuilder (com.google.template.soy.jbcsrc.restricted.CodeBuilder)13 SoyExpression (com.google.template.soy.jbcsrc.restricted.SoyExpression)11 ArrayList (java.util.ArrayList)8 LocalVariable (com.google.template.soy.jbcsrc.restricted.LocalVariable)7 Scope (com.google.template.soy.jbcsrc.TemplateVariableManager.Scope)5 Variable (com.google.template.soy.jbcsrc.TemplateVariableManager.Variable)4 AppendableAndOptions (com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions)4 IfBlock (com.google.template.soy.jbcsrc.ControlFlow.IfBlock)3 SaveRestoreState (com.google.template.soy.jbcsrc.TemplateVariableManager.SaveRestoreState)3 FieldRef (com.google.template.soy.jbcsrc.restricted.FieldRef)3 LinkedHashMap (java.util.LinkedHashMap)3 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)2 ClassData (com.google.template.soy.jbcsrc.internal.ClassData)2 Statement.returnExpression (com.google.template.soy.jbcsrc.restricted.Statement.returnExpression)2 RangeArgs (com.google.template.soy.shared.RangeArgs)2 SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)2 ForNonemptyNode (com.google.template.soy.soytree.ForNonemptyNode)2