use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.
the class GenPyCallExprVisitor method escapeCall.
/**
* Escaping directives might apply to the output of the call node, so wrap the output with all
* required directives.
*
* @param callExpr The expression text of the call itself.
* @param directives The list of the directives to be applied to the call.
* @return A PyExpr containing the call expression with all directives applied.
*/
private PyExpr escapeCall(String callExpr, ImmutableList<SoyPrintDirective> directives) {
PyExpr escapedExpr = new PyExpr(callExpr, Integer.MAX_VALUE);
if (directives.isEmpty()) {
return escapedExpr;
}
// Successively wrap each escapedExpr in various directives.
for (SoyPrintDirective directive : directives) {
Preconditions.checkState(directive instanceof SoyPySrcPrintDirective, "Autoescaping produced a bogus directive: %s", directive.getName());
escapedExpr = ((SoyPySrcPrintDirective) directive).applyForPySrc(escapedExpr, ImmutableList.<PyExpr>of());
}
return escapedExpr;
}
use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.
the class GenPyExprsVisitor method visitMsgFallbackGroupNode.
@Override
protected void visitMsgFallbackGroupNode(MsgFallbackGroupNode node) {
PyExpr msg = generateMsgFunc(node.getMsg());
// MsgFallbackGroupNode could only have one child or two children. See MsgFallbackGroupNode.
if (node.hasFallbackMsg()) {
StringBuilder pyExprTextSb = new StringBuilder();
PyExpr fallbackMsg = generateMsgFunc(node.getFallbackMsg());
// Build Python ternary expression: a if cond else c
pyExprTextSb.append(msg.getText()).append(" if ");
// The fallback message is only used if the first message is not available, but the fallback
// is. So availability of both messages must be tested.
long firstId = MsgUtils.computeMsgIdForDualFormat(node.getMsg());
long secondId = MsgUtils.computeMsgIdForDualFormat(node.getFallbackMsg());
pyExprTextSb.append(PyExprUtils.TRANSLATOR_NAME).append(".is_msg_available(").append(firstId).append(")").append(" or not ").append(PyExprUtils.TRANSLATOR_NAME).append(".is_msg_available(").append(secondId).append(")");
pyExprTextSb.append(" else ").append(fallbackMsg.getText());
msg = new PyStringExpr(pyExprTextSb.toString(), PyExprUtils.pyPrecedenceForOperator(Operator.CONDITIONAL));
}
// Escaping directives apply to messages, especially in attribute context.
for (SoyPrintDirective directive : node.getEscapingDirectives()) {
Preconditions.checkState(directive instanceof SoyPySrcPrintDirective, "Contextual autoescaping produced a bogus directive: %s", directive.getName());
msg = ((SoyPySrcPrintDirective) directive).applyForPySrc(msg, ImmutableList.<PyExpr>of());
}
pyExprs.add(msg);
}
use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.
the class PerformDeprecatedNonContextualAutoescapeVisitor method visitPrintNode.
@Override
protected void visitPrintNode(PrintNode node) {
if (autoescapeMode != AutoescapeMode.NONCONTEXTUAL) {
// that this pass is never used without first running the contextual autoescaper.
if (node.getChildren().isEmpty()) {
throw new IllegalStateException(String.format("Internal error: A contextual or strict template has a print node that was never " + "assigned any escape directives: %s at %s", node.toSourceString(), node.getSourceLocation()));
}
return;
}
// Traverse the list to (a) record whether we saw any directive that cancels autoescape
// (including 'noAutoescape' of course) and (b) remove 'noAutoescape' directives.
boolean shouldCancelAutoescape = false;
for (PrintDirectiveNode directiveNode : ImmutableList.copyOf(node.getChildren())) {
SoyPrintDirective directive = directiveNode.getPrintDirective();
if (directive != null && directive.shouldCancelAutoescape()) {
shouldCancelAutoescape = true;
break;
}
}
// ideally should migrate off of deprecated-noncontextual autoescape.
if (autoescapeMode == AutoescapeMode.NONCONTEXTUAL && !shouldCancelAutoescape) {
PrintDirectiveNode newEscapeHtmlDirectiveNode = new PrintDirectiveNode(nodeIdGen.genId(), node.getSourceLocation(), ImmutableList.<ExprNode>of(), new EscapeHtmlDirective(), /* isSynthetic= */
true);
node.addChild(0, newEscapeHtmlDirectiveNode);
}
}
use of com.google.template.soy.shared.restricted.SoyPrintDirective 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);
}
use of com.google.template.soy.shared.restricted.SoyPrintDirective in project closure-templates by google.
the class SoyNodeCompiler method visitMsgFallbackGroupNode.
/**
* MsgFallbackGroupNodes have either one or two children. In the 2 child case the second child is
* the {@code {fallbackmsg}} entry. For this we generate code that looks like:
*
* <pre>{@code
* if (renderContext.hasMsg(primaryId)) {
* <render primary msg>
* } else {
* <render fallback msg>
* }
* }</pre>
*
* <p>All of the logic for actually rendering {@code msg} nodes is handled by the {@link
* MsgCompiler}.
*/
@Override
protected Statement visitMsgFallbackGroupNode(MsgFallbackGroupNode node) {
MsgNode msg = node.getMsg();
MsgPartsAndIds idAndParts = MsgUtils.buildMsgPartsAndComputeMsgIdForDualFormat(msg);
ImmutableList<SoyPrintDirective> escapingDirectives = node.getEscapingDirectives();
Statement renderDefault = getMsgCompiler().compileMessage(idAndParts, msg, escapingDirectives);
// need to check for presence.
if (node.hasFallbackMsg()) {
MsgNode fallback = node.getFallbackMsg();
MsgPartsAndIds fallbackIdAndParts = MsgUtils.buildMsgPartsAndComputeMsgIdForDualFormat(fallback);
// TODO(lukes): consider changing the control flow here by 'inlining' the usePrimaryMsg logic
// it would save some lookups. Right now we will do to 2- 3 calls to
// SoyMsgBundle.getMsgParts (each of which requires a binary search). We could reduce that
// to 1-2 in the worse case by inlining and storing the lists in local variables.
IfBlock ifAvailableRenderDefault = IfBlock.create(parameterLookup.getRenderContext().usePrimaryMsg(idAndParts.id, fallbackIdAndParts.id), renderDefault);
return ControlFlow.ifElseChain(ImmutableList.of(ifAvailableRenderDefault), Optional.of(getMsgCompiler().compileMessage(fallbackIdAndParts, fallback, escapingDirectives)));
} else {
return renderDefault;
}
}
Aggregations