use of com.google.template.soy.soytree.LetContentNode in project closure-templates by google.
the class VeLogInstrumentationVisitor method visitHtmlAttributeNode.
/**
* For HtmlAttributeNode that has a logging function as its value, replace the logging function
* with its place holder, and append a new data attribute that contains all the desired
* information that are used later by the runtime library.
*/
@Override
protected void visitHtmlAttributeNode(HtmlAttributeNode node) {
// Skip attributes that do not have a value.
if (!node.hasValue()) {
return;
}
SourceLocation insertionLocation = node.getSourceLocation();
for (FunctionNode function : SoyTreeUtils.getAllNodesOfType(node, FunctionNode.class)) {
if (!(function.getSoyFunction() instanceof LoggingFunction)) {
continue;
}
FunctionNode funcNode = new FunctionNode(VeLogJsSrcLoggingFunction.INSTANCE, insertionLocation);
funcNode.addChild(new StringNode(function.getFunctionName(), QuoteStyle.SINGLE, insertionLocation));
funcNode.addChild(new ListLiteralNode(function.getChildren(), insertionLocation));
StandaloneNode attributeName = node.getChild(0);
if (attributeName instanceof RawTextNode) {
// If attribute name is a plain text, directly pass it as a function argument.
funcNode.addChild(new StringNode(((RawTextNode) attributeName).getRawText(), QuoteStyle.SINGLE, insertionLocation));
} else {
// Otherwise wrap the print node or call node into a let block, and use the let variable
// as a function argument.
String varName = "soy_logging_function_attribute_" + counter;
LetContentNode letNode = LetContentNode.forVariable(nodeIdGen.genId(), attributeName.getSourceLocation(), varName, null);
// Adds a let var which references to the original attribute name, and move the name to
// the let block.
node.replaceChild(attributeName, new PrintNode(nodeIdGen.genId(), insertionLocation, /* isImplicit= */
true, /* expr= */
new VarRefNode(varName, insertionLocation, false, letNode.getVar()), /* attributes= */
ImmutableList.of(), ErrorReporter.exploding()));
letNode.addChild(attributeName);
node.getParent().addChild(node.getParent().getChildIndex(node), letNode);
funcNode.addChild(new VarRefNode(varName, insertionLocation, false, letNode.getVar()));
}
funcNode.addChild(new IntegerNode(counter++, insertionLocation));
PrintNode loggingFunctionAttribute = new PrintNode(nodeIdGen.genId(), insertionLocation, /* isImplicit= */
true, /* expr= */
funcNode, /* attributes= */
ImmutableList.of(), ErrorReporter.exploding());
// Append the logging function attribute to its parent
int appendIndex = node.getParent().getChildIndex(node) + 1;
node.getParent().addChild(appendIndex, loggingFunctionAttribute);
// Replace the original attribute value to the placeholder.
HtmlAttributeValueNode placeHolder = new HtmlAttributeValueNode(nodeIdGen.genId(), insertionLocation, Quotes.DOUBLE);
placeHolder.addChild(new RawTextNode(nodeIdGen.genId(), ((LoggingFunction) function.getSoyFunction()).getPlaceholder(), insertionLocation));
node.replaceChild(node.getChild(1), placeHolder);
// logging function in a html attribute value.
break;
}
visitChildren(node);
}
use of com.google.template.soy.soytree.LetContentNode in project closure-templates by google.
the class TemplateParserTest method testParseLetStmt.
@Test
public void testParseLetStmt() throws Exception {
String templateBody = "{@param boo : ?}\n" + " {let $alpha: $boo.foo /}\n" + " {let $beta kind=\"html\"}Boo!{/let}\n" + " {let $gamma kind=\"html\"}\n" + " {for $i in range($alpha)}\n" + " {$i}{$beta}\n" + " {/for}\n" + " {/let}\n" + " {let $delta kind=\"html\"}Boo!{/let}\n";
List<StandaloneNode> nodes = parseTemplateContent(templateBody, FAIL).getChildren();
assertEquals(4, nodes.size());
LetValueNode alphaNode = (LetValueNode) nodes.get(0);
assertEquals("alpha", alphaNode.getVarName());
assertEquals("$boo.foo", alphaNode.getExpr().toSourceString());
LetContentNode betaNode = (LetContentNode) nodes.get(1);
assertEquals("beta", betaNode.getVarName());
assertEquals("Boo!", ((RawTextNode) betaNode.getChild(0)).getRawText());
assertEquals(SanitizedContentKind.HTML, betaNode.getContentKind());
LetContentNode gammaNode = (LetContentNode) nodes.get(2);
assertEquals("gamma", gammaNode.getVarName());
assertThat(gammaNode.getChild(0)).isInstanceOf(ForNode.class);
assertEquals(SanitizedContentKind.HTML, gammaNode.getContentKind());
LetContentNode deltaNode = (LetContentNode) nodes.get(3);
assertEquals("delta", deltaNode.getVarName());
assertEquals("Boo!", ((RawTextNode) betaNode.getChild(0)).getRawText());
assertEquals(SanitizedContentKind.HTML, deltaNode.getContentKind());
// Test error case.
TemplateSubject.assertThatTemplateContent("{let $alpha /}{/let}").causesError("parse error at '/}': expected }, ':', or identifier").at(1, 13);
// Test error case.
TemplateSubject.assertThatTemplateContent("{let $alpha: $boo.foo}{/let}").causesError("parse error at '}': expected /}, ?, '?:', or, and, ==, !=, <, >, <=, >=, +, -, *, /, " + "%, ., ?., [, or ?[").at(1, 22);
}
use of com.google.template.soy.soytree.LetContentNode in project closure-templates by google.
the class ResolveNamesVisitorTest method testLetContentSlotLifetime.
@Test
public void testLetContentSlotLifetime() {
SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(constructTemplateSource("{let $a kind=\"text\"}", // introduce an extra scope
" {if true}", " {let $b: 2 /}", " {$b}", " {/if}", "{/let}", "{$a}")).parse().fileSet();
new ResolveNamesVisitor(ErrorReporter.exploding()).exec(soyTree);
TemplateNode n = soyTree.getChild(0).getChild(0);
// 1 because each new $la binding overwrites the prior one
assertThat(n.getMaxLocalVariableTableSize()).isEqualTo(2);
LetContentNode aLetNode = (LetContentNode) n.getChild(0);
assertThat(aLetNode.getVar().localVariableIndex()).isEqualTo(1);
LetValueNode bLetNode = (LetValueNode) ((IfCondNode) ((IfNode) aLetNode.getChild(0)).getChild(0)).getChild(0);
assertThat(bLetNode.getVar().localVariableIndex()).isEqualTo(0);
}
Aggregations