aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Vladimir Moskva <vladmos@google.com>2016-08-23 15:04:54 +0000
committerGravatar John Cater <jcater@google.com>2016-08-23 22:57:28 +0000
commit1077038d02a4151e156622076896eca1e4f28726 (patch)
tree899f51d249d452e0a8a100648e3de2c27e1a29d1
parent63d0848819137c620dca53c4cf762ee6bb4abc3b (diff)
More flexible LValue syntax
-- MOS_MIGRATED_REVID=131056178
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/LValue.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java19
-rw-r--r--src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java7
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java44
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java6
6 files changed, 69 insertions, 35 deletions
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 729dd0c160..ef5bdb78de 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
@@ -84,39 +84,39 @@ public class LValue implements Serializable {
}
// Support syntax for setting an element in an array, e.g. a[5] = 2
- // We currently do not allow slices (e.g. a[2:6] = [3]).
+ // TODO: We currently do not allow slices (e.g. a[2:6] = [3]).
if (lvalue instanceof FuncallExpression) {
FuncallExpression func = (FuncallExpression) lvalue;
List<Argument.Passed> args = func.getArguments();
if (func.getFunction().getName().equals("$index")
- && func.getObject() instanceof Identifier
&& args.size() == 1) {
Object key = args.get(0).getValue().eval(env);
- assignItem(env, loc, (Identifier) func.getObject(), key, result);
+ Object evaluatedObject = func.getObject().eval(env);
+ assignItem(env, loc, evaluatedObject, key, result);
return;
}
}
-
throw new EvalException(loc,
"can only assign to variables and tuples, not to '" + lvalue + "'");
}
- // Since dict is still immutable, the expression 'a[x] = b' creates a new dictionary and
- // assigns it to 'a'.
@SuppressWarnings("unchecked")
private static void assignItem(
- Environment env, Location loc, Identifier ident, Object key, Object value)
+ Environment env, Location loc, Object o, Object key, Object value)
throws EvalException, InterruptedException {
- Object o = ident.eval(env);
- if (!(o instanceof SkylarkDict)) {
+ if (o instanceof SkylarkDict) {
+ SkylarkDict<Object, Object> dict = (SkylarkDict<Object, Object>) o;
+ dict.put(key, value, loc, env);
+ } else if (o instanceof SkylarkList) {
+ SkylarkList<Object> list = (SkylarkList<Object>) o;
+ list.set(key, value, loc, env);
+ } else {
throw new EvalException(
loc,
- "can only assign an element in a dictionary, not in a '"
+ "can only assign an element in a dictionary or a list, not in a '"
+ EvalUtils.getDataTypeName(o)
+ "'");
}
- SkylarkDict<Object, Object> dict = (SkylarkDict<Object, Object>) o;
- dict.put(key, value, loc, env);
}
/**
@@ -158,7 +158,7 @@ public class LValue implements Serializable {
}
if (expr instanceof FuncallExpression) {
FuncallExpression func = (FuncallExpression) expr;
- if (func.getFunction().getName().equals("$index") && func.getObject() instanceof Identifier) {
+ if (func.getFunction().getName().equals("$index")) {
return;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index 4b39a7d1c6..0df0aa4336 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -82,7 +82,7 @@ public class MethodLibrary {
return str.substring(start, stop);
}
- private static int getListIndex(int index, int listSize, Location loc)
+ public static int getListIndex(int index, int listSize, Location loc)
throws ConversionException, EvalException {
// Get the nth element in the list
if (index < 0) {
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
index 7098a1d790..05cf33b176 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
@@ -121,6 +121,25 @@ public abstract class SkylarkList<E> extends MutableCollection<E> implements Lis
throw new UnsupportedOperationException();
}
+ /**
+ * Put an entry into a SkylarkList.
+ * @param key the index
+ * @param value the associated value
+ * @param loc a {@link Location} in case of error
+ * @param env an {@link Environment}, to check Mutability
+ * @throws EvalException if the key is invalid
+ */
+ public void set(Object key, E value, Location loc, Environment env) throws EvalException {
+ checkMutable(loc, env);
+ if (!(key instanceof Integer)) {
+ throw new EvalException(loc, "list indices must be integers, not '" + key + '"');
+ }
+ int index = ((Integer) key).intValue();
+ List list = getContentsUnsafe();
+ index = MethodLibrary.getListIndex(index, list.size(), loc);
+ list.set(index, value);
+ }
+
// Other methods
@Override
public void write(Appendable buffer, char quotationMark) {
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
index f8823b9907..3e677be5b9 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -908,11 +908,12 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase {
}
@Test
- public void testStructDictMembersAreImmutable() throws Exception {
- checkErrorContains(
- "can only assign to variables and tuples, not to 's.x['b']'",
+ public void testStructDictMembersAreMutable() throws Exception {
+ eval(
"s = struct(x = {'a' : 1})",
"s.x['b'] = 2\n");
+ assertThat(((SkylarkClassObject) lookup("s")).getValue("x"))
+ .isEqualTo(ImmutableMap.of("a", 1, "b", 2));
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
index 8f0a6f0c2f..a0a09e8709 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
@@ -868,6 +868,36 @@ public class SkylarkEvaluationTest extends EvaluationTest {
}
@Test
+ public void testNestedDictAssignmentAsLValue() throws Exception {
+ new SkylarkTest().setUp("def func():",
+ " d = {'a' : 1}",
+ " e = {'d': d}",
+ " e['d']['b'] = 2",
+ " return e",
+ "e = func()").testLookup("e", ImmutableMap.of("d", ImmutableMap.of("a", 1, "b", 2)));
+ }
+
+ @Test
+ public void testListAssignmentAsLValue() throws Exception {
+ new SkylarkTest().setUp("def func():",
+ " a = [1, 2]",
+ " a[1] = 3",
+ " a[-2] = 4",
+ " return a",
+ "a = str(func())").testLookup("a", "[4, 3]");
+ }
+
+ @Test
+ public void testNestedListAssignmentAsLValue() throws Exception {
+ new SkylarkTest().setUp("def func():",
+ " d = [1, 2]",
+ " e = [3, d]",
+ " e[1][1] = 4",
+ " return e",
+ "e = str(func())").testLookup("e", "[3, [1, 4]]");
+ }
+
+ @Test
public void testDictTupleAssignmentAsLValue() throws Exception {
new SkylarkTest().setUp("def func():",
" d = {'a' : 1}",
@@ -902,20 +932,6 @@ public class SkylarkEvaluationTest extends EvaluationTest {
}
@Test
- public void testListIndexAsLValueAsLValue() throws Exception {
- new SkylarkTest()
- .testIfErrorContains(
- "can only assign an element in a dictionary, not in a 'list'",
- "def id(l):",
- " return l",
- "def func():",
- " l = id([1])",
- " l[0] = 2",
- " return l",
- "l = func()");
- }
-
- @Test
public void testTopLevelDict() throws Exception {
new SkylarkTest().setUp("if 1:",
" v = 'a'",
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
index b7bd6f6306..661b8636a2 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
@@ -139,13 +139,11 @@ public class ValidationTest extends EvaluationTestCase {
@Test
public void testFuncReturningDictAssignmentAsLValue() throws Exception {
- checkError(
- "can only assign to variables and tuples, not to 'my_dict()['b']'",
+ parse(
"def my_dict():",
" return {'a': 1}",
"def func():",
- " my_dict()['b'] = 2",
- " return d\n");
+ " my_dict()['b'] = 2");
}
@Test