Search in sources :

Example 1 with Variable

use of com.google.template.soy.jbcsrc.TemplateVariableManager.Variable in project closure-templates by google.

the class SoyNodeCompiler method visitForNode.

@Override
protected Statement visitForNode(ForNode node) {
    ForNonemptyNode nonEmptyNode = (ForNonemptyNode) node.getChild(0);
    Optional<RangeArgs> exprAsRangeArgs = RangeArgs.createFromNode(node);
    Scope scope = variables.enterScope();
    final Variable indexVar;
    final List<Statement> initializers = new ArrayList<>();
    final Variable sizeVar;
    final Variable itemVar;
    if (exprAsRangeArgs.isPresent()) {
        final CompiledForeachRangeArgs compiledArgs = calculateRangeArgs(node, scope);
        initializers.addAll(compiledArgs.initStatements());
        // The size is just the number of items in the range.  The logic is a little tricky so we
        // implement it in a runtime function: JbcsrcRuntime.rangeLoopLength
        sizeVar = scope.createSynthetic(SyntheticVarName.foreachLoopLength(nonEmptyNode), MethodRef.RUNTIME_RANGE_LOOP_LENGTH.invoke(compiledArgs.start(), compiledArgs.end(), compiledArgs.step()), DERIVED);
        indexVar = scope.createSynthetic(SyntheticVarName.foreachLoopIndex(nonEmptyNode), constant(0), STORE);
        itemVar = scope.create(nonEmptyNode.getVarName(), new Expression(Type.LONG_TYPE, Feature.CHEAP) {

            @Override
            protected void doGen(CodeBuilder adapter) {
                // executes ((long) start + index * step)
                compiledArgs.start().gen(adapter);
                compiledArgs.step().gen(adapter);
                indexVar.local().gen(adapter);
                adapter.visitInsn(Opcodes.IMUL);
                adapter.visitInsn(Opcodes.IADD);
                adapter.cast(Type.INT_TYPE, Type.LONG_TYPE);
            }
        }, DERIVED);
    } else {
        SoyExpression expr = exprCompiler.compile(node.getExpr()).unboxAs(List.class);
        Variable listVar = scope.createSynthetic(SyntheticVarName.foreachLoopList(nonEmptyNode), expr, STORE);
        initializers.add(listVar.initializer());
        sizeVar = scope.createSynthetic(SyntheticVarName.foreachLoopLength(nonEmptyNode), MethodRef.LIST_SIZE.invoke(listVar.local()), DERIVED);
        indexVar = scope.createSynthetic(SyntheticVarName.foreachLoopIndex(nonEmptyNode), constant(0), STORE);
        itemVar = scope.create(nonEmptyNode.getVarName(), MethodRef.LIST_GET.invoke(listVar.local(), indexVar.local()).checkedCast(SOY_VALUE_PROVIDER_TYPE), DERIVED);
    }
    initializers.add(sizeVar.initializer());
    final Statement loopBody = visitChildrenInNewScope(nonEmptyNode);
    final Statement exitScope = scope.exitScope();
    // it important for this to be generated after exitScope is called (or before enterScope)
    final Statement emptyBlock = node.numChildren() == 2 ? visitChildrenInNewScope(node.getChild(1)) : null;
    return new Statement() {

        @Override
        protected void doGen(CodeBuilder adapter) {
            for (Statement initializer : initializers) {
                initializer.gen(adapter);
            }
            sizeVar.local().gen(adapter);
            Label emptyListLabel = new Label();
            adapter.ifZCmp(Opcodes.IFEQ, emptyListLabel);
            indexVar.initializer().gen(adapter);
            Label loopStart = adapter.mark();
            itemVar.initializer().gen(adapter);
            loopBody.gen(adapter);
            // index++
            adapter.iinc(indexVar.local().index(), 1);
            indexVar.local().gen(adapter);
            sizeVar.local().gen(adapter);
            // if index < list.size(), goto loopstart
            adapter.ifICmp(Opcodes.IFLT, loopStart);
            // exit the loop
            exitScope.gen(adapter);
            if (emptyBlock != null) {
                Label skipIfEmptyBlock = new Label();
                adapter.goTo(skipIfEmptyBlock);
                adapter.mark(emptyListLabel);
                emptyBlock.gen(adapter);
                adapter.mark(skipIfEmptyBlock);
            } else {
                adapter.mark(emptyListLabel);
            }
        }
    };
}
Also used : Variable(com.google.template.soy.jbcsrc.TemplateVariableManager.Variable) RangeArgs(com.google.template.soy.shared.RangeArgs) Statement(com.google.template.soy.jbcsrc.restricted.Statement) ArrayList(java.util.ArrayList) Label(org.objectweb.asm.Label) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder) 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) ForNonemptyNode(com.google.template.soy.soytree.ForNonemptyNode)

