Search in sources :

Example 1 with ExprRootNode

use of com.google.template.soy.exprtree.ExprRootNode in project closure-templates by google.

the class GenCallCodeUtils method gen.

/**
 * Generates the JS expression for a given call.
 *
 * <p> Important: If there are CallParamContentNode children whose contents are not computable as
 * JS expressions, then this function assumes that, elsewhere, code has been generated to define
 * their respective 'param&lt;n&gt;' temporary variables.
 *
 * <p> Here are five example calls:
 * <pre>
 *   {call some.func data="all" /}
 *   {call some.func data="$boo.foo" /}
 *   {call some.func}
 *     {param goo = $moo /}
 *   {/call}
 *   {call some.func data="$boo"}
 *     {param goo}Blah{/param}
 *   {/call}
 *   {call some.func}
 *     {param goo}
 *       {for $i in range(3)}{$i}{/for}
 *     {/param}
 *   {/call}
 * </pre>
 * Their respective generated calls might be the following:
 * <pre>
 *   some.func(opt_data)
 *   some.func(opt_data.boo.foo)
 *   some.func({goo: opt_data.moo})
 *   some.func(soy.$$assignDefaults({goo: 'Blah'}, opt_data.boo))
 *   some.func({goo: param65})
 * </pre>
 * Note that in the last case, the param content is not computable as JS expressions, so we assume
 * that code has been generated to define the temporary variable 'param&lt;n&gt;'.
 *
 * @param callNode The call to generate code for.
 * @param templateAliases A mapping of fully qualified calls to a variable in scope.
 * @return The JS expression for the call.
 */
public CodeChunk.WithValue gen(CallNode callNode, TemplateAliases templateAliases, TranslationContext translationContext, ErrorReporter errorReporter) {
    // Build the JS CodeChunk for the callee's name.
    CodeChunk.WithValue callee;
    if (callNode instanceof CallBasicNode) {
        // Case 1: Basic call.
        // TODO(lukes): add the logic for the goog.require here.  The simplest strategy requires a
        // TemplateRegistry to detect external templates.
        callee = CodeChunk.dottedIdNoRequire(templateAliases.get(((CallBasicNode) callNode).getCalleeName()));
    } else {
        // Case 2: Delegate call.
        CallDelegateNode callDelegateNode = (CallDelegateNode) callNode;
        CodeChunk.WithValue calleeId = JsRuntime.SOY_GET_DELTEMPLATE_ID.call(stringLiteral(delTemplateNamer.getDelegateName(callDelegateNode)));
        ExprRootNode variantSoyExpr = callDelegateNode.getDelCalleeVariantExpr();
        CodeChunk.WithValue variant;
        if (variantSoyExpr == null) {
            // Case 2a: Delegate call with empty variant.
            variant = LITERAL_EMPTY_STRING;
        } else {
            // Case 2b: Delegate call with variant expression.
            variant = new TranslateExprNodeVisitor(translationContext, errorReporter).exec(variantSoyExpr);
        }
        callee = SOY_GET_DELEGATE_FN.call(calleeId, variant, callDelegateNode.allowEmptyDefault() ? LITERAL_TRUE : LITERAL_FALSE);
    }
    // Generate the data object to pass to callee
    CodeChunk.WithValue objToPass = genObjToPass(callNode, templateAliases, translationContext, errorReporter);
    // Generate the main call expression.
    CodeChunk.WithValue call = callee.call(objToPass, JsRuntime.OPT_IJ_DATA);
    if (callNode.getEscapingDirectives().isEmpty()) {
        return call;
    }
    // Apply escaping directives as necessary.
    // 
    // The print directive system continues to use JsExpr, as it is a publicly available API and
    // migrating it to CodeChunk would be a major change. Therefore, we convert our CodeChunks
    // to JsExpr and back here.
    JsExpr callResult = call.singleExprOrName();
    RequiresCollector.IntoImmutableSet collector = new RequiresCollector.IntoImmutableSet();
    call.collectRequires(collector);
    for (SoyPrintDirective directive : callNode.getEscapingDirectives()) {
        Preconditions.checkState(directive instanceof SoyJsSrcPrintDirective, "Contextual autoescaping produced a bogus directive: %s", directive.getName());
        callResult = ((SoyJsSrcPrintDirective) directive).applyForJsSrc(callResult, ImmutableList.<JsExpr>of());
        if (directive instanceof SoyLibraryAssistedJsSrcPrintDirective) {
            for (String name : ((SoyLibraryAssistedJsSrcPrintDirective) directive).getRequiredJsLibNames()) {
                collector.add(GoogRequire.create(name));
            }
        }
    }
    return fromExpr(callResult, collector.get()).withInitialStatements(call.initialStatements());
}
Also used : JsExpr(com.google.template.soy.jssrc.restricted.JsExpr) CallBasicNode(com.google.template.soy.soytree.CallBasicNode) RequiresCollector(com.google.template.soy.jssrc.dsl.CodeChunk.RequiresCollector) CallDelegateNode(com.google.template.soy.soytree.CallDelegateNode) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode) CodeChunk(com.google.template.soy.jssrc.dsl.CodeChunk) SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) SoyJsSrcPrintDirective(com.google.template.soy.jssrc.restricted.SoyJsSrcPrintDirective) SoyLibraryAssistedJsSrcPrintDirective(com.google.template.soy.jssrc.restricted.SoyLibraryAssistedJsSrcPrintDirective)

