Search in sources :

Example 1 with SoyPrintDirective

use of com.google.template.soy.shared.restricted.SoyPrintDirective 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 SoyPrintDirective

use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.

the class RemoveUnnecessaryEscapingDirectives method filterEscapingDirectives.

private static ImmutableList<SoyPrintDirective> filterEscapingDirectives(ImmutableList<SoyPrintDirective> escapingDirectives) {
    for (int i = 0; i < escapingDirectives.size(); i++) {
        SoyPrintDirective directive = escapingDirectives.get(i);
        if (canSkip(directive)) {
            ImmutableList.Builder<SoyPrintDirective> builder = ImmutableList.builder();
            builder.addAll(escapingDirectives.subList(0, i));
            for (; i < escapingDirectives.size(); i++) {
                directive = escapingDirectives.get(i);
                if (!canSkip(directive)) {
                    builder.add(directive);
                }
            }
            return builder.build();
        }
    }
    return escapingDirectives;
}
Also used : SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) ImmutableList(com.google.common.collect.ImmutableList)

Example 3 with SoyPrintDirective

use of com.google.template.soy.shared.restricted.SoyPrintDirective 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)

Example 4 with SoyPrintDirective

use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.

the class RenderVisitor method visitMsgFallbackGroupNode.

@Override
protected void visitMsgFallbackGroupNode(MsgFallbackGroupNode node) {
    if (assistantForMsgs == null) {
        assistantForMsgs = new RenderVisitorAssistantForMsgs(this, msgBundle);
    }
    if (!node.getEscapingDirectives().isEmpty()) {
        // The entire message needs to be escaped, so we need to render to a temporary buffer.
        // Fortunately, for most messages (in HTML context) this is unnecessary.
        pushOutputBuf(new StringBuilder());
    }
    assistantForMsgs.visitForUseByMaster(node);
    if (!node.getEscapingDirectives().isEmpty()) {
        // Escape the entire message with the required directives.
        SoyValue wholeMsg = StringData.forValue(popOutputBuf().toString());
        for (SoyPrintDirective directive : node.getEscapingDirectives()) {
            wholeMsg = applyDirective(directive, wholeMsg, ImmutableList.<SoyValue>of(), node);
        }
        append(currOutputBuf, wholeMsg.stringValue());
    }
}
Also used : SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) SoyValue(com.google.template.soy.data.SoyValue)

Example 5 with SoyPrintDirective

use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.

the class RenderVisitor method visitCallNodeHelper.

