Search in sources :

Example 1 with CallBasicNode

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

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

the class GenJsCodeVisitor method addCodeToRequireSoyNamespaces.

/**
 * Helper for visitSoyFileNode(SoyFileNode) to add code to require Soy namespaces.
 *
 * @param soyFile The node we're visiting.
 */
private void addCodeToRequireSoyNamespaces(SoyFileNode soyFile) {
    String prevCalleeNamespace = null;
    Set<String> calleeNamespaces = new TreeSet<>();
    for (CallBasicNode node : new FindCalleesNotInFileVisitor().exec(soyFile)) {
        String calleeNotInFile = node.getCalleeName();
        int lastDotIndex = calleeNotInFile.lastIndexOf('.');
        calleeNamespaces.add(calleeNotInFile.substring(0, lastDotIndex));
    }
    for (String calleeNamespace : calleeNamespaces) {
        if (calleeNamespace.length() > 0 && !calleeNamespace.equals(prevCalleeNamespace)) {
            jsCodeBuilder.addGoogRequire(GoogRequire.create(calleeNamespace));
            prevCalleeNamespace = calleeNamespace;
        }
    }
}
Also used : FindCalleesNotInFileVisitor(com.google.template.soy.shared.internal.FindCalleesNotInFileVisitor) TreeSet(java.util.TreeSet) CallBasicNode(com.google.template.soy.soytree.CallBasicNode)

Example 3 with CallBasicNode

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

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

the class GenJsCodeVisitor method addCodeToRequireGoogModules.

/**
 * Generates the module imports and aliasing. This generates code like the following:
 *
 * <pre>
 * var $import1 = goog.require('some.namespace');
 * var $templateAlias1 = $import1.tmplOne;
 * var $templateAlias2 = $import1.tmplTwo;
 * var $import2 = goog.require('other.namespace');
 * ...
 * </pre>
 *
 * @param soyFile The node we're visiting.
 */
private void addCodeToRequireGoogModules(SoyFileNode soyFile) {
    int counter = 1;
    // Get all the unique calls in the file.
    Set<String> calls = new HashSet<>();
    for (CallBasicNode callNode : SoyTreeUtils.getAllNodesOfType(soyFile, CallBasicNode.class)) {
        calls.add(callNode.getCalleeName());
    }
    // Map all the unique namespaces to the templates in those namespaces.
    SetMultimap<String, String> namespaceToTemplates = TreeMultimap.create();
    for (String call : calls) {
        namespaceToTemplates.put(call.substring(0, call.lastIndexOf('.')), call);
    }
    for (String namespace : namespaceToTemplates.keySet()) {
        // Skip the file's own namespace as there is nothing to import/alias.
        if (namespace.equals(soyFile.getNamespace())) {
            continue;
        }
        // Add a require of the module
        String namespaceAlias = "$import" + counter++;
        String importNamespace = getGoogModuleNamespace(namespace);
        jsCodeBuilder.append(VariableDeclaration.builder(namespaceAlias).setRhs(GOOG_REQUIRE.call(stringLiteral(importNamespace))).build());
        // Alias all the templates used from the module
        for (String fullyQualifiedName : namespaceToTemplates.get(namespace)) {
            String alias = templateAliases.get(fullyQualifiedName);
            String shortName = fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.'));
            jsCodeBuilder.append(VariableDeclaration.builder(alias).setRhs(dottedIdNoRequire(namespaceAlias + shortName)).build());
        }
    }
}
Also used : CallBasicNode(com.google.template.soy.soytree.CallBasicNode) HashSet(java.util.HashSet)

Example 5 with CallBasicNode

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

the class AliasUtils method createTemplateAliases.

/**
 * Creates a mapping for assigning and looking up the variable alias for templates both within a
 * file and referenced from external files. For local files, the alias is just the local
 * template's name. For external templates, the alias is an identifier that is unique for that
 * template.
 *
 * <p>For V1 templates, no alias is generated and the template should be called by the fully
 * qualified name.
 *
 * @param fileNode The {@link SoyFileNode} to create an alias mapping for.
 * @return A {@link TemplateAliases} to look up aliases with.
 */
static TemplateAliases createTemplateAliases(SoyFileNode fileNode) {
    Map<String, String> aliasMap = new HashMap<>();
    Set<String> localTemplates = new HashSet<>();
    int counter = 0;
    // Go through templates first and just alias them to their local name.
    for (TemplateBasicNode templateBasicNode : SoyTreeUtils.getAllNodesOfType(fileNode, TemplateBasicNode.class)) {
        String partialName = templateBasicNode.getPartialTemplateName();
        String fullyQualifiedName = templateBasicNode.getTemplateName();
        localTemplates.add(fullyQualifiedName);
        Preconditions.checkState(partialName != null, "Aliasing not supported for V1 templates");
        // Need to start the alias with something that cannot be a part of a reserved
        // JavaScript identifier like 'function' or 'catch'.
        String alias = "$" + partialName.substring(1);
        aliasMap.put(fullyQualifiedName, alias);
    }
    // Go through all call sites looking for foreign template calls and create an alias for them.
    for (CallBasicNode callBasicNode : SoyTreeUtils.getAllNodesOfType(fileNode, CallBasicNode.class)) {
        String fullyQualifiedName = callBasicNode.getCalleeName();
        // to a local template.
        if (localTemplates.contains(fullyQualifiedName) || aliasMap.containsKey(fullyQualifiedName)) {
            continue;
        }
        String alias = TEMPLATE_ALIAS_PREFIX + (++counter);
        aliasMap.put(fullyQualifiedName, alias);
    }
    return new Aliases(aliasMap);
}
Also used : TemplateBasicNode(com.google.template.soy.soytree.TemplateBasicNode) HashMap(java.util.HashMap) CallBasicNode(com.google.template.soy.soytree.CallBasicNode) HashSet(java.util.HashSet)

Aggregations

CallBasicNode (com.google.template.soy.soytree.CallBasicNode)8 CallDelegateNode (com.google.template.soy.soytree.CallDelegateNode)3 Test (org.junit.Test)3 StandaloneNode (com.google.template.soy.soytree.SoyNode.StandaloneNode)2 HashSet (java.util.HashSet)2 SanitizedContentKind (com.google.template.soy.base.internal.SanitizedContentKind)1 ErrorReporter (com.google.template.soy.error.ErrorReporter)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 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 FindCalleesNotInFileVisitor (com.google.template.soy.shared.internal.FindCalleesNotInFileVisitor)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