Example 2 with Variable

use of com.google.template.soy.jbcsrc.TemplateVariableManager.Variable 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 3 with Variable

use of com.google.template.soy.jbcsrc.TemplateVariableManager.Variable in project closure-templates by google.

the class MsgCompiler method handleTranslationWithPlaceholders.

/**
 * Handles a complex message with placeholders.
 */
private Statement handleTranslationWithPlaceholders(MsgNode msg, ImmutableList<SoyPrintDirective> escapingDirectives, Expression soyMsgParts, Expression locale, ImmutableList<SoyMsgPart> parts) {
    // We need to render placeholders into a buffer and then pack them into a map to pass to
    // Runtime.renderSoyMsgWithPlaceholders.
    Expression placeholderMap = variables.getMsgPlaceholderMapField().accessor(thisVar);
    Map<String, Statement> placeholderNameToPutStatement = new LinkedHashMap<>();
    putPlaceholdersIntoMap(placeholderMap, msg, parts, placeholderNameToPutStatement);
    // sanity check
    checkState(!placeholderNameToPutStatement.isEmpty());
    variables.setMsgPlaceholderMapMinSize(placeholderNameToPutStatement.size());
    Statement populateMap = Statement.concat(placeholderNameToPutStatement.values());
    Statement clearMap = placeholderMap.invokeVoid(MethodRef.LINKED_HASH_MAP_CLEAR);
    Statement render;
    if (areAllPrintDirectivesStreamable(escapingDirectives)) {
        // No need to save/restore since rendering a message doesn't detach.  All detaching for data
        // should have already happened as part of constructing the placholder map.
        AppendableAndOptions wrappedAppendable = applyStreamingEscapingDirectives(escapingDirectives, appendableExpression, parameterLookup.getRenderContext(), variables);
        Statement initAppendable = Statement.NULL_STATEMENT;
        Statement clearAppendable = Statement.NULL_STATEMENT;
        Expression appendableExpression = wrappedAppendable.appendable();
        if (wrappedAppendable.closeable()) {
            Scope scope = variables.enterScope();
            Variable appendableVar = scope.createTemporary("msg_appendable", wrappedAppendable.appendable());
            initAppendable = appendableVar.initializer();
            appendableExpression = appendableVar.local();
            clearAppendable = Statement.concat(appendableVar.local().checkedCast(BytecodeUtils.CLOSEABLE_TYPE).invokeVoid(MethodRef.CLOSEABLE_CLOSE), scope.exitScope());
        }
        render = Statement.concat(initAppendable, MethodRef.RUNTIME_RENDER_SOY_MSG_PARTS_WITH_PLACEHOLDERS.invokeVoid(soyMsgParts, locale, placeholderMap, appendableExpression), clearAppendable);
    } else {
        // render into the handy buffer we already have!
        Statement renderToBuffer = MethodRef.RUNTIME_RENDER_SOY_MSG_PARTS_WITH_PLACEHOLDERS.invokeVoid(soyMsgParts, locale, placeholderMap, tempBuffer());
        // N.B. the type here is always 'string'
        SoyExpression value = SoyExpression.forString(tempBuffer().invoke(MethodRef.ADVISING_STRING_BUILDER_GET_AND_CLEAR));
        for (SoyPrintDirective directive : escapingDirectives) {
            value = parameterLookup.getRenderContext().applyPrintDirective(directive, value);
        }
        render = Statement.concat(renderToBuffer, appendableExpression.appendString(value.coerceToString()).toStatement());
    }
    return Statement.concat(populateMap, render, clearMap);
}
Also used : SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Variable(com.google.template.soy.jbcsrc.TemplateVariableManager.Variable) Scope(com.google.template.soy.jbcsrc.TemplateVariableManager.Scope) SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) Statement(com.google.template.soy.jbcsrc.restricted.Statement) AppendableAndOptions(com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions) LinkedHashMap(java.util.LinkedHashMap)

Example 4 with Variable

use of com.google.template.soy.jbcsrc.TemplateVariableManager.Variable in project closure-templates by google.

the class PrintDirectives method applyStreamingPrintDirectivesTo.

