@@ -203,6 +203,32 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
203203 // and must not be taken as the JSON path operator
204204 private int mapKeyDepth = 0;
205205
206+ // opening brackets of the enclosing subscripts: a ":" at the top level of a subscript
207+ // separates the bounds of a slice such as l[1:3] and is not the JSON path operator
208+ private final Deque<Token> subscriptOpenings = new ArrayDeque<Token>();
209+
210+ /**
211+ * Whether the pending ":" is at the top level of the innermost subscript, i.e. not nested
212+ * in brackets, braces, parentheses or a CASE expression opened inside that subscript.
213+ */
214+ private boolean isSliceColonAhead() {
215+ Token colon = getToken(1);
216+ if (subscriptOpenings.isEmpty() || !":".equals(colon.image)) {
217+ return false;
218+ }
219+ int depth = 0;
220+ for (Token t = subscriptOpenings.peek().next; t != null && t != colon; t = t.next) {
221+ if (t.kind == K_CASE || "(".equals(t.image) || "[".equals(t.image)
222+ || "{".equals(t.image)) {
223+ depth++;
224+ } else if (t.kind == K_END || ")".equals(t.image) || "]".equals(t.image)
225+ || "}".equals(t.image)) {
226+ depth--;
227+ }
228+ }
229+ return depth == 0;
230+ }
231+
206232 private Expression createOutputArgument(Expression argument) throws ParseException {
207233 Expression value = argument;
208234 if (argument instanceof VariableAssignment) {
@@ -1659,6 +1685,10 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
16591685 || next.kind >= MIN_NON_RESERVED_WORD && next.kind <= MAX_NON_RESERVED_WORD;
16601686 }
16611687
1688+ private static boolean isSliceDelimiter(Token token) {
1689+ return ":".equals(token.image) || "]".equals(token.image) || ",".equals(token.image);
1690+ }
1691+
16621692 private boolean isAliasAhead() {
16631693 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
16641694 return false;
@@ -7009,7 +7039,7 @@ Column Column() #Column :
70097039 // @todo: we better should return a SEQUENCE instead of a COLUMN
70107040 [ LOOKAHEAD(2) "." <K_NEXTVAL> { data.getNames().add("nextval"); } ]
70117041
7012- [ LOOKAHEAD(2) arrayConstructor = ArrayConstructor(false ) ]
7042+ [ LOOKAHEAD(2) arrayConstructor = Subscript( ) ]
70137043 {
70147044 Column col = createColumn(data.getNames(), data.getDelimiters());
70157045 if (tk != null) { col.withCommentText(tk.image); }
@@ -11510,29 +11540,85 @@ Expression AddChain():
1151011540
1151111541Expression ArrayExpression(Expression obj): {
1151211542 Expression expr;
11543+ } {
11544+ expr = ArraySubscript(obj)
11545+ ( LOOKAHEAD(2) expr = ArraySubscript(expr) )*
11546+ { return expr; }
11547+ }
11548+
11549+ ArrayExpression ArraySubscript(Expression obj): {
1151311550 Expression idxExpr = null;
11514- Expression startExpr = null;
11515- Expression stopExpr = null ;
11551+ RangeExpression slice = null;
11552+ Token opening ;
1151611553} {
11517- "["
11518- [LOOKAHEAD(3) idxExpr = ArrayIndexExpression()]
11554+ opening="["
11555+ try {
11556+ { subscriptOpenings.push(opening); }
11557+ [ LOOKAHEAD(3, { !":".equals(getToken(1).image) }) idxExpr = ArrayIndexExpression() ]
11558+ [ slice = SliceTail(idxExpr) ]
11559+ } finally {
11560+ subscriptOpenings.pop();
11561+ }
11562+ "]"
11563+ {
11564+ return slice == null
11565+ ? new ArrayExpression(obj, idxExpr, null, null)
11566+ : new ArrayExpression(obj, null, slice.getStartExpression(),
11567+ slice.getEndExpression()).withStepExpression(slice.getStepExpression());
11568+ }
11569+ }
11570+
11571+ /**
11572+ * The rest of a slice after its optional start: {@code :[stop][:[step]]}. As in DuckDB, a
11573+ * {@code -} stop before a step stands for the end of the list, as in {@code l[1:-:2]}.
11574+ */
11575+ RangeExpression SliceTail(Expression start): {
11576+ Expression stop = null;
11577+ Expression step = null;
11578+ } {
11579+ ":"
11580+ [
11581+ LOOKAHEAD("-" ":") "-"
11582+ |
11583+ LOOKAHEAD({ !isSliceDelimiter(getToken(1)) }) stop = Expression()
11584+ ]
11585+ [
11586+ ":" [ LOOKAHEAD({ !isSliceDelimiter(getToken(1)) }) step = Expression() ]
11587+ ]
11588+ { return new RangeExpression(start, stop).withStepExpression(step); }
11589+ }
11590+
11591+ /** A subscript of a column, such as {@code col[1]}, {@code col[1, 2]} or {@code col[1:3]}. */
11592+ ArrayConstructor Subscript() : {
11593+ ExpressionList<Expression> expList = new ExpressionList<Expression>();
11594+ Expression exp;
11595+ Token opening;
11596+ } {
11597+ opening="["
11598+ try {
11599+ { subscriptOpenings.push(opening); }
1151911600 [
11520- (":" { startExpr=idxExpr; idxExpr=null; })
11521- [stopExpr = SimpleExpression()]
11601+ exp=SubscriptElement() { expList.add(exp); }
11602+ ( "," exp=SubscriptElement() { expList.add(exp); } )*
1152211603 ]
11604+ } finally {
11605+ subscriptOpenings.pop();
11606+ }
1152311607 "]"
11524- { expr = new ArrayExpression(obj, idxExpr, startExpr, stopExpr); }
11608+ { return new ArrayConstructor(expList, false); }
11609+ }
11610+
11611+ Expression SubscriptElement():
11612+ {
11613+ Expression expression = null;
11614+ }
11615+ {
1152511616 (
11526- LOOKAHEAD(2) "["
11527- [LOOKAHEAD(3) idxExpr = ArrayIndexExpression()]
11528- [
11529- (":" { startExpr=idxExpr; idxExpr=null; })
11530- [stopExpr = SimpleExpression()]
11531- ]
11532- "]"
11533- { expr = new ArrayExpression(expr, idxExpr, startExpr, stopExpr); }
11534- )*
11535- { return expr; }
11617+ LOOKAHEAD({ ":".equals(getToken(1).image) }) expression=SliceTail(null)
11618+ |
11619+ expression=Expression() [ expression=SliceTail(expression) ]
11620+ )
11621+ { return expression; }
1153611622}
1153711623
1153811624/**
@@ -11793,7 +11879,7 @@ Expression PrimaryExpression() #PrimaryExpression:
1179311879 // Check for JSON operands
1179411880 [
1179511881 LOOKAHEAD(2, { !isPostgreSqlJsonAccess(getToken(1))
11796- && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0)
11882+ && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0 && !isSliceColonAhead() )
1179711883 || !":".equals(getToken(1).image)) }) (
1179811884 LOOKAHEAD(2) (
1179911885 token="->"
@@ -12161,7 +12247,7 @@ JsonExpression JsonExpression(Expression expr, List<Map.Entry<Expression, String
1216112247
1216212248 (
1216312249 LOOKAHEAD(2, { !isPostgreSqlJsonAccess(getToken(1))
12164- && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0)
12250+ && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0 && !isSliceColonAhead() )
1216512251 || !":".equals(getToken(1).image)) }) (
1216612252 token="->"
1216712253 |
0 commit comments