use of com.google.template.soy.soytree.SoyNode.StandaloneNode in project closure-templates by google.
the class TemplateParserTest method testParsePrintStmt.
@Test
public void testParsePrintStmt() throws Exception {
String templateBody = "{@param boo : ?}{@param goo : ?}\n" + " {$boo.foo}{$boo.foo}\n" + " {$goo + 1 |noAutoescape}\n" + " {print 'blah blahblahblah' |escapeHtml|insertWordBreaks:8}\n";
List<StandaloneNode> nodes = parseTemplateContent(templateBody, FAIL).getChildren();
assertEquals(4, nodes.size());
PrintNode pn0 = (PrintNode) nodes.get(0);
assertEquals("$boo.foo", pn0.getExpr().toSourceString());
assertEquals(0, pn0.getChildren().size());
assertEquals("FOO", pn0.genBasePhName());
assertEquals("{$boo.foo}", pn0.toSourceString());
assertTrue(pn0.getExpr().getRoot() instanceof FieldAccessNode);
PrintNode pn1 = (PrintNode) nodes.get(1);
assertTrue(pn0.genSamenessKey().equals(pn1.genSamenessKey()));
assertTrue(pn1.getExpr().getRoot() instanceof FieldAccessNode);
PrintNode pn2 = (PrintNode) nodes.get(2);
assertEquals("$goo + 1", pn2.getExpr().toSourceString());
assertEquals(1, pn2.getChildren().size());
PrintDirectiveNode pn2d0 = pn2.getChild(0);
assertEquals("|noAutoescape", pn2d0.getName());
assertEquals("XXX", pn2.genBasePhName());
assertTrue(pn2.getExpr().getRoot() instanceof PlusOpNode);
PrintNode pn3 = (PrintNode) nodes.get(3);
assertEquals("'blah blahblahblah'", pn3.getExpr().toSourceString());
assertEquals(2, pn3.getChildren().size());
PrintDirectiveNode pn3d0 = pn3.getChild(0);
assertEquals("|escapeHtml", pn3d0.getName());
PrintDirectiveNode pn3d1 = pn3.getChild(1);
assertEquals("|insertWordBreaks", pn3d1.getName());
assertEquals(8, ((IntegerNode) pn3d1.getArgs().get(0).getRoot()).getValue());
assertEquals("XXX", pn3.genBasePhName());
assertTrue(pn3.getExpr().getRoot() instanceof StringNode);
assertFalse(pn0.genSamenessKey().equals(pn2.genSamenessKey()));
assertFalse(pn3.genSamenessKey().equals(pn0.genSamenessKey()));
}
use of com.google.template.soy.soytree.SoyNode.StandaloneNode 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.SoyNode.StandaloneNode in project closure-templates by google.
the class InsertMsgsVisitor method buildReplacementNodesFromTranslation.
/**
* Private helper for visitMsgFallbackGroupNode() to build the list of replacement nodes for a
* message from its translation.
*/
private void buildReplacementNodesFromTranslation(MsgNode msg, SoyMsg translation) {
currReplacementNodes = Lists.newArrayList();
for (SoyMsgPart msgPart : translation.getParts()) {
if (msgPart instanceof SoyMsgRawTextPart) {
// Append a new RawTextNode to the currReplacementNodes list.
String rawText = ((SoyMsgRawTextPart) msgPart).getRawText();
currReplacementNodes.add(new RawTextNode(nodeIdGen.genId(), rawText, msg.getSourceLocation()));
} else if (msgPart instanceof SoyMsgPlaceholderPart) {
// Get the representative placeholder node and iterate through its contents.
String placeholderName = ((SoyMsgPlaceholderPart) msgPart).getPlaceholderName();
MsgPlaceholderNode placeholderNode = msg.getRepPlaceholderNode(placeholderName);
for (StandaloneNode contentNode : placeholderNode.getChildren()) {
// simply add the content node to the currReplacementNodes list being built.
if (contentNode instanceof MsgHtmlTagNode) {
currReplacementNodes.addAll(((MsgHtmlTagNode) contentNode).getChildren());
} else {
currReplacementNodes.add(contentNode);
}
}
} else {
throw new AssertionError();
}
}
}
use of com.google.template.soy.soytree.SoyNode.StandaloneNode in project closure-templates by google.
the class GenJsCodeVisitorAssistantForMsgs method genGoogMsgPlaceholder.
/**
* Returns a code chunk for the given placeholder node.
*/
protected CodeChunk.WithValue genGoogMsgPlaceholder(MsgPlaceholderNode msgPhNode) {
List<CodeChunk.WithValue> contentChunks = new ArrayList<>();
for (StandaloneNode contentNode : msgPhNode.getChildren()) {
if (contentNode instanceof MsgHtmlTagNode && !isComputableAsJsExprsVisitor.exec(contentNode)) {
// This is a MsgHtmlTagNode that is not computable as JS expressions. Visit it to
// generate code to define the 'htmlTag<n>' variable.
visit(contentNode);
contentChunks.add(id("htmlTag" + contentNode.getId()));
} else if (contentNode instanceof CallNode) {
// If the CallNode has any CallParamContentNode children that are not computable as JS
// expressions, visit them to generate code to define their respective 'param<n>' variables.
CallNode callNode = (CallNode) contentNode;
for (CallParamNode grandchild : callNode.getChildren()) {
if (grandchild instanceof CallParamContentNode && !isComputableAsJsExprsVisitor.exec(grandchild)) {
visit(grandchild);
}
}
CodeChunk.WithValue call = genCallCodeUtils.gen(callNode, templateAliases, translationContext, errorReporter);
contentChunks.add(call);
} else {
List<CodeChunk.WithValue> chunks = genJsExprsVisitor.exec(contentNode);
contentChunks.add(CodeChunkUtils.concatChunks(chunks));
}
}
return CodeChunkUtils.concatChunks(contentChunks);
}
use of com.google.template.soy.soytree.SoyNode.StandaloneNode in project closure-templates by google.
the class RewriteGenderMsgsVisitor method splitMsgForGender.
/**
* Helper to split a msg for gender, by adding a 'select' node and cloning the msg's contents into
* all 3 cases of the 'select' node ('female'/'male'/default).
*
* @param msg The message to split.
* @param genderExpr The expression for the gender value.
* @param baseSelectVarName The base select var name to use, or null if it should be generated
* from the gender expression.
*/
private void splitMsgForGender(MsgNode msg, ExprRootNode genderExpr, @Nullable String baseSelectVarName) {
List<StandaloneNode> origChildren = ImmutableList.copyOf(msg.getChildren());
msg.clearChildren();
MsgSelectCaseNode femaleCase = new MsgSelectCaseNode(nodeIdGen.genId(), msg.getSourceLocation(), "female");
femaleCase.addChildren(SoyTreeUtils.cloneListWithNewIds(origChildren, nodeIdGen));
MsgSelectCaseNode maleCase = new MsgSelectCaseNode(nodeIdGen.genId(), msg.getSourceLocation(), "male");
maleCase.addChildren(SoyTreeUtils.cloneListWithNewIds(origChildren, nodeIdGen));
MsgSelectDefaultNode defaultCase = new MsgSelectDefaultNode(nodeIdGen.genId(), msg.getSourceLocation());
defaultCase.addChildren(SoyTreeUtils.cloneListWithNewIds(origChildren, nodeIdGen));
MsgSelectNode selectNode = new MsgSelectNode(nodeIdGen.genId(), msg.getSourceLocation(), genderExpr, baseSelectVarName);
selectNode.addChild(femaleCase);
selectNode.addChild(maleCase);
selectNode.addChild(defaultCase);
msg.addChild(selectNode);
}
Aggregations