use of com.google.template.soy.soytree.CallDelegateNode 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.soytree.CallDelegateNode 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);
}
use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.
the class BytecodeCompilerTest method testDelCallEscaping_separateCompilation.
// Tests for a bug where we would overescape deltemplates at the call site when the strict
// content kind of the deltemplate was unknown at compile time.
@Test
public void testDelCallEscaping_separateCompilation() throws IOException {
String soyFileContent1 = Joiner.on("\n").join("{namespace ns}", "", "{template .callerTemplate}", " {delcall myApp.myDelegate/}", "{/template}", "");
SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(soyFileContent1).parse().fileSet();
// apply an escaping directive to the callsite, just like the autoescaper would
CallDelegateNode cdn = SoyTreeUtils.getAllNodesOfType(soyTree.getChild(0), CallDelegateNode.class).get(0);
cdn.setEscapingDirectives(ImmutableList.of(new EscapeHtmlDirective()));
TemplateRegistry templateRegistry = new TemplateRegistry(soyTree, ErrorReporter.exploding());
CompiledTemplates templates = BytecodeCompiler.compile(templateRegistry, false, ErrorReporter.exploding()).get();
CompiledTemplate.Factory caller = templates.getTemplateFactory("ns.callerTemplate");
try {
renderWithContext(caller, getDefaultContext(templates));
fail();
} catch (IllegalArgumentException iae) {
assertThat(iae).hasMessageThat().isEqualTo("Found no active impl for delegate call to \"myApp.myDelegate\" (and delcall does " + "not set allowemptydefault=\"true\").");
}
String soyFileContent2 = Joiner.on("\n").join("{namespace ns2}", "", "{deltemplate myApp.myDelegate}", " <span>Hello</span>", "{/deltemplate}", "");
CompiledTemplates templatesWithDeltemplate = compileFiles(soyFileContent2);
// By passing an alternate context, we ensure the deltemplate selector contains the delegate
assertThat(renderWithContext(caller, getDefaultContext(templatesWithDeltemplate))).isEqualTo("<span>Hello</span>");
}
use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.
the class TemplateParserTest method testParseCallStmtWithPhname.
@SuppressWarnings({ "ConstantConditions" })
@Test
public void testParseCallStmtWithPhname() throws Exception {
String templateBody = "{@param animals:?}\n" + "{msg desc=\"...\"}\n" + " {call .booTemplate_ phname=\"booTemplate_\" /}\n" + " {call .booTemplate_ phname=\"booTemplate_\" /}\n" + " {delcall MySecretFeature.zooTemplate data=\"$animals\" phname=\"secret_zoo\"}\n" + " {param zoo: 0 /}\n" + " {/delcall}\n" + "{/msg}";
List<StandaloneNode> nodes = ((MsgFallbackGroupNode) parseTemplateContent(templateBody, FAIL).getChild(0)).getChild(0).getChildren();
assertEquals(3, nodes.size());
CallBasicNode cn0 = (CallBasicNode) ((MsgPlaceholderNode) nodes.get(0)).getChild(0);
assertEquals("BOO_TEMPLATE", cn0.genBasePhName());
assertEquals("brittle.test.ns.booTemplate_", cn0.getCalleeName());
assertEquals(".booTemplate_", cn0.getSourceCalleeName());
assertEquals(false, cn0.isPassingData());
assertEquals(false, cn0.isPassingAllData());
assertEquals(null, cn0.getDataExpr());
assertEquals(0, cn0.numChildren());
CallBasicNode cn1 = (CallBasicNode) ((MsgPlaceholderNode) nodes.get(1)).getChild(0);
CallDelegateNode cn2 = (CallDelegateNode) ((MsgPlaceholderNode) nodes.get(2)).getChild(0);
assertEquals("SECRET_ZOO", cn2.genBasePhName());
assertEquals("MySecretFeature.zooTemplate", cn2.getDelCalleeName());
assertEquals(true, cn2.isPassingData());
assertEquals(false, cn2.isPassingAllData());
assertTrue(cn2.getDataExpr().getRoot() != null);
assertEquals("$animals", cn2.getDataExpr().toSourceString());
assertEquals(1, cn2.numChildren());
// CallNodes are never same
assertFalse(cn0.genSamenessKey().equals(cn1.genSamenessKey()));
assertFalse(cn2.genSamenessKey().equals(cn0.genSamenessKey()));
}
use of com.google.template.soy.soytree.CallDelegateNode in project closure-templates by google.
the class TemplateParserTest method testParseDelegateCallStmt.
@SuppressWarnings({ "ConstantConditions" })
@Test
public void testParseDelegateCallStmt() throws Exception {
String templateBody = "{@param animals : ?}{@param too : ?}\n" + " {delcall booTemplate /}\n" + " {delcall foo.goo.mooTemplate data=\"all\" /}\n" + " {delcall MySecretFeature.zooTemplate data=\"$animals\"}\n" + " {param yoo: round($too) /}\n" + " {param woo kind=\"html\"}poo{/param}\n" + " {/delcall}\n";
List<StandaloneNode> nodes = parseTemplateContent(templateBody, FAIL).getChildren();
assertEquals(3, nodes.size());
CallDelegateNode cn0 = (CallDelegateNode) nodes.get(0);
assertEquals("booTemplate", cn0.getDelCalleeName());
assertEquals(false, cn0.isPassingData());
assertEquals(false, cn0.isPassingAllData());
assertEquals(null, cn0.getDataExpr());
assertEquals("XXX", cn0.genBasePhName());
assertEquals(0, cn0.numChildren());
CallDelegateNode cn1 = (CallDelegateNode) nodes.get(1);
assertEquals("foo.goo.mooTemplate", cn1.getDelCalleeName());
assertEquals(true, cn1.isPassingData());
assertEquals(true, cn1.isPassingAllData());
assertEquals(null, cn1.getDataExpr());
assertFalse(cn1.genSamenessKey().equals(cn0.genSamenessKey()));
assertEquals(0, cn1.numChildren());
CallDelegateNode cn2 = (CallDelegateNode) nodes.get(2);
assertEquals("MySecretFeature.zooTemplate", cn2.getDelCalleeName());
assertEquals(true, cn2.isPassingData());
assertEquals(false, cn2.isPassingAllData());
assertTrue(cn2.getDataExpr().getRoot() != null);
assertEquals("$animals", cn2.getDataExpr().toSourceString());
assertEquals(2, cn2.numChildren());
CallParamValueNode cn2cpvn0 = (CallParamValueNode) cn2.getChild(0);
assertEquals("yoo", cn2cpvn0.getKey().identifier());
assertEquals("round($too)", cn2cpvn0.getExpr().toSourceString());
assertTrue(cn2cpvn0.getExpr().getRoot() instanceof FunctionNode);
CallParamContentNode cn2cpcn1 = (CallParamContentNode) cn2.getChild(1);
assertEquals("woo", cn2cpcn1.getKey().identifier());
assertEquals("poo", ((RawTextNode) cn2cpcn1.getChild(0)).getRawText());
}
Aggregations