use of com.google.template.soy.jbcsrc.restricted.Statement 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.jbcsrc.restricted.Statement in project closure-templates by google.
the class MsgCompiler method addHtmlTagNodeToPlaceholderMap.
/**
* Returns a statement that adds the content of the node to the map.
*
* @param mapExpression The map to put the new entry in
* @param mapKey The map key
* @param htmlTagNode The node
*/
private Statement addHtmlTagNodeToPlaceholderMap(Expression mapExpression, String mapKey, MsgHtmlTagNode htmlTagNode) {
Optional<String> rawText = tryGetRawTextContent(htmlTagNode);
Statement putStatement;
if (rawText.isPresent()) {
putStatement = mapExpression.invoke(MethodRef.LINKED_HASH_MAP_PUT, constant(mapKey), constant(rawText.get())).toStatement();
} else {
Statement renderIntoBuffer = soyNodeCompiler.compileToBuffer(htmlTagNode, tempBuffer());
Statement putBuffer = putBufferIntoMapForPlaceholder(mapExpression, mapKey);
putStatement = Statement.concat(renderIntoBuffer, putBuffer);
}
return putStatement.withSourceLocation(htmlTagNode.getSourceLocation());
}
use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.
the class MsgCompiler method putPlaceholderIntoMap.
private void putPlaceholderIntoMap(Expression mapExpression, MsgNode originalMsg, Map<String, Statement> placeholderNameToPutStatement, SoyMsgPlaceholderPart placeholder) throws AssertionError {
String placeholderName = placeholder.getPlaceholderName();
if (!placeholderNameToPutStatement.containsKey(placeholderName)) {
MsgPlaceholderNode repPlaceholderNode = originalMsg.getRepPlaceholderNode(placeholder.getPlaceholderName());
if (repPlaceholderNode.numChildren() == 0) {
throw new IllegalStateException("empty rep node for: " + placeholderName);
}
StandaloneNode initialNode = repPlaceholderNode.getChild(0);
Statement putEntyInMap;
if (initialNode instanceof MsgHtmlTagNode) {
putEntyInMap = addHtmlTagNodeToPlaceholderMap(mapExpression, placeholderName, (MsgHtmlTagNode) initialNode);
} else if (initialNode instanceof CallNode) {
putEntyInMap = addCallNodeToPlaceholderMap(mapExpression, placeholderName, (CallNode) initialNode);
} else if (initialNode instanceof PrintNode) {
putEntyInMap = addPrintNodeToPlaceholderMap(mapExpression, placeholderName, (PrintNode) initialNode);
} else if (initialNode instanceof RawTextNode) {
putEntyInMap = addRawTextNodeToPlaceholderMap(mapExpression, placeholderName, (RawTextNode) initialNode);
} else {
// the AST for MsgNodes guarantee that these are the only options
throw new AssertionError("Unexpected child: " + initialNode.getClass());
}
placeholderNameToPutStatement.put(placeholder.getPlaceholderName(), putEntyInMap.withSourceLocation(repPlaceholderNode.getSourceLocation()));
}
}
use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.
the class PrintDirectives method applyStreamingPrintDirectivesTo.
private static AppendableAndOptions applyStreamingPrintDirectivesTo(List<DirectiveWithArgs> directivesToApply, Expression appendable, JbcSrcPluginContext context, TemplateVariableManager variableManager) {
final List<LocalVariable> closeables = new ArrayList<>();
final List<Variable> appendableVars = new ArrayList<>();
Scope scope = variableManager.enterScope();
AppendableAndOptions prev = AppendableAndOptions.create(appendable);
Variable prevVar = scope.createTemporary("tmp_appendable", appendable);
appendableVars.add(prevVar);
// appendable with the last directive first. so iterate in reverse order.
for (DirectiveWithArgs directiveToApply : Lists.reverse(directivesToApply)) {
AppendableAndOptions curr = directiveToApply.apply(context, prevVar.local());
Variable currVar = scope.createTemporary("tmp_appendable", curr.appendable());
appendableVars.add(currVar);
if (curr.closeable()) {
closeables.add(currVar.local());
}
prev = curr;
prevVar = currVar;
}
// Check if we need to apply a wrapper to make sure close propagates to all the right places
// this is necessary if there are multiple closeable wrappers.
final Expression appendableExpression;
final boolean closeable;
if (closeables.isEmpty()) {
appendableExpression = prev.appendable();
closeable = false;
} else if (closeables.size() == 1 && prev.closeable()) {
// there is exactly one closeable and it is first, we don't need a wrapper
appendableExpression = prev.appendable();
closeable = true;
} else {
// there is either more than one closeable, or it is not the first one, so we need a wrapper
// We need to reverse the list of closeables so that we close them in the correct order. for
// example, given '|foo|bar' we will first wrap the delegate with bar and then with foo but we
// need to close foo first.
appendableExpression = RUNTIME_PROPAGATE_CLOSE.invoke(Iterables.getLast(appendableVars).local(), BytecodeUtils.asImmutableList(Lists.reverse(closeables)));
closeable = true;
}
final Statement exitScope = scope.exitScope();
Expression result = new Expression(appendableExpression.resultType()) {
@Override
protected void doGen(CodeBuilder adapter) {
for (Variable var : appendableVars) {
var.initializer().gen(adapter);
}
appendableExpression.gen(adapter);
exitScope.gen(adapter);
}
};
if (closeable) {
return AppendableAndOptions.createCloseable(result);
} else {
return AppendableAndOptions.create(result);
}
}
use of com.google.template.soy.jbcsrc.restricted.Statement in project closure-templates by google.
the class SoyNodeCompiler method visitIfNode.
@Override
protected Statement visitIfNode(IfNode node) {
List<IfBlock> ifs = new ArrayList<>();
Optional<Statement> elseBlock = Optional.absent();
for (SoyNode child : node.getChildren()) {
if (child instanceof IfCondNode) {
IfCondNode icn = (IfCondNode) child;
SoyExpression cond = exprCompiler.compile(icn.getExpr()).coerceToBoolean();
Statement block = visitChildrenInNewScope(icn);
ifs.add(IfBlock.create(cond, block));
} else {
IfElseNode ien = (IfElseNode) child;
elseBlock = Optional.of(visitChildrenInNewScope(ien));
}
}
return ControlFlow.ifElseChain(ifs, elseBlock);
}
Aggregations