@@ -203,6 +203,10 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
203203 // and must not be taken as the JSON path operator
204204 private int mapKeyDepth = 0;
205205
206+ // depth of subscripts: a ":" there separates the bounds of a slice such as l[1:3]
207+ // and must not be taken as the JSON path operator
208+ private int subscriptDepth = 0;
209+
206210 private Expression createOutputArgument(Expression argument) throws ParseException {
207211 Expression value = argument;
208212 if (argument instanceof VariableAssignment) {
@@ -1571,6 +1575,10 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
15711575 || next.kind >= MIN_NON_RESERVED_WORD && next.kind <= MAX_NON_RESERVED_WORD;
15721576 }
15731577
1578+ private static boolean isSliceDelimiter(Token token) {
1579+ return ":".equals(token.image) || "]".equals(token.image) || ",".equals(token.image);
1580+ }
1581+
15741582 private boolean isAliasAhead() {
15751583 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
15761584 return false;
@@ -6884,7 +6892,7 @@ Column Column() #Column :
68846892 // @todo: we better should return a SEQUENCE instead of a COLUMN
68856893 [ LOOKAHEAD(2) "." <K_NEXTVAL> { data.getNames().add("nextval"); } ]
68866894
6887- [ LOOKAHEAD(2) arrayConstructor = ArrayConstructor(false ) ]
6895+ [ LOOKAHEAD(2) arrayConstructor = Subscript( ) ]
68886896 {
68896897 Column col = createColumn(data.getNames(), data.getDelimiters());
68906898 if (tk != null) { col.withCommentText(tk.image); }
@@ -11341,29 +11349,83 @@ Expression AddChain():
1134111349
1134211350Expression ArrayExpression(Expression obj): {
1134311351 Expression expr;
11352+ } {
11353+ expr = ArraySubscript(obj)
11354+ ( LOOKAHEAD(2) expr = ArraySubscript(expr) )*
11355+ { return expr; }
11356+ }
11357+
11358+ ArrayExpression ArraySubscript(Expression obj): {
1134411359 Expression idxExpr = null;
11345- Expression startExpr = null;
11346- Expression stopExpr = null;
11360+ RangeExpression slice = null;
11361+ } {
11362+ "["
11363+ try {
11364+ { subscriptDepth++; }
11365+ [ LOOKAHEAD(3, { !":".equals(getToken(1).image) }) idxExpr = ArrayIndexExpression() ]
11366+ [ slice = SliceTail(idxExpr) ]
11367+ } finally {
11368+ subscriptDepth--;
11369+ }
11370+ "]"
11371+ {
11372+ return slice == null
11373+ ? new ArrayExpression(obj, idxExpr, null, null)
11374+ : new ArrayExpression(obj, null, slice.getStartExpression(),
11375+ slice.getEndExpression()).withStepExpression(slice.getStepExpression());
11376+ }
11377+ }
11378+
11379+ /**
11380+ * The rest of a slice after its optional start: {@code :[stop][:[step]]}. As in DuckDB, a
11381+ * {@code -} stop before a step stands for the end of the list, as in {@code l[1:-:2]}.
11382+ */
11383+ RangeExpression SliceTail(Expression start): {
11384+ Expression stop = null;
11385+ Expression step = null;
11386+ } {
11387+ ":"
11388+ [
11389+ LOOKAHEAD("-" ":") "-"
11390+ |
11391+ LOOKAHEAD({ !isSliceDelimiter(getToken(1)) }) stop = Expression()
11392+ ]
11393+ [
11394+ ":" [ LOOKAHEAD({ !isSliceDelimiter(getToken(1)) }) step = Expression() ]
11395+ ]
11396+ { return new RangeExpression(start, stop).withStepExpression(step); }
11397+ }
11398+
11399+ /** A subscript of a column, such as {@code col[1]}, {@code col[1, 2]} or {@code col[1:3]}. */
11400+ ArrayConstructor Subscript() : {
11401+ ExpressionList<Expression> expList = new ExpressionList<Expression>();
11402+ Expression exp;
1134711403} {
1134811404 "["
11349- [LOOKAHEAD(3) idxExpr = ArrayIndexExpression()]
11405+ try {
11406+ { subscriptDepth++; }
1135011407 [
11351- (":" { startExpr=idxExpr; idxExpr=null; })
11352- [stopExpr = SimpleExpression()]
11408+ exp=SubscriptElement() { expList.add(exp); }
11409+ ( "," exp=SubscriptElement() { expList.add(exp); } )*
1135311410 ]
11411+ } finally {
11412+ subscriptDepth--;
11413+ }
1135411414 "]"
11355- { expr = new ArrayExpression(obj, idxExpr, startExpr, stopExpr); }
11415+ { return new ArrayConstructor(expList, false); }
11416+ }
11417+
11418+ Expression SubscriptElement():
11419+ {
11420+ Expression expression = null;
11421+ }
11422+ {
1135611423 (
11357- LOOKAHEAD(2) "["
11358- [LOOKAHEAD(3) idxExpr = ArrayIndexExpression()]
11359- [
11360- (":" { startExpr=idxExpr; idxExpr=null; })
11361- [stopExpr = SimpleExpression()]
11362- ]
11363- "]"
11364- { expr = new ArrayExpression(expr, idxExpr, startExpr, stopExpr); }
11365- )*
11366- { return expr; }
11424+ LOOKAHEAD({ ":".equals(getToken(1).image) }) expression=SliceTail(null)
11425+ |
11426+ expression=Expression() [ expression=SliceTail(expression) ]
11427+ )
11428+ { return expression; }
1136711429}
1136811430
1136911431/**
@@ -11618,7 +11680,7 @@ Expression PrimaryExpression() #PrimaryExpression:
1161811680 // Check for JSON operands
1161911681 [
1162011682 LOOKAHEAD(2, { !isPostgreSqlJsonAccess(getToken(1))
11621- && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0)
11683+ && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0 && subscriptDepth == 0 )
1162211684 || !":".equals(getToken(1).image)) }) (
1162311685 LOOKAHEAD(2) (
1162411686 token="->"
@@ -11983,7 +12045,7 @@ JsonExpression JsonExpression(Expression expr, List<Map.Entry<Expression, String
1198312045
1198412046 (
1198512047 LOOKAHEAD(2, { !isPostgreSqlJsonAccess(getToken(1))
11986- && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0)
12048+ && ((ternaryThenBranchDepth == 0 && mapKeyDepth == 0 && subscriptDepth == 0 )
1198712049 || !":".equals(getToken(1).image)) }) (
1198812050 token="->"
1198912051 |
0 commit comments