use of com.google.template.soy.exprtree.ExprNode.PrimitiveNode in project closure-templates by google.
the class RewriteGlobalsPass method resolveGlobal.
private void resolveGlobal(GlobalNode global) {
// First check to see if this global matches a proto enum. We do this because the enums from
// the type registry have better type information and for applications with legacy globals
// configs there is often overlap, so the order in which we check is actually important.
// proto enums are dotted identifiers
String name = global.getName();
int lastDot = name.lastIndexOf('.');
if (lastDot > 0) {
String enumTypeName = name.substring(0, lastDot);
SoyType type = typeRegistry.getType(enumTypeName);
if (type != null && type.getKind() == SoyType.Kind.PROTO_ENUM) {
SoyProtoEnumType enumType = (SoyProtoEnumType) type;
String enumMemberName = name.substring(lastDot + 1);
Integer enumValue = enumType.getValue(enumMemberName);
if (enumValue != null) {
// TODO(lukes): consider introducing a new PrimitiveNode for enums
global.resolve(enumType, new IntegerNode(enumValue, global.getSourceLocation()));
} else {
// If we found the type definition but not the value, then that's an error
// regardless of whether we're allowing unbound globals or not.
errorReporter.report(global.getSourceLocation(), ENUM_MEMBERSHIP_ERROR, enumMemberName, enumTypeName);
}
// TODO(lukes): issue a warning if a registered global also matches
return;
}
}
// if that doesn't work, see if it was registered in the globals file.
PrimitiveData value = compileTimeGlobals.get(global.getName());
if (value != null) {
PrimitiveNode expr = InternalValueUtils.convertPrimitiveDataToExpr(value, global.getSourceLocation());
global.resolve(expr.getType(), expr);
}
}
use of com.google.template.soy.exprtree.ExprNode.PrimitiveNode 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();
}
use of com.google.template.soy.exprtree.ExprNode.PrimitiveNode in project closure-templates by google.
the class TranslateExprNodeVisitor method visitLegacyObjectMapLiteralNode.
/**
* Helper to visit a LegacyObjectMapLiteralNode, with the extra option of whether to quote keys.
*/
private CodeChunk.WithValue visitLegacyObjectMapLiteralNode(LegacyObjectMapLiteralNode node, boolean doQuoteKeys) {
// If there are only string keys, then the expression will be
// {aa: 11, bb: 22} or {'aa': 11, 'bb': 22}
// where the former is with unquoted keys and the latter with quoted keys.
// If there are both string and nonstring keys, then the expression will be
// (function() { var $$tmp0 = {'aa': 11}; $$tmp0[opt_data.bb] = 22; return $$tmp0; })()
// Since we are outputting JS code to be processed by Closure Compiler, it is important that
// any unquoted map literal keys are string literals, since Closure Compiler can rename unquoted
// map keys and we want everything to be renamed at the same time.
// We will divide the map literal contents into two categories.
//
// Key-value pairs with StringNode keys can be included in the JS object literal.
// Key-value pairs that are not StringNodes (VarRefs, IJ values, etc.) must be passed through
// the soy.$$checkLegacyObjectMapLiteralKey() function, cannot be included in the JS object
// literal, and must generate code in the form of:
// $$map[soy.$$checkLegacyObjectMapLiteralKey(key)] = value
LinkedHashMap<CodeChunk.WithValue, CodeChunk.WithValue> objLiteral = new LinkedHashMap<>();
LinkedHashMap<CodeChunk.WithValue, CodeChunk.WithValue> assignments = new LinkedHashMap<>();
for (int i = 0; i < node.numChildren(); i += 2) {
ExprNode keyNode = node.getChild(i);
ExprNode valueNode = node.getChild(i + 1);
// roll it into the next case.
if (!(keyNode instanceof StringNode) && keyNode instanceof PrimitiveNode) {
errorReporter.report(keyNode.getSourceLocation(), CONSTANT_USED_AS_KEY_IN_MAP_LITERAL, keyNode.toSourceString());
continue;
}
// since the compiler may change the names of any unquoted map keys.
if (!doQuoteKeys && !(keyNode instanceof StringNode)) {
errorReporter.report(keyNode.getSourceLocation(), EXPR_IN_MAP_LITERAL_REQUIRES_QUOTE_KEYS_IF_JS, keyNode.toSourceString());
continue;
}
if (keyNode instanceof StringNode) {
if (doQuoteKeys) {
objLiteral.put(visit(keyNode), visit(valueNode));
} else {
String strKey = ((StringNode) keyNode).getValue();
if (BaseUtils.isIdentifier(strKey)) {
objLiteral.put(id(strKey), visit(valueNode));
} else {
errorReporter.report(keyNode.getSourceLocation(), MAP_LITERAL_WITH_NON_ID_KEY_REQUIRES_QUOTE_KEYS_IF_JS, keyNode.toSourceString());
continue;
}
}
} else {
// key is not a StringNode; key must be passed through
// soy.$$checkLegacyObjectMapLiteralKey() and the pair cannot be included in the JS object
// literal.
CodeChunk.WithValue rawKey = visit(keyNode);
assignments.put(SOY_CHECK_LEGACY_OBJECT_MAP_LITERAL_KEY.call(rawKey), visit(valueNode));
}
}
// Build the map literal
ImmutableList<CodeChunk.WithValue> keys = ImmutableList.copyOf(objLiteral.keySet());
ImmutableList<CodeChunk.WithValue> values = ImmutableList.copyOf(objLiteral.values());
CodeChunk.WithValue map = mapLiteral(keys, values);
if (assignments.isEmpty()) {
// to a tmp var.
return map;
}
// Otherwise, we need to bail to a tmp var and emit assignment statements.
CodeChunk.WithValue mapVar = codeGenerator.declarationBuilder().setRhs(map).build().ref();
ImmutableList.Builder<CodeChunk> initialStatements = ImmutableList.builder();
for (Map.Entry<CodeChunk.WithValue, CodeChunk.WithValue> entry : assignments.entrySet()) {
initialStatements.add(mapVar.bracketAccess(entry.getKey()).assign(entry.getValue()));
}
return mapVar.withInitialStatements(initialStatements.build());
}
use of com.google.template.soy.exprtree.ExprNode.PrimitiveNode in project closure-templates by google.
the class SimplifyExprVisitor method attemptPreeval.
// -----------------------------------------------------------------------------------------------
// Helpers.
/**
* Attempts to preevaluate a node. If successful, the node is replaced with a new constant node in
* the tree. If unsuccessful, the tree is not changed.
*/
private void attemptPreeval(ExprNode node) {
// Note that we need to catch RenderException because preevaluation may fail, e.g. when
// (a) the expression uses a bidi function that needs bidiGlobalDir to be in scope, but the
// apiCallScope is not currently active,
// (b) the expression uses an external function (Soy V1 syntax),
// (c) other cases I haven't thought up.
SoyValue preevalResult;
try {
preevalResult = preevalVisitor.exec(node);
} catch (RenderException e) {
// failed to preevaluate
return;
}
PrimitiveNode newNode = InternalValueUtils.convertPrimitiveDataToExpr((PrimitiveData) preevalResult, node.getSourceLocation());
if (newNode != null) {
node.getParent().replaceChild(node, newNode);
}
}
Aggregations