Example 2 with ExprRootNode

use of com.google.template.soy.exprtree.ExprRootNode in project closure-templates by google.

the class SoyNodeCompiler method visitPrintNode.

@Override
protected Statement visitPrintNode(PrintNode node) {
    if (node.getExpr().getRoot() instanceof FunctionNode) {
        FunctionNode fn = (FunctionNode) node.getExpr().getRoot();
        if (fn.getSoyFunction() instanceof LoggingFunction) {
            return visitLoggingFunction(node, fn, (LoggingFunction) fn.getSoyFunction());
        }
    }
    // evaluates to a SoyValueProvider.  This will allow us to render incrementally.
    if (areAllPrintDirectivesStreamable(node)) {
        Label reattachPoint = new Label();
        ExprRootNode expr = node.getExpr();
        Optional<Expression> asSoyValueProvider = expressionToSoyValueProviderCompiler.compileAvoidingBoxing(expr, reattachPoint);
        if (asSoyValueProvider.isPresent()) {
            return renderIncrementally(asSoyValueProvider.get(), node.getChildren(), reattachPoint);
        }
    }
    // otherwise we need to apply some non-streaming print directives, or the expression would
    // require boxing to be a print directive (which usually means it is quite trivial).
    Label reattachPoint = new Label();
    SoyExpression value = compilePrintNodeAsExpression(node, reattachPoint);
    // TODO(lukes): call value.render?
    AppendableExpression renderSoyValue = appendableExpression.appendString(value.coerceToString()).labelStart(reattachPoint);
    Statement stmt;
    if (shouldCheckBuffer(node)) {
        stmt = detachState.detachLimited(renderSoyValue);
    } else {
        stmt = renderSoyValue.toStatement();
    }
    return stmt;
}
Also used : SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) SoyExpression(com.google.template.soy.jbcsrc.restricted.SoyExpression) Expression(com.google.template.soy.jbcsrc.restricted.Expression) Statement(com.google.template.soy.jbcsrc.restricted.Statement) FunctionNode(com.google.template.soy.exprtree.FunctionNode) Label(org.objectweb.asm.Label) LoggingFunction(com.google.template.soy.logging.LoggingFunction) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode)

Example 3 with ExprRootNode

use of com.google.template.soy.exprtree.ExprRootNode 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 4 with ExprRootNode

use of com.google.template.soy.exprtree.ExprRootNode in project closure-templates by google.

the class GenPyCallExprVisitor method visitCallDelegateNode.

/**
 * Visits a delegate call node and builds the call expression to retrieve the function and execute
 * it. The get_delegate_fn returns the function directly, so its output can be called directly.
 *
 * @param node The delegate call node.
 * @return The call Python expression.
 */
