use of com.google.template.soy.jssrc.dsl.CodeChunk 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<n>' 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<n>'.
*
* @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());
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenJsCodeVisitorAssistantForMsgs method generateMsgGroupVariable.
/**
* Returns a code chunk representing a variable declaration for an {@link MsgFallbackGroupNode}
* that contains fallback(s).
*/
private CodeChunk.WithValue generateMsgGroupVariable(MsgFallbackGroupNode node, String tmpVarName) {
checkState(node.numChildren() == 2);
// Generate the goog.getMsg calls for all children.
GoogMsgCodeGenInfo primaryCodeGenInfo = genGoogGetMsgCallHelper(buildGoogMsgVarNameHelper(node.getChild(0)), node.getChild(0));
GoogMsgCodeGenInfo fallbackCodeGenInfo = genGoogGetMsgCallHelper(buildGoogMsgVarNameHelper(node.getChild(1)), node.getChild(1));
// Declare a temporary variable to hold the getMsgWithFallback() call so that we can apply any
// MessageFormats from any of the fallbacks. This is also the variable name that we return to
// the caller.
CodeChunk.WithValue selectedMsg = VariableDeclaration.builder(tmpVarName).setRhs(CodeChunk.dottedIdNoRequire("goog.getMsgWithFallback").call(primaryCodeGenInfo.googMsgVar, fallbackCodeGenInfo.googMsgVar)).build().ref();
// We use id() here instead of using the corresponding code chunks because the stupid
// jscodebuilder system causes us to regenerate the msg vars multiple times because it doesn't
// detect that they were already generated.
// TODO(b/33382980): clean this up
CodeChunk.WithValue isPrimaryMsgInUse = CodeChunk.id(tmpVarName).doubleEquals(CodeChunk.id(primaryCodeGenInfo.googMsgVarName));
translationContext.soyToJsVariableMappings().setIsPrimaryMsgInUse(node, isPrimaryMsgInUse);
if (primaryCodeGenInfo.placeholders == null && fallbackCodeGenInfo.placeholders == null) {
// all placeholders have already been substituted, just return
return selectedMsg;
}
// Generate the goog.i18n.MessageFormat calls for child plural/select messages (if any), each
// wrapped in an if-block that will only execute if that child is the chosen message.
CodeChunk condition;
if (primaryCodeGenInfo.placeholders != null) {
ConditionalBuilder builder = CodeChunk.ifStatement(selectedMsg.doubleEquals(primaryCodeGenInfo.googMsgVar), selectedMsg.assign(getMessageFormatCall(primaryCodeGenInfo)));
if (fallbackCodeGenInfo.placeholders != null) {
builder.else_(selectedMsg.assign(getMessageFormatCall(fallbackCodeGenInfo)));
}
condition = builder.build();
} else {
condition = CodeChunk.ifStatement(selectedMsg.doubleEquals(fallbackCodeGenInfo.googMsgVar), selectedMsg.assign(getMessageFormatCall(fallbackCodeGenInfo))).build();
}
return CodeChunk.id(tmpVarName).withInitialStatement(condition);
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenJsCodeVisitor method handleForeachLoop.
/**
* Example:
*
* <pre>
* {for $foo in $boo.foos}
* ...
* {/for}
* </pre>
*
* might generate
*
* <pre>
* for (var foo2Index = 0; foo2Index < foo2ListLen; foo2Index++) {
* var foo2Data = foo2List[foo2Index];
* ...
* }
* </pre>
*/
private CodeChunk handleForeachLoop(ForNonemptyNode node, CodeChunk.WithValue limit, Function<CodeChunk.WithValue, CodeChunk.WithValue> getDataItemFunction) {
// Build some local variable names.
String varName = node.getVarName();
String varPrefix = varName + node.getForNodeId();
// TODO(user): A more consistent pattern for local variable management.
String loopIndexName = varPrefix + "Index";
String dataName = varPrefix + "Data";
CodeChunk.WithValue loopIndex = id(loopIndexName);
VariableDeclaration data = VariableDeclaration.builder(dataName).setRhs(getDataItemFunction.apply(loopIndex)).build();
// Populate the local var translations with the translations from this node.
templateTranslationContext.soyToJsVariableMappings().put(varName, id(dataName)).put(varName + "__isFirst", loopIndex.doubleEquals(number(0))).put(varName + "__isLast", loopIndex.doubleEquals(limit.minus(number(1)))).put(varName + "__index", loopIndex);
// Generate the loop body.
CodeChunk foreachBody = CodeChunk.statements(data, visitChildrenReturningCodeChunk(node));
// Create the entire for block.
return forLoop(loopIndexName, limit, foreachBody);
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenJsCodeVisitor method doVisitReturningCodeChunk.
/**
* Do not use directly; use {@link #visitChildrenReturningCodeChunk} or {@link
* #visitNodeReturningCodeChunk} instead.
*/
private CodeChunk doVisitReturningCodeChunk(SoyNode node, boolean visitChildren) {
// Replace jsCodeBuilder with a child JsCodeBuilder.
JsCodeBuilder original = jsCodeBuilder;
jsCodeBuilder = createChildJsCodeBuilder();
// Visit body.
// set indent to 0 since when rendering the CodeChunk, everything will get re-indented
jsCodeBuilder.setIndent(0);
if (visitChildren) {
visitChildren((ParentSoyNode<?>) node);
} else {
visit(node);
}
CodeChunk chunk = CodeChunk.treatRawStringAsStatementLegacyOnly(jsCodeBuilder.getCode(), jsCodeBuilder.googRequires());
jsCodeBuilder = original;
return chunk;
}
use of com.google.template.soy.jssrc.dsl.CodeChunk in project closure-templates by google.
the class GenJsCodeVisitor method generateNonExpressionIfNode.
/**
* Generates the JavaScript code for an {if} block that cannot be done as an expression.
*
* <p>TODO(user): Instead of interleaving JsCodeBuilders like this, consider refactoring
* GenJsCodeVisitor to return CodeChunks for each sub-Template level SoyNode.
*/
protected void generateNonExpressionIfNode(IfNode node) {
ConditionalBuilder conditional = null;
for (SoyNode child : node.getChildren()) {
if (child instanceof IfCondNode) {
IfCondNode condNode = (IfCondNode) child;
// Convert predicate.
CodeChunk.WithValue predicate = translateExpr(condNode.getExpr());
// Convert body.
CodeChunk consequent = visitChildrenReturningCodeChunk(condNode);
// Add if-block to conditional.
if (conditional == null) {
conditional = ifStatement(predicate, consequent);
} else {
conditional.elseif_(predicate, consequent);
}
} else if (child instanceof IfElseNode) {
// Convert body.
CodeChunk trailingElse = visitChildrenReturningCodeChunk((IfElseNode) child);
// Add else-block to conditional.
conditional.else_(trailingElse);
} else {
throw new AssertionError();
}
}
jsCodeBuilder.append(conditional.build());
}
Aggregations