Skylark: Use LValue class in loops and comprehensions.
--
MOS_MIGRATED_REVID=89020190
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java b/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
index f0063d0..601f128 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
@@ -52,7 +52,8 @@
@Override
void exec(Environment env) throws EvalException, InterruptedException {
- lvalue.assign(env, getLocation(), expression);
+ Object rvalue = expression.eval(env);
+ lvalue.assign(env, getLocation(), rvalue);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/DictComprehension.java b/src/main/java/com/google/devtools/build/lib/syntax/DictComprehension.java
index 05190ab..4c7278b 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/DictComprehension.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/DictComprehension.java
@@ -24,14 +24,14 @@
private final Expression keyExpression;
private final Expression valueExpression;
- private final Ident loopVar;
+ private final LValue loopVar;
private final Expression listExpression;
- public DictComprehension(Expression keyExpression, Expression valueExpression, Ident loopVar,
+ public DictComprehension(Expression keyExpression, Expression valueExpression, Expression loopVar,
Expression listExpression) {
this.keyExpression = keyExpression;
this.valueExpression = valueExpression;
- this.loopVar = loopVar;
+ this.loopVar = new LValue(loopVar);
this.listExpression = listExpression;
}
@@ -43,7 +43,7 @@
return valueExpression;
}
- Ident getLoopVar() {
+ LValue getLoopVar() {
return loopVar;
}
@@ -57,7 +57,7 @@
LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
Iterable<?> elements = EvalUtils.toIterable(listExpression.eval(env), getLocation());
for (Object element : elements) {
- env.update(loopVar.getName(), element);
+ loopVar.assign(env, getLocation(), element);
Object key = keyExpression.eval(env);
map.put(key, valueExpression.eval(env));
}
@@ -68,7 +68,7 @@
SkylarkType validate(ValidationEnvironment env) throws EvalException {
SkylarkType elementsType = listExpression.validate(env);
SkylarkType listElementType = SkylarkType.getGenericArgType(elementsType);
- env.update(loopVar.getName(), listElementType, getLocation());
+ loopVar.validate(env, getLocation(), listElementType);
SkylarkType keyType = keyExpression.validate(env);
if (!keyType.isSimple()) {
// TODO(bazel-team): this is most probably dead code but it's better to have it here
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/LValue.java b/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
index a328118..2713154 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
@@ -42,7 +42,7 @@
/**
* Assign a value to an LValue and update the environment.
*/
- public void assign(Environment env, Location loc, Expression rvalue)
+ public void assign(Environment env, Location loc, Object result)
throws EvalException, InterruptedException {
if (!(expr instanceof Ident)) {
throw new EvalException(loc,
@@ -50,8 +50,7 @@
}
Ident ident = (Ident) expr;
- Object result = rvalue.eval(env);
- Preconditions.checkNotNull(result, "result of %s is null", rvalue);
+ Preconditions.checkNotNull(result, "trying to assign null to %s", ident);
if (env.isSkylarkEnabled()) {
// The variable may have been referenced successfully if a global variable
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ListComprehension.java b/src/main/java/com/google/devtools/build/lib/syntax/ListComprehension.java
index 3153e8c..26cbfc0 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/ListComprehension.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/ListComprehension.java
@@ -28,7 +28,7 @@
private final Expression elementExpression;
// This cannot be a map, because we need to both preserve order _and_ allow duplicate identifiers.
- private final List<Map.Entry<Ident, Expression>> lists;
+ private final List<Map.Entry<LValue, Expression>> lists;
/**
* [elementExpr (for var in listExpr)+]
@@ -44,9 +44,9 @@
return convert(new ArrayList<>(), env);
}
- List<Map.Entry<Ident, Iterable<?>>> listValues = Lists.newArrayListWithCapacity(lists.size());
+ List<Map.Entry<LValue, Iterable<?>>> listValues = Lists.newArrayListWithCapacity(lists.size());
int size = 1;
- for (Map.Entry<Ident, Expression> list : lists) {
+ for (Map.Entry<LValue, Expression> list : lists) {
Object listValueObject = list.getValue().eval(env);
final Iterable<?> listValue = EvalUtils.toIterable(listValueObject, getLocation());
int listSize = EvalUtils.size(listValue);
@@ -54,7 +54,7 @@
return convert(new ArrayList<>(), env);
}
size *= listSize;
- listValues.add(Maps.<Ident, Iterable<?>>immutableEntry(list.getKey(), listValue));
+ listValues.add(Maps.<LValue, Iterable<?>>immutableEntry(list.getKey(), listValue));
}
List<Object> resultList = Lists.newArrayListWithCapacity(size);
evalLists(env, listValues, resultList);
@@ -73,7 +73,7 @@
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[').append(elementExpression);
- for (Map.Entry<Ident, Expression> list : lists) {
+ for (Map.Entry<LValue, Expression> list : lists) {
sb.append(" for ").append(list.getKey()).append(" in ").append(list.getValue());
}
sb.append(']');
@@ -84,11 +84,11 @@
return elementExpression;
}
- public void add(Ident ident, Expression listExpression) {
- lists.add(Maps.immutableEntry(ident, listExpression));
+ public void add(Expression loopVar, Expression listExpression) {
+ lists.add(Maps.immutableEntry(new LValue(loopVar), listExpression));
}
- public List<Map.Entry<Ident, Expression>> getLists() {
+ public List<Map.Entry<LValue, Expression>> getLists() {
return lists;
}
@@ -106,11 +106,11 @@
* of the element expression to the result. Otherwise calls itself recursively
* with all the lists except the outermost.
*/
- private void evalLists(Environment env, List<Map.Entry<Ident, Iterable<?>>> listValues,
+ private void evalLists(Environment env, List<Map.Entry<LValue, Iterable<?>>> listValues,
List<Object> result) throws EvalException, InterruptedException {
- Map.Entry<Ident, Iterable<?>> listValue = listValues.get(0);
+ Map.Entry<LValue, Iterable<?>> listValue = listValues.get(0);
for (Object listElement : listValue.getValue()) {
- env.update(listValue.getKey().getName(), listElement);
+ listValue.getKey().assign(env, getLocation(), listElement);
if (listValues.size() == 1) {
result.add(elementExpression.eval(env));
} else {
@@ -121,11 +121,11 @@
@Override
SkylarkType validate(ValidationEnvironment env) throws EvalException {
- for (Map.Entry<Ident, Expression> list : lists) {
+ for (Map.Entry<LValue, Expression> list : lists) {
// TODO(bazel-team): Get the type of elements
SkylarkType type = list.getValue().validate(env);
env.checkIterable(type, getLocation());
- env.update(list.getKey().getName(), SkylarkType.UNKNOWN, getLocation());
+ list.getKey().validate(env, getLocation(), SkylarkType.UNKNOWN);
}
elementExpression.validate(env);
return SkylarkType.LIST;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java
index 439a4b1..a373594 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SyntaxTreeVisitor.java
@@ -61,8 +61,8 @@
public void visit(ListComprehension node) {
visit(node.getElementExpression());
- for (Map.Entry<Ident, Expression> list : node.getLists()) {
- visit(list.getKey());
+ for (Map.Entry<LValue, Expression> list : node.getLists()) {
+ visit(list.getKey().getExpression());
visit(list.getValue());
}
}
@@ -70,7 +70,7 @@
public void accept(DictComprehension node) {
visit(node.getKeyExpression());
visit(node.getValueExpression());
- visit(node.getLoopVar());
+ visit(node.getLoopVar().getExpression());
visit(node.getListExpression());
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
index b2bfaec..2a1b495 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTest.java
@@ -363,21 +363,21 @@
@Test
public void testDictComprehensions() throws Exception {
- assertEquals(Collections.emptyMap(), eval("{x : x for x in []}"));
- assertEquals(ImmutableMap.of(1, 1, 2, 2), eval("{x : x for x in [1, 2]}"));
+ assertEquals(Collections.emptyMap(), eval("{a : a for a in []}"));
+ assertEquals(ImmutableMap.of(1, 1, 2, 2), eval("{b : b for b in [1, 2]}"));
assertEquals(ImmutableMap.of("a", "v_a", "b", "v_b"),
- eval("{x : 'v_' + x for x in ['a', 'b']}"));
+ eval("{c : 'v_' + c for c in ['a', 'b']}"));
assertEquals(ImmutableMap.of("k_a", "a", "k_b", "b"),
- eval("{'k_' + x : x for x in ['a', 'b']}"));
+ eval("{'k_' + d : d for d in ['a', 'b']}"));
assertEquals(ImmutableMap.of("k_a", "v_a", "k_b", "v_b"),
- eval("{'k_' + x : 'v_' + x for x in ['a', 'b']}"));
+ eval("{'k_' + e : 'v_' + e for e in ['a', 'b']}"));
}
@Test
public void testDictComprehensions_MultipleKey() throws Exception {
assertEquals(ImmutableMap.of(1, 1, 2, 2), eval("{x : x for x in [1, 2, 1]}"));
assertEquals(ImmutableMap.of("ab", "ab", "c", "c"),
- eval("{x : x for x in ['ab', 'c', 'a' + 'b']}"));
+ eval("{y : y for y in ['ab', 'c', 'a' + 'b']}"));
}
@Test