diff options
author | 2015-04-15 14:23:35 +0000 | |
---|---|---|
committer | 2015-04-15 16:21:36 +0000 | |
commit | 8a52826b593b8e46aa4a09829c9ce979cacb6f67 (patch) | |
tree | 3cb26557245e0ba5e0d17e6800590bdee17babf6 /src/main/java/com/google/devtools/build/lib/syntax | |
parent | fc9140ecc662f46a415df11b35430fcd264328ad (diff) |
Build language: Implement integer division
--
MOS_MIGRATED_REVID=91192716
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax')
5 files changed, 34 insertions, 2 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 ac47b63731..210d1f5027 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 @@ -184,13 +184,37 @@ public final class BinaryOperatorExpression extends Expression { break; } + case DIVIDE: { + // int / int + if (lval instanceof Integer && rval instanceof Integer) { + if (rval.equals(0)) { + throw new EvalException(getLocation(), "integer division by zero"); + } + // Integer division doesn't give the same result in Java and in Python 2 with + // negative numbers. + // Java: -7/3 = -2 + // Python: -7/3 = -3 + // We want to follow Python semantics, so we use float division and round down. + return (int) Math.floor(new Double((Integer) lval) / (Integer) rval); + } + } + case PERCENT: { // int % int if (lval instanceof Integer && rval instanceof Integer) { if (rval.equals(0)) { throw new EvalException(getLocation(), "integer modulo by zero"); } - return ((Integer) lval).intValue() % ((Integer) rval).intValue(); + // Python and Java implement division differently, wrt negative numbers. + // In Python, sign of the result is the sign of the divisor. + int div = (Integer) rval; + int result = ((Integer) lval).intValue() % Math.abs(div); + if (result > 0 && div < 0) { + result += div; // make the result negative + } else if (result < 0 && div > 0) { + result += div; // make the result positive + } + return result; } // string % tuple, string % dict, string % anything-else 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 86b8de7b1d..77cdf3f5ee 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 @@ -685,6 +685,10 @@ public final class Lexer { addToken(new Token(TokenKind.PERCENT, pos - 1, pos)); break; } + case '/': { + addToken(new Token(TokenKind.SLASH, pos - 1, pos)); + break; + } case ';': { addToken(new Token(TokenKind.SEMI, 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 628570e2d5..8849583ac2 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 @@ -19,6 +19,7 @@ package com.google.devtools.build.lib.syntax; public enum Operator { AND("and"), + DIVIDE("/"), EQUALS_EQUALS("=="), GREATER(">"), GREATER_EQUALS(">="), 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 75b8db8b4c..e993821dd8 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 @@ -87,6 +87,7 @@ class Parser { TokenKind.PLUS, TokenKind.MINUS, TokenKind.PERCENT, + TokenKind.SLASH, TokenKind.RPAREN, TokenKind.RBRACKET); @@ -115,6 +116,7 @@ class Parser { .put(TokenKind.NOT_EQUALS, Operator.NOT_EQUALS) .put(TokenKind.OR, Operator.OR) .put(TokenKind.PERCENT, Operator.PERCENT) + .put(TokenKind.SLASH, Operator.DIVIDE) .put(TokenKind.PLUS, Operator.PLUS) .put(TokenKind.STAR, Operator.MULT) .build(); @@ -134,7 +136,7 @@ class Parser { EnumSet.of(Operator.EQUALS_EQUALS, Operator.NOT_EQUALS, Operator.LESS, Operator.LESS_EQUALS, Operator.GREATER, Operator.GREATER_EQUALS, Operator.IN), EnumSet.of(Operator.MINUS, Operator.PLUS), - EnumSet.of(Operator.MULT, Operator.PERCENT)); + EnumSet.of(Operator.DIVIDE, Operator.MULT, Operator.PERCENT)); private Iterator<Token> tokens = null; private int errorsCount; 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 866b9b978d..57f5fc4876 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 @@ -74,6 +74,7 @@ public enum TokenKind { RETURN("return"), RPAREN(")"), SEMI(";"), + SLASH("/"), STAR("*"), STAR_STAR("**"), STRING("string"), |