diff options
author | 2015-05-08 14:47:26 +0000 | |
---|---|---|
committer | 2015-05-08 17:01:16 +0000 | |
commit | e3f4ed7e67c9effb30fcf554fa97026857e394fa (patch) | |
tree | 1fb0802139281877086b57edf8d11e09c3de6660 /src/main/java/com/google/devtools/build/lib/syntax | |
parent | 5821646f64394747e8fa68733f362147931e9037 (diff) |
Build language: Support 'not in' operator.
--
MOS_MIGRATED_REVID=93129861
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax')
4 files changed, 45 insertions, 25 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 b5bf4f5160..2a0bd54d68 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 @@ -70,6 +70,33 @@ public final class BinaryOperatorExpression extends Expression { } } + private boolean evalIn(Object lval, Object rval) throws EvalException { + if (rval instanceof SkylarkList) { + for (Object obj : (SkylarkList) rval) { + if (obj.equals(lval)) { + return true; + } + } + return false; + } else if (rval instanceof Collection<?>) { + return ((Collection<?>) rval).contains(lval); + } else if (rval instanceof Map<?, ?>) { + return ((Map<?, ?>) rval).containsKey(lval); + } else if (rval instanceof SkylarkNestedSet) { + return ((SkylarkNestedSet) rval).expandedSet().contains(lval); + } else if (rval instanceof String) { + if (lval instanceof String) { + return ((String) rval).contains((String) lval); + } else { + throw new EvalException(getLocation(), + "in operator only works on strings if the left operand is also a string"); + } + } else { + throw new EvalException(getLocation(), + "in operator only works on lists, tuples, sets, dicts and strings"); + } + } + @Override Object eval(Environment env) throws EvalException, InterruptedException { Object lval = lhs.eval(env); @@ -264,30 +291,11 @@ public final class BinaryOperatorExpression extends Expression { } case IN: { - if (rval instanceof SkylarkList) { - for (Object obj : (SkylarkList) rval) { - if (obj.equals(lval)) { - return true; - } - } - return false; - } else if (rval instanceof Collection<?>) { - return ((Collection<?>) rval).contains(lval); - } else if (rval instanceof Map<?, ?>) { - return ((Map<?, ?>) rval).containsKey(lval); - } else if (rval instanceof SkylarkNestedSet) { - return ((SkylarkNestedSet) rval).expandedSet().contains(lval); - } else if (rval instanceof String) { - if (lval instanceof String) { - return ((String) rval).contains((String) lval); - } else { - throw new EvalException(getLocation(), - "in operator only works on strings if the left operand is also a string"); - } - } else { - throw new EvalException(getLocation(), - "in operator only works on lists, tuples, sets, dicts and strings"); - } + return evalIn(lval, rval); + } + + case NOT_IN: { + return !evalIn(lval, rval); } default: { 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 8849583ac2..73b37cf717 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 @@ -30,6 +30,7 @@ public enum Operator { MULT("*"), NOT("not"), NOT_EQUALS("!="), + NOT_IN("not in"), OR("or"), PERCENT("%"), PLUS("+"); 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 e25ca98b4e..5c363a63f1 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 @@ -114,6 +114,7 @@ class Parser { .put(TokenKind.LESS_EQUALS, Operator.LESS_EQUALS) .put(TokenKind.MINUS, Operator.MINUS) .put(TokenKind.NOT_EQUALS, Operator.NOT_EQUALS) + .put(TokenKind.NOT_IN, Operator.NOT_IN) .put(TokenKind.OR, Operator.OR) .put(TokenKind.PERCENT, Operator.PERCENT) .put(TokenKind.SLASH, Operator.DIVIDE) @@ -134,7 +135,7 @@ class Parser { EnumSet.of(Operator.AND), 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.GREATER, Operator.GREATER_EQUALS, Operator.IN, Operator.NOT_IN), EnumSet.of(Operator.MINUS, Operator.PLUS), EnumSet.of(Operator.DIVIDE, Operator.MULT, Operator.PERCENT)); @@ -924,6 +925,15 @@ class Parser { // The loop is not strictly needed, but it prevents risks of stack overflow. Depth is // limited to number of different precedence levels (operatorPrecedence.size()). for (;;) { + + if (token.kind == TokenKind.NOT) { + // If NOT appears when we expect a binary operator, it must be followed by IN. + // Since the code expects every operator to be a single token, we push a NOT_IN token. + expect(TokenKind.NOT); + expect(TokenKind.IN); + pushToken(new Token(TokenKind.NOT_IN, token.left, token.right)); + } + if (!binaryOperators.containsKey(token.kind)) { return expr; } 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 57f5fc4876..0ada226f53 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 @@ -62,6 +62,7 @@ public enum TokenKind { NONLOCAL("nonlocal"), NOT("not"), NOT_EQUALS("!="), + NOT_IN("not in"), OR("or"), OUTDENT("outdent"), PASS("pass"), |