use of com.google.template.soy.exprtree.ExprNode 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 in project closure-templates by google.
the class TranslateExprNodeVisitor method visitMapLiteralNode.
@Override
protected WithValue visitMapLiteralNode(MapLiteralNode node) {
// Map literal nodes are much simpler to translate than legacy object map literal nodes.
// Because they are implemented by ES6 Maps, there is no possibility that JSCompiler
// will mistakenly rename (or not rename) its keys, and no need to ever quote a key.
CodeChunk.WithValue map = codeGenerator.declarationBuilder().setRhs(CodeChunk.new_(id("Map")).call()).build().ref();
ImmutableList.Builder<CodeChunk> setCalls = ImmutableList.builder();
for (int i = 0; i < node.numChildren(); i += 2) {
ExprNode keyNode = node.getChild(i);
// Constructing a map literal with a null key is a runtime error.
CodeChunk.WithValue key = SOY_CHECK_NOT_NULL.call(genMapKeyCode(keyNode));
CodeChunk.WithValue value = visit(node.getChild(i + 1));
setCalls.add(map.dotAccess("set").call(key, value));
}
return map.withInitialStatements(setCalls.build());
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class GenJsCodeVisitor method visitSwitchNode.
/**
* Example:
*
* <pre>
* {switch $boo}
* {case 0}
* ...
* {case 1, 2}
* ...
* {default}
* ...
* {/switch}
* </pre>
*
* might generate
*
* <pre>
* switch (opt_data.boo) {
* case 0:
* ...
* break;
* case 1:
* case 2:
* ...
* break;
* default:
* ...
* }
* </pre>
*/
@Override
protected void visitSwitchNode(SwitchNode node) {
CodeChunk.WithValue switchOn = coerceTypeForSwitchComparison(node.getExpr());
SwitchBuilder switchBuilder = switch_(switchOn);
for (SoyNode child : node.getChildren()) {
if (child instanceof SwitchCaseNode) {
SwitchCaseNode scn = (SwitchCaseNode) child;
ImmutableList.Builder<CodeChunk.WithValue> caseChunks = ImmutableList.builder();
for (ExprNode caseExpr : scn.getExprList()) {
CodeChunk.WithValue caseChunk = translateExpr(caseExpr);
caseChunks.add(caseChunk);
}
CodeChunk body = visitChildrenReturningCodeChunk(scn);
switchBuilder.case_(caseChunks.build(), body);
} else if (child instanceof SwitchDefaultNode) {
CodeChunk body = visitChildrenReturningCodeChunk((SwitchDefaultNode) child);
switchBuilder.default_(body);
} else {
throw new AssertionError();
}
}
jsCodeBuilder.append(switchBuilder.build());
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class SimplifyExprVisitor method visitAndOpNode.
// -----------------------------------------------------------------------------------------------
// Implementations for operators.
@Override
protected void visitAndOpNode(AndOpNode node) {
// Recurse.
visitChildren(node);
// Can simplify if either child is constant. We assume no side-effects.
SoyValue operand0 = getConstantOrNull(node.getChild(0));
if (operand0 != null) {
ExprNode replacementNode = operand0.coerceToBoolean() ? node.getChild(1) : node.getChild(0);
node.getParent().replaceChild(node, replacementNode);
}
}
use of com.google.template.soy.exprtree.ExprNode in project closure-templates by google.
the class SimplifyExprVisitor method visitOrOpNode.
@Override
protected void visitOrOpNode(OrOpNode node) {
// Recurse.
visitChildren(node);
// Can simplify if either child is constant. We assume no side-effects.
SoyValue operand0 = getConstantOrNull(node.getChild(0));
if (operand0 != null) {
ExprNode replacementNode = operand0.coerceToBoolean() ? node.getChild(0) : node.getChild(1);
node.getParent().replaceChild(node, replacementNode);
}
}
Aggregations