Search in sources :

Example 1 with CallDelegateNode

use of com.google.template.soy.soytree.CallDelegateNode 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 CallDelegateNode

use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.

the class TemplateCompiler method generateTemplateMetadata.

/**
 * Writes a {@link TemplateMetadata} to the generated class.
 */
private void generateTemplateMetadata() {
    SanitizedContentKind contentKind = template.node().getContentKind();
    String kind = contentKind == null ? "" : contentKind.name();
    // using linked hash sets below for determinism
    Set<String> uniqueIjs = new LinkedHashSet<>();
    for (VarRefNode var : getAllNodesOfType(template.node(), VarRefNode.class)) {
        if (var.isInjected()) {
            uniqueIjs.add(var.getName());
        }
    }
    Set<String> callees = new LinkedHashSet<>();
    for (CallBasicNode call : getAllNodesOfType(template.node(), CallBasicNode.class)) {
        callees.add(call.getCalleeName());
    }
    Set<String> delCallees = new LinkedHashSet<>();
    for (CallDelegateNode call : getAllNodesOfType(template.node(), CallDelegateNode.class)) {
        delCallees.add(call.getDelCalleeName());
    }
    TemplateMetadata.DelTemplateMetadata deltemplateMetadata;
    if (template.node().getKind() == SoyNode.Kind.TEMPLATE_DELEGATE_NODE) {
        TemplateDelegateNode delegateNode = (TemplateDelegateNode) template.node();
        deltemplateMetadata = createDelTemplateMetadata(delegateNode.getDelPackageName() == null ? "" : delegateNode.getDelPackageName(), delegateNode.getDelTemplateName(), delegateNode.getDelTemplateVariant());
    } else {
        deltemplateMetadata = createDefaultDelTemplateMetadata();
    }
    TemplateMetadata metadata = createTemplateMetadata(kind, uniqueIjs, callees, delCallees, deltemplateMetadata);
    TEMPLATE_METADATA_REF.write(metadata, writer);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) VarRefNode(com.google.template.soy.exprtree.VarRefNode) SanitizedContentKind(com.google.template.soy.base.internal.SanitizedContentKind) CallBasicNode(com.google.template.soy.soytree.CallBasicNode) TemplateMetadata(com.google.template.soy.jbcsrc.shared.TemplateMetadata) CallDelegateNode(com.google.template.soy.soytree.CallDelegateNode)

Example 3 with CallDelegateNode

use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.

the class BytecodeCompilerTest method testDelCallEscaping_separateCompilation.

// Tests for a bug where we would overescape deltemplates at the call site when the strict
// content kind of the deltemplate was unknown at compile time.
@Test
public void testDelCallEscaping_separateCompilation() throws IOException {
    String soyFileContent1 = Joiner.on("\n").join("{namespace ns}", "", "{template .callerTemplate}", "  {delcall myApp.myDelegate/}", "{/template}", "");
    SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(soyFileContent1).parse().fileSet();
    // apply an escaping directive to the callsite, just like the autoescaper would
    CallDelegateNode cdn = SoyTreeUtils.getAllNodesOfType(soyTree.getChild(0), CallDelegateNode.class).get(0);
    cdn.setEscapingDirectives(ImmutableList.of(new EscapeHtmlDirective()));
    TemplateRegistry templateRegistry = new TemplateRegistry(soyTree, ErrorReporter.exploding());
    CompiledTemplates templates = BytecodeCompiler.compile(templateRegistry, false, ErrorReporter.exploding()).get();
    CompiledTemplate.Factory caller = templates.getTemplateFactory("ns.callerTemplate");
    try {
        renderWithContext(caller, getDefaultContext(templates));
        fail();
    } catch (IllegalArgumentException iae) {
        assertThat(iae).hasMessageThat().isEqualTo("Found no active impl for delegate call to \"myApp.myDelegate\" (and delcall does " + "not set allowemptydefault=\"true\").");
    }
    String soyFileContent2 = Joiner.on("\n").join("{namespace ns2}", "", "{deltemplate myApp.myDelegate}", "  <span>Hello</span>", "{/deltemplate}", "");
    CompiledTemplates templatesWithDeltemplate = compileFiles(soyFileContent2);
    // By passing an alternate context, we ensure the deltemplate selector contains the delegate
    assertThat(renderWithContext(caller, getDefaultContext(templatesWithDeltemplate))).isEqualTo("<span>Hello</span>");
}
Also used : TemplateRegistry(com.google.template.soy.soytree.TemplateRegistry) EscapeHtmlDirective(com.google.template.soy.coredirectives.EscapeHtmlDirective) SoyFileSetNode(com.google.template.soy.soytree.SoyFileSetNode) CompiledTemplates(com.google.template.soy.jbcsrc.shared.CompiledTemplates) CallDelegateNode(com.google.template.soy.soytree.CallDelegateNode) CompiledTemplate(com.google.template.soy.jbcsrc.shared.CompiledTemplate) Test(org.junit.Test)

