use of com.google.template.soy.data.SoyValue 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);
}
}
use of com.google.template.soy.data.SoyValue in project closure-templates by google.
the class EvalVisitor method visitNullSafeItemAccessNode.
private SoyValue visitNullSafeItemAccessNode(ItemAccessNode itemAccess) {
SoyValue base = visitNullSafeNodeRecurse(itemAccess.getBaseExprChild());
// attempting item access on non-SoyMap
if (!(base instanceof SoyLegacyObjectMap || base instanceof SoyMap)) {
if (base == NullSafetySentinel.INSTANCE) {
// Bail out if base expression failed a null-safety check.
return NullSafetySentinel.INSTANCE;
}
if (itemAccess.isNullSafe()) {
if (isNullOrUndefinedBase(base)) {
// Return the sentinel value that indicates that a null-safety check failed.
return NullSafetySentinel.INSTANCE;
} else {
throw RenderException.create(String.format("While evaluating \"%s\", encountered non-map/list just before accessing \"%s\".", itemAccess.toSourceString(), itemAccess.getSourceStringSuffix()));
}
}
// TODO: If feasible, find and fix existing instances, then throw RenderException here.
return UndefinedData.INSTANCE;
}
// base is a valid SoyMap or SoyLegacyObjectMap: get value
maybeMarkBadProtoAccess(itemAccess, base);
SoyValue key = visit(itemAccess.getKeyExprChild());
SoyType baseType = SoyTypes.tryRemoveNull(itemAccess.getBaseExprChild().getType());
// We need to know whether to invoke the SoyMap or SoyLegacyObjectMap method.
// An instanceof check on the runtime value of base is insufficient, since
// DictImpl implements both interfaces. Instead, look at the declared type of the base
// expression.
boolean shouldUseNewMap = MapType.ANY_MAP.isAssignableFrom(baseType);
SoyValue value = shouldUseNewMap ? ((SoyMap) base).get(key) : ((SoyLegacyObjectMap) base).getItem(key);
if (value != null && !TofuTypeChecks.isInstance(itemAccess.getType(), value)) {
throw RenderException.create(String.format("Expected value of type '%s', but actual type was '%s'.", itemAccess.getType(), value.getClass().getSimpleName()));
}
if (value != null) {
return value;
} else if (shouldUseNewMap) {
// UndefinedData is a misfeature. The new map type should return null for failed lookups.
return NullData.INSTANCE;
} else {
return UndefinedData.INSTANCE;
}
}
use of com.google.template.soy.data.SoyValue in project closure-templates by google.
the class EvalVisitor method visitLegacyObjectMapLiteralOrMapLiteralNode.
private SoyValue visitLegacyObjectMapLiteralOrMapLiteralNode(AbstractParentExprNode node) {
checkState(node.getKind() == ExprNode.Kind.LEGACY_OBJECT_MAP_LITERAL_NODE || node.getKind() == ExprNode.Kind.MAP_LITERAL_NODE);
int numItems = node.numChildren() / 2;
boolean isStringKeyed = true;
ExprNode firstNonstringKeyNode = null;
List<SoyValue> keys = Lists.newArrayListWithCapacity(numItems);
List<SoyValue> values = Lists.newArrayListWithCapacity(numItems);
for (int i = 0; i < numItems; i++) {
SoyValue key = visit(node.getChild(2 * i));
if (isStringKeyed && !(key instanceof StringData)) {
isStringKeyed = false;
// temporary until we support nonstring key
firstNonstringKeyNode = node.getChild(2 * i);
}
keys.add(key);
values.add(visit(node.getChild(2 * i + 1)));
}
if (node.getKind() == ExprNode.Kind.LEGACY_OBJECT_MAP_LITERAL_NODE) {
if (!isStringKeyed) {
throw RenderException.create(String.format("legacy_object_map literals must have string keys (key \"%s\" in map %s does not " + "evaluate to a string).", firstNonstringKeyNode.toSourceString(), node.toSourceString()));
}
// Not an ImmutableMap, because map literals allow duplicate keys (last one wins).
Map<String, SoyValue> map = new LinkedHashMap<>();
for (int i = 0; i < numItems; i++) {
map.put(keys.get(i).stringValue(), values.get(i));
}
return DictImpl.forProviderMap(map, RuntimeMapTypeTracker.Type.LEGACY_OBJECT_MAP_OR_RECORD);
} else {
ImmutableMap.Builder<SoyValue, SoyValue> builder = ImmutableMap.builder();
for (int i = 0; i < numItems; ++i) {
SoyValue key = keys.get(i);
SoyValue value = values.get(i);
if (isNullOrUndefinedBase(key)) {
throw RenderException.create(String.format("null key in entry: null=%s", value));
}
builder.put(key, value);
}
return SoyMapImpl.forProviderMap(builder.build());
}
}
use of com.google.template.soy.data.SoyValue in project closure-templates by google.
the class DictImplTest method testSoyValueMethods.
@Test
public void testSoyValueMethods() {
SoyValue val1 = DictImpl.forProviderMap(ImmutableMap.of(), RuntimeMapTypeTracker.Type.UNKNOWN);
// DictImpl is always truthy.
assertThat(val1.coerceToBoolean()).isTrue();
assertThat(val1.coerceToString()).isEqualTo("{}");
SoyValue val2 = DictImpl.forProviderMap(ImmutableMap.of(), RuntimeMapTypeTracker.Type.UNKNOWN);
// DictImpl uses object identity.
assertThat(val1.equals(val2)).isFalse();
SoyValue val3 = DictImpl.forProviderMap(ImmutableMap.<String, SoyValue>of("foo", FloatData.forValue(3.14), "too", BooleanData.TRUE), RuntimeMapTypeTracker.Type.UNKNOWN);
assertThat(val3.coerceToBoolean()).isTrue();
assertThat(val3.coerceToString()).isEqualTo("{foo: 3.14, too: true}");
}
use of com.google.template.soy.data.SoyValue in project closure-templates by google.
the class MinFunctionTest method testComputeForJava.
@Test
public void testComputeForJava() {
MinFunction minFunction = new MinFunction();
SoyValue float0 = FloatData.forValue(7.5);
SoyValue float1 = FloatData.forValue(7.777);
assertThat(minFunction.computeForJava(ImmutableList.of(float0, float1))).isEqualTo(FloatData.forValue(7.5));
SoyValue integer0 = IntegerData.forValue(-7);
SoyValue integer1 = IntegerData.forValue(-8);
assertThat(minFunction.computeForJava(ImmutableList.of(integer0, integer1))).isEqualTo(IntegerData.forValue(-8));
}
Aggregations