Skylark: Slice operations now accept a step argument.
--
MOS_MIGRATED_REVID=110446625
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 1214d8d..c5f612f 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
@@ -713,16 +713,15 @@
return receiver;
}
- // substring_suffix ::= '[' expression? ':' expression? ']'
+ // substring_suffix ::= '[' expression? ':' expression? ':' expression? ']'
private Expression parseSubstringSuffix(int start, Expression receiver) {
List<Argument.Passed> args = new ArrayList<>();
Expression startExpr;
- Expression endExpr;
expect(TokenKind.LBRACKET);
int loc1 = token.left;
if (token.kind == TokenKind.COLON) {
- startExpr = setLocation(new IntegerLiteral(0), token.left, token.right);
+ startExpr = setLocation(new Identifier("None"), token.left, token.right);
} else {
startExpr = parseExpression();
}
@@ -734,20 +733,38 @@
start, token.right);
}
// This is a slice (or substring)
- expect(TokenKind.COLON);
- int loc2 = token.left;
- if (token.kind == TokenKind.RBRACKET) {
- endExpr = setLocation(new IntegerLiteral(Integer.MAX_VALUE), token.left, token.right);
- } else {
- endExpr = parseNonTupleExpression();
- }
+ args.add(parseSliceArgument(new Identifier("None")));
+ args.add(parseSliceArgument(new IntegerLiteral(1)));
expect(TokenKind.RBRACKET);
-
- args.add(setLocation(new Argument.Positional(endExpr), loc2, endExpr));
return makeFuncallExpression(receiver, new Identifier("$slice"), args,
start, token.right);
}
+ /**
+ * Parses {@code [':' [expr]]} which can either be the end or the step argument of a slice
+ * operation. If no such expression is found, this method returns an argument that represents
+ * {@code defaultValue}.
+ */
+ private Argument.Positional parseSliceArgument(Expression defaultValue) {
+ Expression explicitArg = getSliceEndOrStepExpression();
+ Expression argValue =
+ (explicitArg == null) ? setLocation(defaultValue, token.left, token.right) : explicitArg;
+ return setLocation(new Argument.Positional(argValue), token.left, argValue);
+ }
+
+ private Expression getSliceEndOrStepExpression() {
+ // There has to be a colon before any end or slice argument.
+ // However, if the next token thereafter is another colon or a right bracket, no argument value
+ // was specified.
+ if (token.kind == TokenKind.COLON) {
+ expect(TokenKind.COLON);
+ if (token.kind != TokenKind.COLON && token.kind != TokenKind.RBRACKET) {
+ return parseNonTupleExpression();
+ }
+ }
+ return null;
+ }
+
// Equivalent to 'exprlist' rule in Python grammar.
// loop_variables ::= primary_with_suffix ( ',' primary_with_suffix )* ','?
private Expression parseForLoopVariables() {