Example 4 with CallDelegateNode

use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.

the class TemplateParserTest method testParseCallStmtWithPhname.

@SuppressWarnings({ "ConstantConditions" })
@Test
public void testParseCallStmtWithPhname() throws Exception {
    String templateBody = "{@param animals:?}\n" + "{msg desc=\"...\"}\n" + "  {call .booTemplate_ phname=\"booTemplate_\" /}\n" + "  {call .booTemplate_ phname=\"booTemplate_\" /}\n" + "  {delcall MySecretFeature.zooTemplate data=\"$animals\" phname=\"secret_zoo\"}\n" + "    {param zoo: 0 /}\n" + "  {/delcall}\n" + "{/msg}";
    List<StandaloneNode> nodes = ((MsgFallbackGroupNode) parseTemplateContent(templateBody, FAIL).getChild(0)).getChild(0).getChildren();
    assertEquals(3, nodes.size());
    CallBasicNode cn0 = (CallBasicNode) ((MsgPlaceholderNode) nodes.get(0)).getChild(0);
    assertEquals("BOO_TEMPLATE", cn0.genBasePhName());
    assertEquals("brittle.test.ns.booTemplate_", cn0.getCalleeName());
    assertEquals(".booTemplate_", cn0.getSourceCalleeName());
    assertEquals(false, cn0.isPassingData());
    assertEquals(false, cn0.isPassingAllData());
    assertEquals(null, cn0.getDataExpr());
    assertEquals(0, cn0.numChildren());
    CallBasicNode cn1 = (CallBasicNode) ((MsgPlaceholderNode) nodes.get(1)).getChild(0);
    CallDelegateNode cn2 = (CallDelegateNode) ((MsgPlaceholderNode) nodes.get(2)).getChild(0);
    assertEquals("SECRET_ZOO", cn2.genBasePhName());
    assertEquals("MySecretFeature.zooTemplate", cn2.getDelCalleeName());
    assertEquals(true, cn2.isPassingData());
    assertEquals(false, cn2.isPassingAllData());
    assertTrue(cn2.getDataExpr().getRoot() != null);
    assertEquals("$animals", cn2.getDataExpr().toSourceString());
    assertEquals(1, cn2.numChildren());
    // CallNodes are never same
    assertFalse(cn0.genSamenessKey().equals(cn1.genSamenessKey()));
    assertFalse(cn2.genSamenessKey().equals(cn0.genSamenessKey()));
}
Also used : StandaloneNode(com.google.template.soy.soytree.SoyNode.StandaloneNode) CallBasicNode(com.google.template.soy.soytree.CallBasicNode) CallDelegateNode(com.google.template.soy.soytree.CallDelegateNode) Test(org.junit.Test)

Example 5 with CallDelegateNode

use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.

the class TemplateParserTest method testParseDelegateCallStmt.