// for IntelliJ
@SuppressWarnings("ConstantConditions")
private void visitCallNodeHelper(CallNode node, TemplateNode callee) {
    // ------ Build the call data. ------
    SoyRecord dataToPass;
    if (node.isPassingAllData()) {
        dataToPass = data;
    } else if (node.isPassingData()) {
        SoyValue dataRefValue = eval(node.getDataExpr(), node);
        if (!(dataRefValue instanceof SoyRecord)) {
            throw RenderException.create("In 'call' command " + node.toSourceString() + ", the data reference does not resolve to a SoyRecord.").addStackTraceElement(node);
        }
        dataToPass = (SoyRecord) dataRefValue;
    } else {
        dataToPass = null;
    }
    SoyRecord callData;
    int numChildren = node.numChildren();
    if (numChildren == 0) {
        // --- Cases 1 and 2: Not passing params. ---
        if (dataToPass == null) {
            // Case 1: Not passing data and not passing params.
            callData = ParamStore.EMPTY_INSTANCE;
        } else {
            // Case 2: Passing data and not passing params.
            callData = dataToPass;
        }
    } else {
        // --- Cases 3 and 4: Passing params. ---
        ParamStore mutableCallData;
        if (dataToPass == null) {
            // Case 3: Not passing data and passing params.
            mutableCallData = new BasicParamStore(numChildren);
        } else {
            // Case 4: Passing data and passing params.
            mutableCallData = new AugmentedParamStore(dataToPass, numChildren);
        }
        for (CallParamNode child : node.getChildren()) {
            if (child instanceof CallParamValueNode) {
                mutableCallData.setField(child.getKey().identifier(), lazyEval(((CallParamValueNode) child).getExpr(), child));
            } else if (child instanceof CallParamContentNode) {
                mutableCallData.setField(child.getKey().identifier(), renderRenderUnitNode((CallParamContentNode) child));
            } else {
                throw new AssertionError();
            }
        }
        callData = mutableCallData;
    }
    if (node.getEscapingDirectives().isEmpty()) {
        // No escaping at the call site -- render directly into the output buffer.
        RenderVisitor rv = this.createHelperInstance(currOutputBuf, callData);
        try {
            rv.renderTemplate(callee, node.getParamsToRuntimeCheck(callee));
        } catch (RenderException re) {
            // this template call.
            throw re.addStackTraceElement(node);
        }
    } else {
        // Escaping the call site's result, such as at a strict template boundary.
        // TODO: Some optimization is needed here before Strict Soy can be widely used:
        // - Only create this temporary buffer when contexts mismatch. We could run a pre-pass that
        // eliminates escaping directives when all callers are known.
        // - Instead of creating a temporary buffer and copying, wrap with an escaping StringBuilder.
        StringBuilder calleeBuilder = new StringBuilder();
        RenderVisitor rv = this.createHelperInstance(calleeBuilder, callData);
        try {
            rv.renderTemplate(callee, node.getParamsToRuntimeCheck(callee));
        } catch (RenderException re) {
            // this template call.
            throw re.addStackTraceElement(node);
        }
        ContentKind calleeKind = fromSanitizedContentKind(callee.getContentKind());
        SoyValue resultData = calleeKind != null ? UnsafeSanitizedContentOrdainer.ordainAsSafe(calleeBuilder.toString(), calleeKind) : StringData.forValue(calleeBuilder.toString());
        for (SoyPrintDirective directive : node.getEscapingDirectives()) {
            resultData = applyDirective(directive, resultData, ImmutableList.<SoyValue>of(), node);
        }
        append(currOutputBuf, resultData, node);
    }
}
Also used : SoyRecord(com.google.template.soy.data.SoyRecord) CallParamNode(com.google.template.soy.soytree.CallParamNode) CallParamValueNode(com.google.template.soy.soytree.CallParamValueNode) SoyValue(com.google.template.soy.data.SoyValue) BasicParamStore(com.google.template.soy.data.internal.BasicParamStore) AugmentedParamStore(com.google.template.soy.data.internal.AugmentedParamStore) CallParamContentNode(com.google.template.soy.soytree.CallParamContentNode) SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) ParamStore(com.google.template.soy.data.internal.ParamStore) AugmentedParamStore(com.google.template.soy.data.internal.AugmentedParamStore) BasicParamStore(com.google.template.soy.data.internal.BasicParamStore) ContentKind(com.google.template.soy.data.SanitizedContent.ContentKind) SanitizedContentKind(com.google.template.soy.base.internal.SanitizedContentKind)

Aggregations

SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)18 CodeChunk (com.google.template.soy.jssrc.dsl.CodeChunk)4 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)3 SoyJsSrcPrintDirective (com.google.template.soy.jssrc.restricted.SoyJsSrcPrintDirective)3 PyExpr (com.google.template.soy.pysrc.restricted.PyExpr)3 SoyPySrcPrintDirective (com.google.template.soy.pysrc.restricted.SoyPySrcPrintDirective)3 PrintDirectiveNode (com.google.template.soy.soytree.PrintDirectiveNode)3 ArrayList (java.util.ArrayList)3 ImmutableSet (com.google.common.collect.ImmutableSet)2 SoyValue (com.google.template.soy.data.SoyValue)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 LinkedHashMap (java.util.LinkedHashMap)2 Set (java.util.Set)2 Test (org.junit.Test)2 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 SanitizedContentKind (com.google.template.soy.base.internal.SanitizedContentKind)1 UniqueNameGenerator (com.google.template.soy.base.internal.UniqueNameGenerator)1