@Override
protected PyExpr visitCallDelegateNode(CallDelegateNode node) {
    ExprRootNode variantSoyExpr = node.getDelCalleeVariantExpr();
    PyExpr variantPyExpr;
    if (variantSoyExpr == null) {
        // Case 1: Delegate call with empty variant.
        variantPyExpr = new PyStringExpr("''");
    } else {
        // Case 2: Delegate call with variant expression.
        TranslateToPyExprVisitor translator = new TranslateToPyExprVisitor(localVarStack, errorReporter);
        variantPyExpr = translator.exec(variantSoyExpr);
    }
    String calleeExprText = new PyFunctionExprBuilder("runtime.get_delegate_fn").addArg(node.getDelCalleeName()).addArg(variantPyExpr).addArg(node.allowEmptyDefault()).build();
    String callExprText = calleeExprText + "(" + genObjToPass(node) + ", ijData)";
    return escapeCall(callExprText, node.getEscapingDirectives());
}
Also used : PyExpr(com.google.template.soy.pysrc.restricted.PyExpr) PyFunctionExprBuilder(com.google.template.soy.pysrc.restricted.PyFunctionExprBuilder) PyStringExpr(com.google.template.soy.pysrc.restricted.PyStringExpr) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode)

Example 5 with ExprRootNode

use of com.google.template.soy.exprtree.ExprRootNode in project closure-templates by google.

the class GenPyExprsVisitor method visitPrintNode.

/**
 * Visiting a print node accomplishes 3 basic tasks. It loads data, it performs any operations
 * needed, and it executes the appropriate print directives.
 *
 * <p>TODO(dcphillips): Add support for local variables once LetNode are supported.
 *
 * <p>Example:
 *
 * <pre>
 *   {$boo |changeNewlineToBr}
 *   {$goo + 5}
 * </pre>
 *
 * might generate
 *
 * <pre>
 *   sanitize.change_newline_to_br(data.get('boo'))
 *   data.get('goo') + 5
 * </pre>
 */
@Override
protected void visitPrintNode(PrintNode node) {
    TranslateToPyExprVisitor translator = new TranslateToPyExprVisitor(localVarExprs, errorReporter);
    PyExpr pyExpr = translator.exec(node.getExpr());
    // Process directives.
    for (PrintDirectiveNode directiveNode : node.getChildren()) {
        // Get directive.
        SoyPrintDirective directive = directiveNode.getPrintDirective();
        if (!(directive instanceof SoyPySrcPrintDirective)) {
            errorReporter.report(directiveNode.getSourceLocation(), UNKNOWN_SOY_PY_SRC_PRINT_DIRECTIVE, directiveNode.getName());
            continue;
        }
        // Get directive args.
        List<ExprRootNode> args = directiveNode.getArgs();
        // Translate directive args.
        List<PyExpr> argsPyExprs = new ArrayList<>(args.size());
        for (ExprRootNode arg : args) {
            argsPyExprs.add(translator.exec(arg));
        }
        // Apply directive.
        pyExpr = ((SoyPySrcPrintDirective) directive).applyForPySrc(pyExpr, argsPyExprs);
    }
    pyExprs.add(pyExpr);
}
Also used : PyExpr(com.google.template.soy.pysrc.restricted.PyExpr) SoyPySrcPrintDirective(com.google.template.soy.pysrc.restricted.SoyPySrcPrintDirective) PrintDirectiveNode(com.google.template.soy.soytree.PrintDirectiveNode) SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) ArrayList(java.util.ArrayList) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode)

Aggregations

ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)16 SoyDataException (com.google.template.soy.data.SoyDataException)3 SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)3 PrintDirectiveNode (com.google.template.soy.soytree.PrintDirectiveNode)3 ArrayList (java.util.ArrayList)3 SoyValue (com.google.template.soy.data.SoyValue)2 StringNode (com.google.template.soy.exprtree.StringNode)2 Expression (com.google.template.soy.jbcsrc.restricted.Expression)2 SoyExpression (com.google.template.soy.jbcsrc.restricted.SoyExpression)2 Statement (com.google.template.soy.jbcsrc.restricted.Statement)2 CodeChunk (com.google.template.soy.jssrc.dsl.CodeChunk)2 SoyJsSrcPrintDirective (com.google.template.soy.jssrc.restricted.SoyJsSrcPrintDirective)2 PyExpr (com.google.template.soy.pysrc.restricted.PyExpr)2 CaseOrDefaultNode (com.google.template.soy.soytree.CaseOrDefaultNode)2 Label (org.objectweb.asm.Label)2 Identifier (com.google.template.soy.base.internal.Identifier)1 IntegerData (com.google.template.soy.data.restricted.IntegerData)1 UndefinedData (com.google.template.soy.data.restricted.UndefinedData)1 Checkpoint (com.google.template.soy.error.ErrorReporter.Checkpoint)1 ExprNode (com.google.template.soy.exprtree.ExprNode)1