diff options
author | 2015-08-24 14:50:00 +0000 | |
---|---|---|
committer | 2015-08-25 07:39:59 +0000 | |
commit | 092f13b79ac6a1b5ef065e83929eb1403d69f975 (patch) | |
tree | 3e5e753cfe6860f8cfd5a347c36c35c404578025 /src | |
parent | ed5955c5a16996a3b630d7f95206d67d0d0c6380 (diff) |
Introduce '|' operator for set union.
--
MOS_MIGRATED_REVID=101363350
Diffstat (limited to 'src')
7 files changed, 41 insertions, 31 deletions
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 65ea8df75d..9d489e04a3 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 @@ -121,18 +121,22 @@ public final class BinaryOperatorExpression extends Expression { Object rval = rhs.eval(env); switch (operator) { - case PLUS: { + case PLUS: return plus(lval, rval); - } - case MINUS: { + case PIPE: + if (lval instanceof SkylarkNestedSet) { + return new SkylarkNestedSet((SkylarkNestedSet) lval, rval, getLocation()); + } + break; + + case MINUS: if (lval instanceof Integer && rval instanceof Integer) { return ((Integer) lval).intValue() - ((Integer) rval).intValue(); } break; - } - case MULT: { + case MULT: // int * int if (lval instanceof Integer && rval instanceof Integer) { return ((Integer) lval).intValue() * ((Integer) rval).intValue(); @@ -148,9 +152,8 @@ public final class BinaryOperatorExpression extends Expression { return Strings.repeat((String) rval, ((Integer) lval).intValue()); } break; - } - case DIVIDE: { + case DIVIDE: // int / int if (lval instanceof Integer && rval instanceof Integer) { if (rval.equals(0)) { @@ -163,9 +166,9 @@ public final class BinaryOperatorExpression extends Expression { // We want to follow Python semantics, so we use float division and round down. return (int) Math.floor(new Double((Integer) lval) / (Integer) rval); } - } + break; - case PERCENT: { + case PERCENT: // int % int if (lval instanceof Integer && rval instanceof Integer) { if (rval.equals(0)) { @@ -207,43 +210,33 @@ public final class BinaryOperatorExpression extends Expression { } } break; - } - case EQUALS_EQUALS: { + case EQUALS_EQUALS: return lval.equals(rval); - } - case NOT_EQUALS: { + case NOT_EQUALS: return !lval.equals(rval); - } - case LESS: { + case LESS: return compare(lval, rval) < 0; - } - case LESS_EQUALS: { + case LESS_EQUALS: return compare(lval, rval) <= 0; - } - case GREATER: { + case GREATER: return compare(lval, rval) > 0; - } - case GREATER_EQUALS: { + case GREATER_EQUALS: return compare(lval, rval) >= 0; - } - case IN: { + case IN: return evalIn(lval, rval); - } - case NOT_IN: { + case NOT_IN: return !evalIn(lval, rval); - } - default: { + default: throw new AssertionError("Unsupported binary operator: " + operator); - } } // endswitch // NB: this message format is identical to that used by CPython 2.7.6 or 3.4.0, @@ -310,6 +303,7 @@ public final class BinaryOperatorExpression extends Expression { getLocation()); } + // TODO(bazel-team): Remove this case. Union of sets should use '|' instead of '+'. if (lval instanceof SkylarkNestedSet) { return new SkylarkNestedSet((SkylarkNestedSet) lval, rval, getLocation()); } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java index 90b40e3f2c..9d148861bf 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Lexer.java @@ -698,6 +698,10 @@ public final class Lexer { addToken(new Token(TokenKind.MINUS, pos - 1, pos)); break; } + case '|': { + addToken(new Token(TokenKind.PIPE, pos - 1, pos)); + break; + } case '=': { addToken(new Token(TokenKind.EQUALS, pos - 1, pos)); break; diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Operator.java b/src/main/java/com/google/devtools/build/lib/syntax/Operator.java index 73b37cf717..218eee8e7d 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Operator.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Operator.java @@ -33,6 +33,7 @@ public enum Operator { NOT_IN("not in"), OR("or"), PERCENT("%"), + PIPE("|"), PLUS("+"); private final String name; diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java index 8f590472dc..6334673aa1 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java @@ -134,6 +134,7 @@ class Parser { .put(TokenKind.PERCENT, Operator.PERCENT) .put(TokenKind.SLASH, Operator.DIVIDE) .put(TokenKind.PLUS, Operator.PLUS) + .put(TokenKind.PIPE, Operator.PIPE) .put(TokenKind.STAR, Operator.MULT) .build(); @@ -151,6 +152,7 @@ class Parser { EnumSet.of(Operator.NOT), EnumSet.of(Operator.EQUALS_EQUALS, Operator.NOT_EQUALS, Operator.LESS, Operator.LESS_EQUALS, Operator.GREATER, Operator.GREATER_EQUALS, Operator.IN, Operator.NOT_IN), + EnumSet.of(Operator.PIPE), EnumSet.of(Operator.MINUS, Operator.PLUS), EnumSet.of(Operator.DIVIDE, Operator.MULT, Operator.PERCENT)); diff --git a/src/main/java/com/google/devtools/build/lib/syntax/TokenKind.java b/src/main/java/com/google/devtools/build/lib/syntax/TokenKind.java index 0ada226f53..18ba037799 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/TokenKind.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/TokenKind.java @@ -67,6 +67,7 @@ public enum TokenKind { OUTDENT("outdent"), PASS("pass"), PERCENT("%"), + PIPE("|"), PLUS("+"), PLUS_EQUALS("+="), RAISE("raise"), diff --git a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java index 7be1c86545..b2d661b7d4 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/EvaluationTestCase.java @@ -128,7 +128,7 @@ public class EvaluationTestCase { setFailFast(true); try { eval(input); - fail(); + fail("Expected error '" + msg + "' but got no error"); } catch (IllegalArgumentException | EvalException e) { assertThat(e).hasMessage(msg); } @@ -137,7 +137,7 @@ public class EvaluationTestCase { public void checkEvalErrorContains(String msg, String... input) throws Exception { try { eval(input); - fail(); + fail("Expected error containing '" + msg + "' but got no error"); } catch (IllegalArgumentException | EvalException e) { assertThat(e.getMessage()).contains(msg); } @@ -146,7 +146,7 @@ public class EvaluationTestCase { public void checkEvalErrorStartsWith(String msg, String... input) throws Exception { try { eval(input); - fail(); + fail("Expected error starting with '" + msg + "' but got no error"); } catch (IllegalArgumentException | EvalException e) { assertThat(e.getMessage()).startsWith(msg); } 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 e794aa7799..22c715358e 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 @@ -609,6 +609,14 @@ public class SkylarkEvaluationTest extends EvaluationTest { } @Test + public void testUnionSet() throws Exception { + new SkylarkTest() + .testStatement("str(set([1, 3]) | set([1, 2]))", "set([1, 2, 3])") + .testStatement("str(set([1, 2]) | [1, 3])", "set([1, 2, 3])") + .testIfExactError("unsupported operand type(s) for |: 'int' and 'int'", "2 | 4"); + } + + @Test public void testClassObjectCannotAccessNestedSet() throws Exception { new SkylarkTest() .update("mock", new MockClassObject()) |