Build language supports list comparison.
--
MOS_MIGRATED_REVID=91289047
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
index 210d1f5..6eaf45e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
@@ -62,8 +62,29 @@
return lhs + " " + operator + " " + rhs;
}
+ /**
+ * Compares two lists, following on Python semantics.
+ *
+ * <p>Elements are compared until two elements are not equal or we reach the end of a list.
+ */
+ private int compareLists(SkylarkList lval, SkylarkList rval) throws EvalException {
+ for (int i = 0; i < Math.min(lval.size(), rval.size()); i++) {
+ int cmp = compare(lval.get(i), rval.get(i));
+ if (cmp != 0) {
+ return cmp;
+ }
+ }
+ return Integer.compare(lval.size(), rval.size());
+ }
+
@SuppressWarnings("unchecked")
private int compare(Object lval, Object rval) throws EvalException {
+ lval = SkylarkType.convertToSkylark(lval, getLocation());
+ rval = SkylarkType.convertToSkylark(rval, getLocation());
+
+ if (lval instanceof SkylarkList && rval instanceof SkylarkList) {
+ return compareLists((SkylarkList) lval, (SkylarkList) rval);
+ }
if (!(lval instanceof Comparable)) {
throw new EvalException(getLocation(), lval + " is not comparable");
}
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 37042ed..cb54532 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
@@ -190,13 +190,33 @@
}
@Test
- public void testCompareStringInt() throws Exception {
- checkEvalError("Cannot compare string with int", "'a' >= 1");
+ public void testListComparison() throws Exception {
+ assertThat(eval("[] < [1]")).isEqualTo(true);
+ assertThat(eval("[1] < [1, 1]")).isEqualTo(true);
+ assertThat(eval("[1, 1] < [1, 2]")).isEqualTo(true);
+ assertThat(eval("[1, 2] < [1, 2, 3]")).isEqualTo(true);
+ assertThat(eval("[1, 2, 3] <= [1, 2, 3]")).isEqualTo(true);
+
+ assertThat(eval("['a', 'b'] > ['a']")).isEqualTo(true);
+ assertThat(eval("['a', 'b'] >= ['a']")).isEqualTo(true);
+ assertThat(eval("['a', 'b'] < ['a']")).isEqualTo(false);
+ assertThat(eval("['a', 'b'] <= ['a']")).isEqualTo(false);
+
+ assertThat(eval("('a', 'b') > ('a', 'b')")).isEqualTo(false);
+ assertThat(eval("('a', 'b') >= ('a', 'b')")).isEqualTo(true);
+ assertThat(eval("('a', 'b') < ('a', 'b')")).isEqualTo(false);
+ assertThat(eval("('a', 'b') <= ('a', 'b')")).isEqualTo(true);
+
+ assertThat(eval("[[1, 1]] > [[1, 1], []]")).isEqualTo(false);
+ assertThat(eval("[[1, 1]] < [[1, 1], []]")).isEqualTo(true);
+
+ checkEvalError("Cannot compare int with string", "[1] < ['a']");
+ checkEvalError("[1] is not comparable", "[1] < 1");
}
@Test
- public void testNotComparable() throws Exception {
- checkEvalError("[1, 2] is not comparable", "[1, 2] < [1, 3]");
+ public void testCompareStringInt() throws Exception {
+ checkEvalError("Cannot compare string with int", "'a' >= 1");
}
@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 904eb70..c08f1a3 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
@@ -839,12 +839,6 @@
@Override
@Test
- public void testNotComparable() throws Exception {
- checkEvalError("[1, 2] is not comparable", "[1, 2] < [1, 3]");
- }
-
- @Override
- @Test
public void testListComprehensionsMultipleVariablesFail() throws Exception {
checkEvalError("lvalue has length 3, but rvalue has has length 2",
"def foo (): return [x + y for x, y, z in [(1, 2), (3, 4)]]",