use of com.google.template.soy.exprtree.GlobalNode in project closure-templates by google.
the class GenerateParseInfoVisitor method visitSoyFileNode.
@Override
protected void visitSoyFileNode(SoyFileNode node) {
if (node.getSoyFileKind() != SoyFileKind.SRC) {
// don't generate code for deps
return;
}
String javaClassName = soyFileToJavaClassNameMap.get(node);
// Collect the following:
// + all the public basic templates (non-private, non-delegate) in a map from the
// upper-underscore template name to the template's node,
// + all the param keys from all templates (including private),
// + for each param key, the list of templates that list it directly.
// + for any params whose type is a proto, get the proto name and Java class name.
LinkedHashMap<String, TemplateNode> publicBasicTemplateMap = Maps.newLinkedHashMap();
List<String> deltemplates = new ArrayList<>();
Set<String> allParamKeys = Sets.newHashSet();
SetMultimap<String, TemplateNode> paramKeyToTemplatesMultimap = LinkedHashMultimap.create();
SortedSet<String> protoTypes = Sets.newTreeSet();
for (TemplateNode template : node.getChildren()) {
if (template.getVisibility() == Visibility.PUBLIC && template instanceof TemplateBasicNode) {
publicBasicTemplateMap.put(convertToUpperUnderscore(template.getPartialTemplateName().substring(1)), template);
}
if (template instanceof TemplateDelegateNode) {
deltemplates.add("\"" + template.getTemplateName() + "\"");
}
for (TemplateParam param : template.getAllParams()) {
if (!param.isInjected()) {
allParamKeys.add(param.name());
paramKeyToTemplatesMultimap.put(param.name(), template);
}
if (param instanceof HeaderParam) {
SoyType paramType = ((HeaderParam) param).type();
findProtoTypesRecurse(paramType, protoTypes);
}
}
// Field access nodes need special handling to ensure that extension references are handled.
for (FieldAccessNode fieldAccess : SoyTreeUtils.getAllNodesOfType(template, FieldAccessNode.class)) {
SoyType baseType = fieldAccess.getBaseExprChild().getType();
if (baseType.getKind() == SoyType.Kind.PROTO) {
FieldDescriptor desc = ((SoyProtoType) baseType).getFieldDescriptor(fieldAccess.getFieldName());
if (desc.isExtension()) {
protoTypes.add(ProtoUtils.getTofuExtensionImport(desc));
}
}
}
// Add enums
for (GlobalNode global : SoyTreeUtils.getAllNodesOfType(template, GlobalNode.class)) {
if (global.isResolved() && global.getType().getKind() == SoyType.Kind.PROTO_ENUM) {
protoTypes.add(((SoyProtoEnumType) global.getType()).getDescriptorExpression());
}
}
// Add proto init
for (ProtoInitNode protoInit : SoyTreeUtils.getAllNodesOfType(template, ProtoInitNode.class)) {
if (protoInit.getType().getKind() == SoyType.Kind.PROTO) {
protoTypes.add(((SoyProtoType) protoInit.getType()).getDescriptorExpression());
}
}
}
// allParamKeysMap is a map from upper-underscore key to original key.
SortedMap<String, String> allParamKeysMap = Maps.newTreeMap();
for (String key : allParamKeys) {
String upperUnderscoreKey = convertToUpperUnderscore(key);
// stage of the compiler.
while (allParamKeysMap.containsKey(upperUnderscoreKey)) {
upperUnderscoreKey = upperUnderscoreKey + "_";
}
allParamKeysMap.put(upperUnderscoreKey, key);
// Updates the convertedIdents here, since we might have changed the value by adding
// prepending underscores. Without this, the generated SoyTemplateInfo still use the
// old mapping and will fail.
convertedIdents.put(key, upperUnderscoreKey);
}
ilb = new IndentedLinesBuilder(2);
// ------ Header. ------
ilb.appendLine("// This file was automatically generated from ", node.getFileName(), ".");
ilb.appendLine("// Please don't edit this file by hand.");
ilb.appendLine();
ilb.appendLine("package ", javaPackage, ";");
ilb.appendLine();
ilb.appendLine("import com.google.common.collect.ImmutableList;");
ilb.appendLine("import com.google.common.collect.ImmutableMap;");
ilb.appendLine("import com.google.common.collect.ImmutableSortedSet;");
if (!protoTypes.isEmpty()) {
ilb.appendLine("import com.google.protobuf.Descriptors.GenericDescriptor;");
}
ilb.appendLine("import com.google.template.soy.parseinfo.SoyFileInfo;");
ilb.appendLine("import com.google.template.soy.parseinfo.SoyTemplateInfo;");
// ------ Class start. ------
ilb.appendLine();
ilb.appendLine();
appendJavadoc(ilb, "Soy parse info for " + node.getFileName() + ".", true, false);
ilb.appendLine("public final class ", javaClassName, " extends SoyFileInfo {");
ilb.increaseIndent();
// ------ Constant for namespace. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("/** This Soy file's namespace. */");
ilb.appendLine("public static final String __NAMESPACE__ = \"", node.getNamespace(), "\";");
// ------ Proto types map. ------
if (!protoTypes.isEmpty()) {
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("/** Protocol buffer types used by these templates. */");
ilb.appendLine("@Override public ImmutableList<GenericDescriptor> getProtoDescriptors() {");
ilb.increaseIndent();
// Note we use fully-qualified names instead of imports to avoid potential collisions.
List<String> defaultInstances = Lists.newArrayList();
defaultInstances.addAll(protoTypes);
appendListOrSetHelper(ilb, "return ImmutableList.<GenericDescriptor>of", defaultInstances);
ilb.appendLineEnd(";");
ilb.decreaseIndent();
ilb.appendLine("}");
}
// ------ Template names. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("public static final class TemplateName {");
ilb.increaseIndent();
ilb.appendLine("private TemplateName() {}");
ilb.appendLine();
for (Entry<String, TemplateNode> templateEntry : publicBasicTemplateMap.entrySet()) {
StringBuilder javadocSb = new StringBuilder();
javadocSb.append("The full template name of the ").append(templateEntry.getValue().getPartialTemplateName()).append(" template.");
appendJavadoc(ilb, javadocSb.toString(), false, true);
ilb.appendLine("public static final String ", templateEntry.getKey(), " = \"", templateEntry.getValue().getTemplateName(), "\";");
}
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Params. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("/**");
ilb.appendLine(" * Param names from all templates in this Soy file.");
ilb.appendLine(" */");
ilb.appendLine("public static final class Param {");
ilb.increaseIndent();
ilb.appendLine("private Param() {}");
ilb.appendLine();
for (Map.Entry<String, String> paramEntry : allParamKeysMap.entrySet()) {
String upperUnderscoreKey = paramEntry.getKey();
String key = paramEntry.getValue();
StringBuilder javadocSb = new StringBuilder();
javadocSb.append("Listed by ");
boolean isFirst = true;
for (TemplateNode template : paramKeyToTemplatesMultimap.get(key)) {
if (isFirst) {
isFirst = false;
} else {
javadocSb.append(", ");
}
javadocSb.append(buildTemplateNameForJavadoc(node, template));
}
javadocSb.append('.');
appendJavadoc(ilb, javadocSb.toString(), false, true);
ilb.appendLine("public static final String ", upperUnderscoreKey, " = \"", key, "\";");
}
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Templates. ------
for (TemplateNode template : publicBasicTemplateMap.values()) {
visit(template);
}
// ------ Constructor. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("private ", javaClassName, "() {");
ilb.increaseIndent();
ilb.appendLine("super(");
ilb.increaseIndent(2);
ilb.appendLine("\"", node.getFileName(), "\",");
ilb.appendLine("\"", node.getNamespace(), "\",");
// Templates.
List<String> itemSnippets = Lists.newArrayList();
itemSnippets.addAll(publicBasicTemplateMap.keySet());
appendImmutableList(ilb, "<SoyTemplateInfo>", itemSnippets);
ilb.appendLineEnd(",");
// CSS names.
SortedMap<String, CssTagsPrefixPresence> cssNameMap = new CollectCssNamesVisitor().exec(node);
ImmutableMap.Builder<String, String> cssTagPrefixes = ImmutableMap.builder();
for (Map.Entry<String, CssTagsPrefixPresence> entry : cssNameMap.entrySet()) {
cssTagPrefixes.put("\"" + entry.getKey() + "\"", "CssTagsPrefixPresence." + entry.getValue().name());
}
appendImmutableMap(ilb, "<String, CssTagsPrefixPresence>", cssTagPrefixes.build());
ilb.appendLineEnd(",");
appendImmutableList(ilb, "<String>", deltemplates);
ilb.appendLineEnd(");");
ilb.decreaseIndent(2);
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Singleton instance and its getter. ------
ilb.appendLine();
ilb.appendLine();
ilb.appendLine("private static final ", javaClassName, " __INSTANCE__ =");
ilb.increaseIndent(2);
ilb.appendLine("new ", javaClassName, "();");
ilb.decreaseIndent(2);
ilb.appendLine();
ilb.appendLine("public static ", javaClassName, " getInstance() {");
ilb.increaseIndent();
ilb.appendLine("return __INSTANCE__;");
ilb.decreaseIndent();
ilb.appendLine("}");
// ------ Class end. ------
ilb.appendLine();
ilb.decreaseIndent();
ilb.appendLine("}");
generatedFiles.put(javaClassName + ".java", ilb.toString());
ilb = null;
}
use of com.google.template.soy.exprtree.GlobalNode in project closure-templates by google.
the class XidPass method run.
@Override
public void run(SoyFileNode file, IdGenerator nodeIdGen) {
for (FunctionNode fn : SoyTreeUtils.getAllNodesOfType(file, FunctionNode.class)) {
if (fn.getSoyFunction() == BuiltinFunction.XID) {
if (fn.numChildren() != 1) {
// if it isn't == 1, then an error has already been reported, move along.
continue;
}
ExprNode child = fn.getChild(0);
switch(child.getKind()) {
case GLOBAL_NODE:
GlobalNode global = (GlobalNode) child;
if (global.isResolved()) {
// This doesn't have to be an error. but it is confusing if it is is since it is
// unclear if the user intended to xid the identifier or the value.
reporter.report(global.getSourceLocation(), GLOBAL_XID_ARG_IS_RESOLVED, global.getType().toString(), global.getValue().toSourceString());
}
fn.replaceChild(0, new StringNode(global.getName(), QuoteStyle.SINGLE, global.getSourceLocation()));
break;
case STRING_NODE:
break;
default:
reporter.report(child.getSourceLocation(), STRING_OR_GLOBAL_REQUIRED);
}
}
}
}
use of com.google.template.soy.exprtree.GlobalNode 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.GlobalNode in project closure-templates by google.
the class MsgSubstUnitBaseVarNameUtils method genCandidateBaseNamesForExpr.
/**
* Private helper for {@code genShortestBaseNameForExpr()} and {@code
* genNoncollidingBaseNamesForExprs()}.
*
* <p>Given an expression that's a data ref or a global, generates the list of all possible base
* names, from short to long. Shortest contains only the last key. Longest contains up to the
* first key (unless there are accesses using expressions to compute non-static keys, in which
* case we cannot generate any more base names). If no base names can be generated for the given
* expression (i.e. if the expression is not a data ref or global, or the last key is non-static),
* then returns empty list.
*
* <p>For example, given $aaa[0].bbb.cccDdd, generates the list ["CCC_DDD", "BBB_CCC_DDD",
* "AAA_0_BBB_CCC_DDD"]. One the other hand, given $aaa['xxx'], generates the empty list (because
* ['xxx'] parses to a DataRefAccessExprNode).
*
* @param exprNode The expr root of the expression to generate all candidate base names for.
* @return The list of all candidate base names, from shortest to longest.
*/
@VisibleForTesting
static List<String> genCandidateBaseNamesForExpr(ExprNode exprNode) {
if (exprNode instanceof VarRefNode || exprNode instanceof DataAccessNode) {
List<String> baseNames = Lists.newArrayList();
String baseName = null;
while (exprNode != null) {
String nameSegment = null;
if (exprNode instanceof VarRefNode) {
nameSegment = ((VarRefNode) exprNode).getName();
exprNode = null;
} else if (exprNode instanceof FieldAccessNode) {
FieldAccessNode fieldAccess = (FieldAccessNode) exprNode;
nameSegment = fieldAccess.getFieldName();
exprNode = fieldAccess.getBaseExprChild();
} else if (exprNode instanceof ItemAccessNode) {
ItemAccessNode itemAccess = (ItemAccessNode) exprNode;
exprNode = itemAccess.getBaseExprChild();
if (itemAccess.getKeyExprChild() instanceof IntegerNode) {
// Prefix with index, but don't add to baseNames list since it's not a valid ident.
IntegerNode keyValue = (IntegerNode) itemAccess.getKeyExprChild();
if (keyValue.getValue() < 0) {
// Stop if we encounter an invalid key.
break;
}
nameSegment = Long.toString(keyValue.getValue());
baseName = BaseUtils.convertToUpperUnderscore(nameSegment) + ((baseName != null) ? "_" + baseName : "");
continue;
} else {
// Stop if we encounter a non-static key
break;
}
} else {
// Stop if we encounter an expression that is not representable as a name.
break;
}
baseName = BaseUtils.convertToUpperUnderscore(nameSegment) + ((baseName != null) ? "_" + baseName : "");
// new candidate base name whenever we encounter a key
baseNames.add(baseName);
}
return baseNames;
} else if (exprNode instanceof GlobalNode) {
String[] globalNameParts = ((GlobalNode) exprNode).getName().split("\\.");
List<String> baseNames = Lists.newArrayList();
String baseName = null;
for (int i = globalNameParts.length - 1; i >= 0; i--) {
baseName = BaseUtils.convertToUpperUnderscore(globalNameParts[i]) + ((baseName != null) ? "_" + baseName : "");
baseNames.add(baseName);
}
return baseNames;
} else {
// We don't handle expressions other than data refs and globals.
return ImmutableList.of();
}
}
use of com.google.template.soy.exprtree.GlobalNode in project closure-templates by google.
the class SoyUtils method parseCompileTimeGlobals.
/**
* Parses a globals file in the format created by {@link #generateCompileTimeGlobalsFile} into a
* map from global name to primitive value.
*
* @param inputSource A source that returns a reader for the globals file.
* @return The parsed globals map.
* @throws IOException If an error occurs while reading the globals file.
* @throws IllegalStateException If the globals file is not in the correct format.
*/
public static ImmutableMap<String, PrimitiveData> parseCompileTimeGlobals(CharSource inputSource) throws IOException {
Builder<String, PrimitiveData> compileTimeGlobalsBuilder = ImmutableMap.builder();
ErrorReporter errorReporter = ErrorReporter.exploding();
try (BufferedReader reader = inputSource.openBufferedStream()) {
int lineNum = 1;
for (String line = reader.readLine(); line != null; line = reader.readLine(), ++lineNum) {
if (line.startsWith("//") || line.trim().length() == 0) {
continue;
}
SourceLocation sourceLocation = new SourceLocation("globals", lineNum, 1, lineNum, 1);
Matcher matcher = COMPILE_TIME_GLOBAL_LINE.matcher(line);
if (!matcher.matches()) {
errorReporter.report(sourceLocation, INVALID_FORMAT, line);
continue;
}
String name = matcher.group(1);
String valueText = matcher.group(2).trim();
ExprNode valueExpr = SoyFileParser.parseExprOrDie(valueText);
// TODO: Consider allowing non-primitives (e.g. list/map literals).
if (!(valueExpr instanceof PrimitiveNode)) {
if (valueExpr instanceof GlobalNode || valueExpr instanceof VarRefNode) {
errorReporter.report(sourceLocation, INVALID_VALUE, valueExpr.toSourceString());
} else {
errorReporter.report(sourceLocation, NON_PRIMITIVE_VALUE, valueExpr.toSourceString());
}
continue;
}
// Default case.
compileTimeGlobalsBuilder.put(name, InternalValueUtils.convertPrimitiveExprToData((PrimitiveNode) valueExpr));
}
}
return compileTimeGlobalsBuilder.build();
}
Aggregations