@SuppressWarnings({ "ConstantConditions" })
@Test
public void testParseDelegateCallStmt() throws Exception {
    String templateBody = "{@param animals : ?}{@param too : ?}\n" + "  {delcall booTemplate /}\n" + "  {delcall foo.goo.mooTemplate data=\"all\" /}\n" + "  {delcall MySecretFeature.zooTemplate data=\"$animals\"}\n" + "    {param yoo: round($too) /}\n" + "    {param woo kind=\"html\"}poo{/param}\n" + "  {/delcall}\n";
    List<StandaloneNode> nodes = parseTemplateContent(templateBody, FAIL).getChildren();
    assertEquals(3, nodes.size());
    CallDelegateNode cn0 = (CallDelegateNode) nodes.get(0);
    assertEquals("booTemplate", cn0.getDelCalleeName());
    assertEquals(false, cn0.isPassingData());
    assertEquals(false, cn0.isPassingAllData());
    assertEquals(null, cn0.getDataExpr());
    assertEquals("XXX", cn0.genBasePhName());
    assertEquals(0, cn0.numChildren());
    CallDelegateNode cn1 = (CallDelegateNode) nodes.get(1);
    assertEquals("foo.goo.mooTemplate", cn1.getDelCalleeName());
    assertEquals(true, cn1.isPassingData());
    assertEquals(true, cn1.isPassingAllData());
    assertEquals(null, cn1.getDataExpr());
    assertFalse(cn1.genSamenessKey().equals(cn0.genSamenessKey()));
    assertEquals(0, cn1.numChildren());
    CallDelegateNode cn2 = (CallDelegateNode) nodes.get(2);
    assertEquals("MySecretFeature.zooTemplate", cn2.getDelCalleeName());
    assertEquals(true, cn2.isPassingData());
    assertEquals(false, cn2.isPassingAllData());
    assertTrue(cn2.getDataExpr().getRoot() != null);
    assertEquals("$animals", cn2.getDataExpr().toSourceString());
    assertEquals(2, cn2.numChildren());
    CallParamValueNode cn2cpvn0 = (CallParamValueNode) cn2.getChild(0);
    assertEquals("yoo", cn2cpvn0.getKey().identifier());
    assertEquals("round($too)", cn2cpvn0.getExpr().toSourceString());
    assertTrue(cn2cpvn0.getExpr().getRoot() instanceof FunctionNode);
    CallParamContentNode cn2cpcn1 = (CallParamContentNode) cn2.getChild(1);
    assertEquals("woo", cn2cpcn1.getKey().identifier());
    assertEquals("poo", ((RawTextNode) cn2cpcn1.getChild(0)).getRawText());
}
Also used : StandaloneNode(com.google.template.soy.soytree.SoyNode.StandaloneNode) CallParamContentNode(com.google.template.soy.soytree.CallParamContentNode) FunctionNode(com.google.template.soy.exprtree.FunctionNode) CallParamValueNode(com.google.template.soy.soytree.CallParamValueNode) CallDelegateNode(com.google.template.soy.soytree.CallDelegateNode) Test(org.junit.Test)

Aggregations

CallDelegateNode (com.google.template.soy.soytree.CallDelegateNode)5 CallBasicNode (com.google.template.soy.soytree.CallBasicNode)3 Test (org.junit.Test)3 StandaloneNode (com.google.template.soy.soytree.SoyNode.StandaloneNode)2 SanitizedContentKind (com.google.template.soy.base.internal.SanitizedContentKind)1 EscapeHtmlDirective (com.google.template.soy.coredirectives.EscapeHtmlDirective)1 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)1 FunctionNode (com.google.template.soy.exprtree.FunctionNode)1 VarRefNode (com.google.template.soy.exprtree.VarRefNode)1 CompiledTemplate (com.google.template.soy.jbcsrc.shared.CompiledTemplate)1 CompiledTemplates (com.google.template.soy.jbcsrc.shared.CompiledTemplates)1 TemplateMetadata (com.google.template.soy.jbcsrc.shared.TemplateMetadata)1 CodeChunk (com.google.template.soy.jssrc.dsl.CodeChunk)1 RequiresCollector (com.google.template.soy.jssrc.dsl.CodeChunk.RequiresCollector)1 JsExpr (com.google.template.soy.jssrc.restricted.JsExpr)1 SoyJsSrcPrintDirective (com.google.template.soy.jssrc.restricted.SoyJsSrcPrintDirective)1 SoyLibraryAssistedJsSrcPrintDirective (com.google.template.soy.jssrc.restricted.SoyLibraryAssistedJsSrcPrintDirective)1 SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)1 CallParamContentNode (com.google.template.soy.soytree.CallParamContentNode)1 CallParamValueNode (com.google.template.soy.soytree.CallParamValueNode)1