use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class TemplateDelegateNodeBuilder method genInternalTemplateNameHelper.
/**
* Private helper for both setCmdText() and setCmdTextInfo() to generate and set the internal-use
* partial template name and template name.
*/
private void genInternalTemplateNameHelper() {
Preconditions.checkState(id != null);
// encode all the deltemplate information into the name to get a unique string
// though... it might make more sense for this to not have a user visible name given that the
// calling convention is indirect.
String variant = "";
if (delTemplateVariantExpr != null) {
// this is hacky. perhaps we should come up with a less ambiguous strategy
ExprNode expr = delTemplateVariantExpr.getRoot();
if (expr instanceof StringNode) {
variant = ((StringNode) expr).getValue();
} else {
variant = expr.toSourceString();
}
}
String delPackageTemplateAndVariantStr = (soyFileHeaderInfo.delPackageName == null ? "" : soyFileHeaderInfo.delPackageName) + "_" + delTemplateName.replace('.', '_') + "_" + variant;
delPackageTemplateAndVariantStr = delPackageTemplateAndVariantStr.replace('.', '_');
// Generate the actual internal-use template name.
String generatedPartialTemplateName = ".__deltemplate_" + delPackageTemplateAndVariantStr;
String generatedTemplateName = soyFileHeaderInfo.namespace + generatedPartialTemplateName;
setTemplateNames(generatedTemplateName, generatedPartialTemplateName);
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class TemplateDelegateNode method resolveVariantExpression.
/**
* Calculate a DeltemplateKey for the variant.
*
* <p>This is done lazily so that global references can be resolved. This is not ideal since
* nothing guarantees that resolution happens before access.
*
* <p>Note we don't do validation of the variant values since that is handled by the
* TemplateDelegateNodeBuilder during construction
*/
private DelTemplateKey resolveVariantExpression() {
if (delTemplateVariantExpr == null) {
delTemplateKey = DelTemplateKey.create(delTemplateName, "");
return delTemplateKey;
}
ExprNode exprNode = delTemplateVariantExpr.getRoot();
if (exprNode instanceof GlobalNode) {
GlobalNode globalNode = (GlobalNode) exprNode;
if (globalNode.isResolved()) {
exprNode = globalNode.getValue();
} else {
// For this reason we also don't store the key, instead we just return it.
return DelTemplateKey.create(delTemplateName, globalNode.getName());
}
}
if (exprNode instanceof IntegerNode) {
// Globals were already substituted: We may now create the definitive variant and key fields
// on this node.
long variantValue = ((IntegerNode) exprNode).getValue();
delTemplateKey = DelTemplateKey.create(delTemplateName, String.valueOf(variantValue));
} else if (exprNode instanceof StringNode) {
// Globals were already substituted: We may now create the definitive variant and key fields
// on this node.
delTemplateKey = DelTemplateKey.create(delTemplateName, ((StringNode) exprNode).getValue());
} else {
// We must have already reported an error, just create an arbitrary variant expr.
delTemplateKey = DelTemplateKey.create(delTemplateName, exprNode.toSourceString());
}
return delTemplateKey;
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class MsgSubstUnitBaseVarNameUtils method genNoncollidingBaseNamesForExprs.
/**
* Generates base names for all the expressions in a list, where for each expression, we use the
* shortest candidate base name that does not collide with any of the candidate base names
* generated from other expressions in the list. Two candidate base names are considered to
* collide if they are identical or if one is a suffix of the other beginning after an underscore
* character.
*
* <p>For example, given the expressions $userGender and $target.gender, the generated base names
* would be USER_GENDER and TARGET_GENDER. (Even though the shortest candidate base names are
* USER_GENDER and GENDER, the latter one is not used since it collides with the former one.)
*
* <p>Note: We prefer the shorter candidate base names when possible, because the translator
* usually doesn't care about all the names. E.g. $data.actionTargets[0].personInfo.gender turns
* into GENDER as opposed to DATA_ACTION_TARGETS_0_PERSON_INFO_GENDER, which is overkill and
* probably more confusing. Another reason is that refactorings that change higher-level names
* should not change messages unnecessarily. E.g. a refactoring that changes
* $data.actionTargets[0].personInfo.gender -> $userData.actionTargets[0].personInfo.gender should
* not change the placeholder name.
*
* @param exprNodes The expr nodes of the expressions to generate noncolliding base names for.
* @param fallbackBaseName The fallback base name.
* @param errorReporter For reporting collision errors.
* @return The list of generated noncolliding base names.
*/
public static List<String> genNoncollidingBaseNamesForExprs(List<ExprNode> exprNodes, String fallbackBaseName, ErrorReporter errorReporter) {
int numExprs = exprNodes.size();
// --- Compute candidate base names for each expression. ---
List<List<String>> candidateBaseNameLists = Lists.newArrayListWithCapacity(numExprs);
for (ExprNode exprRoot : exprNodes) {
candidateBaseNameLists.add(genCandidateBaseNamesForExpr(exprRoot));
}
// --- Build a multiset of collision strings (if key has > 1 values, then it's a collision). ---
// Note: We could combine this loop with the previous loop, but it's more readable this way.
Multimap<String, ExprNode> collisionStrToLongestCandidatesMultimap = HashMultimap.create();
for (int i = 0; i < numExprs; i++) {
ExprNode exprRoot = exprNodes.get(i);
List<String> candidateBaseNameList = candidateBaseNameLists.get(i);
if (candidateBaseNameList.isEmpty()) {
continue;
}
String longestCandidate = candidateBaseNameList.get(candidateBaseNameList.size() - 1);
// Add longest candidate as a collision string.
collisionStrToLongestCandidatesMultimap.put(longestCandidate, exprRoot);
// Add all suffixes that begin after an underscore char as collision strings.
for (int j = 0, n = longestCandidate.length(); j < n; j++) {
if (longestCandidate.charAt(j) == '_') {
collisionStrToLongestCandidatesMultimap.put(longestCandidate.substring(j + 1), exprRoot);
}
}
}
// --- Find the shortest noncolliding candidate base name for each expression. ---
List<String> noncollidingBaseNames = Lists.newArrayListWithCapacity(numExprs);
OUTER: for (int i = 0; i < numExprs; i++) {
List<String> candidateBaseNameList = candidateBaseNameLists.get(i);
if (!candidateBaseNameList.isEmpty()) {
for (String candidateBaseName : candidateBaseNameList) {
if (collisionStrToLongestCandidatesMultimap.get(candidateBaseName).size() == 1) {
// Found candidate with 1 value in multimap, which means no collision.
noncollidingBaseNames.add(candidateBaseName);
continue OUTER;
}
}
// Did not find any candidate with no collision.
ExprNode exprRoot = exprNodes.get(i);
String longestCandidate = candidateBaseNameList.get(candidateBaseNameList.size() - 1);
ExprNode collidingExprRoot = null;
for (ExprNode er : collisionStrToLongestCandidatesMultimap.get(longestCandidate)) {
if (er != exprRoot) {
collidingExprRoot = er;
break;
}
}
errorReporter.report(collidingExprRoot.getSourceLocation(), COLLIDING_EXPRESSIONS, exprRoot.toSourceString(), collidingExprRoot.toSourceString());
return noncollidingBaseNames;
} else {
// No candidates: Use fallback.
noncollidingBaseNames.add(fallbackBaseName);
}
}
return noncollidingBaseNames;
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class ParseExpressionTest method testParseListsAndMaps.
@Test
public void testParseListsAndMaps() throws Exception {
ExprNode expr = assertThatExpression("[]").isValidExpression();
assertThat(((ListLiteralNode) expr).numChildren()).isEqualTo(0);
expr = assertThatExpression("[55]").isValidExpression();
assertThat(((ListLiteralNode) expr).numChildren()).isEqualTo(1);
expr = assertThatExpression("[55,]").isValidExpression();
assertThat(((ListLiteralNode) expr).numChildren()).isEqualTo(1);
expr = assertThatExpression("['blah', 123, $boo]").isValidExpression();
assertThat(((ListLiteralNode) expr).numChildren()).isEqualTo(3);
expr = assertThatExpression("['blah', 123, $boo,]").isValidExpression();
assertThat(((ListLiteralNode) expr).numChildren()).isEqualTo(3);
expr = assertThatExpression("[:]").isValidExpression();
assertThat(((LegacyObjectMapLiteralNode) expr).numChildren()).isEqualTo(0);
expr = assertThatExpression("['aa': 55]").isValidExpression();
assertThat(((LegacyObjectMapLiteralNode) expr).numChildren()).isEqualTo(2);
expr = assertThatExpression("['aa': 55,]").isValidExpression();
assertThat(((LegacyObjectMapLiteralNode) expr).numChildren()).isEqualTo(2);
expr = assertThatExpression("['aaa': 'blah', 'bbb': 123, $foo.bar: $boo]").isValidExpression();
assertThat(((LegacyObjectMapLiteralNode) expr).numChildren()).isEqualTo(6);
expr = assertThatExpression("['aaa': 'blah', 'bbb': 123, $foo.bar: $boo,]").isValidExpression();
assertThat(((LegacyObjectMapLiteralNode) expr).numChildren()).isEqualTo(6);
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class MsgSubstUnitBaseVarNameUtilsTest method assertShortestBaseNameForExpr.
private void assertShortestBaseNameForExpr(String expected, String exprText) {
ExprNode exprRoot = parse(exprText);
String actual = MsgSubstUnitBaseVarNameUtils.genShortestBaseNameForExpr(exprRoot, "FALLBACK");
assertEquals(expected, actual);
}
Aggregations