private static AppendableAndOptions applyStreamingPrintDirectivesTo(List<DirectiveWithArgs> directivesToApply, Expression appendable, JbcSrcPluginContext context, TemplateVariableManager variableManager) {
    final List<LocalVariable> closeables = new ArrayList<>();
    final List<Variable> appendableVars = new ArrayList<>();
    Scope scope = variableManager.enterScope();
    AppendableAndOptions prev = AppendableAndOptions.create(appendable);
    Variable prevVar = scope.createTemporary("tmp_appendable", appendable);
    appendableVars.add(prevVar);
    // appendable with the last directive first. so iterate in reverse order.
    for (DirectiveWithArgs directiveToApply : Lists.reverse(directivesToApply)) {
        AppendableAndOptions curr = directiveToApply.apply(context, prevVar.local());
        Variable currVar = scope.createTemporary("tmp_appendable", curr.appendable());
        appendableVars.add(currVar);
        if (curr.closeable()) {
            closeables.add(currVar.local());
        }
        prev = curr;
        prevVar = currVar;
    }
    // Check if we need to apply a wrapper to make sure close propagates to all the right places
    // this is necessary if there are multiple closeable wrappers.
    final Expression appendableExpression;
    final boolean closeable;
    if (closeables.isEmpty()) {
        appendableExpression = prev.appendable();
        closeable = false;
    } else if (closeables.size() == 1 && prev.closeable()) {
        // there is exactly one closeable and it is first, we don't need a wrapper
        appendableExpression = prev.appendable();
        closeable = true;
    } else {
        // there is either more than one closeable, or it is not the first one, so we need a wrapper
        // We need to reverse the list of closeables so that we close them in the correct order. for
        // example, given '|foo|bar' we will first wrap the delegate with bar and then with foo but we
        // need to close foo first.
        appendableExpression = RUNTIME_PROPAGATE_CLOSE.invoke(Iterables.getLast(appendableVars).local(), BytecodeUtils.asImmutableList(Lists.reverse(closeables)));
        closeable = true;
    }
    final Statement exitScope = scope.exitScope();
    Expression result = new Expression(appendableExpression.resultType()) {

        @Override
        protected void doGen(CodeBuilder adapter) {
            for (Variable var : appendableVars) {
                var.initializer().gen(adapter);
            }
            appendableExpression.gen(adapter);
            exitScope.gen(adapter);
        }
    };
    if (closeable) {
        return AppendableAndOptions.createCloseable(result);
    } else {
        return AppendableAndOptions.create(result);
    }
}
Also used : Variable(com.google.template.soy.jbcsrc.TemplateVariableManager.Variable) LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) Scope(com.google.template.soy.jbcsrc.TemplateVariableManager.Scope) 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) LocalVariable(com.google.template.soy.jbcsrc.restricted.LocalVariable) ArrayList(java.util.ArrayList) CodeBuilder(com.google.template.soy.jbcsrc.restricted.CodeBuilder)

Aggregations

Scope (com.google.template.soy.jbcsrc.TemplateVariableManager.Scope)4 Variable (com.google.template.soy.jbcsrc.TemplateVariableManager.Variable)4 Expression (com.google.template.soy.jbcsrc.restricted.Expression)4 SoyExpression (com.google.template.soy.jbcsrc.restricted.SoyExpression)4 Statement (com.google.template.soy.jbcsrc.restricted.Statement)4 ArrayList (java.util.ArrayList)3 CodeBuilder (com.google.template.soy.jbcsrc.restricted.CodeBuilder)2 AppendableAndOptions (com.google.template.soy.jbcsrc.restricted.SoyJbcSrcPrintDirective.Streamable.AppendableAndOptions)2 Label (org.objectweb.asm.Label)2 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)1 IfBlock (com.google.template.soy.jbcsrc.ControlFlow.IfBlock)1 LocalVariable (com.google.template.soy.jbcsrc.restricted.LocalVariable)1 RangeArgs (com.google.template.soy.shared.RangeArgs)1 SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)1 ForNonemptyNode (com.google.template.soy.soytree.ForNonemptyNode)1 SoyNode (com.google.template.soy.soytree.SoyNode)1 BlockNode (com.google.template.soy.soytree.SoyNode.BlockNode)1 SwitchCaseNode (com.google.template.soy.soytree.SwitchCaseNode)1 SwitchDefaultNode (com.google.template.soy.soytree.SwitchDefaultNode)1 LinkedHashMap (java.util.LinkedHashMap)1