Search in sources :

Example 1 with GlobalNode

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;
}
Also used : TemplateBasicNode(com.google.template.soy.soytree.TemplateBasicNode) HeaderParam(com.google.template.soy.soytree.defn.HeaderParam) IndentedLinesBuilder(com.google.template.soy.base.internal.IndentedLinesBuilder) ArrayList(java.util.ArrayList) FieldDescriptor(com.google.protobuf.Descriptors.FieldDescriptor) ProtoInitNode(com.google.template.soy.exprtree.ProtoInitNode) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) TemplateNode(com.google.template.soy.soytree.TemplateNode) TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) FieldAccessNode(com.google.template.soy.exprtree.FieldAccessNode) SoyProtoType(com.google.template.soy.types.SoyProtoType) ImmutableMap(com.google.common.collect.ImmutableMap) SoyType(com.google.template.soy.types.SoyType) GlobalNode(com.google.template.soy.exprtree.GlobalNode) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) SortedMap(java.util.SortedMap) LinkedHashMap(java.util.LinkedHashMap) CssTagsPrefixPresence(com.google.template.soy.parseinfo.SoyFileInfo.CssTagsPrefixPresence)

Example 2 with GlobalNode

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);
            }
        }
    }
}
Also used : ExprNode(com.google.template.soy.exprtree.ExprNode) FunctionNode(com.google.template.soy.exprtree.FunctionNode) StringNode(com.google.template.soy.exprtree.StringNode) GlobalNode(com.google.template.soy.exprtree.GlobalNode)

Example 3 with GlobalNode

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;
}
Also used : ExprNode(com.google.template.soy.exprtree.ExprNode) IntegerNode(com.google.template.soy.exprtree.IntegerNode) StringNode(com.google.template.soy.exprtree.StringNode) GlobalNode(com.google.template.soy.exprtree.GlobalNode)

Example 4 with GlobalNode

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();
    }
}
Also used : DataAccessNode(com.google.template.soy.exprtree.DataAccessNode) VarRefNode(com.google.template.soy.exprtree.VarRefNode) IntegerNode(com.google.template.soy.exprtree.IntegerNode) ItemAccessNode(com.google.template.soy.exprtree.ItemAccessNode) GlobalNode(com.google.template.soy.exprtree.GlobalNode) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) FieldAccessNode(com.google.template.soy.exprtree.FieldAccessNode) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 5 with GlobalNode

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();
}
Also used : SourceLocation(com.google.template.soy.base.SourceLocation) ExprNode(com.google.template.soy.exprtree.ExprNode) PrimitiveNode(com.google.template.soy.exprtree.ExprNode.PrimitiveNode) PrimitiveData(com.google.template.soy.data.restricted.PrimitiveData) ErrorReporter(com.google.template.soy.error.ErrorReporter) VarRefNode(com.google.template.soy.exprtree.VarRefNode) Matcher(java.util.regex.Matcher) BufferedReader(java.io.BufferedReader) GlobalNode(com.google.template.soy.exprtree.GlobalNode)

Aggregations

GlobalNode (com.google.template.soy.exprtree.GlobalNode)8 ExprNode (com.google.template.soy.exprtree.ExprNode)4 IntegerNode (com.google.template.soy.exprtree.IntegerNode)4 StringNode (com.google.template.soy.exprtree.StringNode)4 FieldAccessNode (com.google.template.soy.exprtree.FieldAccessNode)2 ProtoInitNode (com.google.template.soy.exprtree.ProtoInitNode)2 VarRefNode (com.google.template.soy.exprtree.VarRefNode)2 Test (org.junit.Test)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 FieldDescriptor (com.google.protobuf.Descriptors.FieldDescriptor)1 SourceLocation (com.google.template.soy.base.SourceLocation)1 IndentedLinesBuilder (com.google.template.soy.base.internal.IndentedLinesBuilder)1 PrimitiveData (com.google.template.soy.data.restricted.PrimitiveData)1 ErrorReporter (com.google.template.soy.error.ErrorReporter)1 DataAccessNode (com.google.template.soy.exprtree.DataAccessNode)1 PrimitiveNode (com.google.template.soy.exprtree.ExprNode.PrimitiveNode)1 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)1 FunctionNode (com.google.template.soy.exprtree.FunctionNode)1