@@ -86,7 +86,7 @@ options {
86
86
87
87
public XQueryParser(XQueryLexer lexer) {
88
88
this((TokenStream)lexer);
89
- this.lexer= lexer;
89
+ this.lexer = lexer;
90
90
setASTNodeClass("org.exist.xquery.parser.XQueryAST");
91
91
}
92
92
@@ -95,15 +95,18 @@ options {
95
95
}
96
96
97
97
public String getErrorMessage() {
98
- StringBuilder buf= new StringBuilder();
99
- for (Iterator i= exceptions.iterator(); i.hasNext();) {
98
+ StringBuilder buf = new StringBuilder();
99
+ for (Iterator i = exceptions.iterator(); i.hasNext();) {
100
100
buf.append(((Exception) i.next()).toString());
101
101
buf.append(' \n' );
102
102
}
103
103
return buf.toString();
104
104
}
105
105
106
106
public Exception getLastException() {
107
+ if (!foundError) {
108
+ return null;
109
+ }
107
110
return (Exception) exceptions.get(exceptions.size() - 1);
108
111
}
109
112
@@ -112,7 +115,7 @@ options {
112
115
}
113
116
114
117
protected void handleException(Exception e) {
115
- foundError= true;
118
+ foundError = true;
116
119
exceptions.add(e);
117
120
}
118
121
}
@@ -184,6 +187,11 @@ imaginaryTokenDefinitions
184
187
PRAGMA
185
188
GTEQ
186
189
SEQUENCE
190
+ TUMBLING_WINDOW
191
+ CURRENT_ITEM
192
+ PREVIOUS_ITEM
193
+ NEXT_ITEM
194
+ WINDOW_VARS
187
195
;
188
196
189
197
// === XPointer ===
@@ -694,7 +702,7 @@ expr throws XPathException
694
702
695
703
exprSingle throws XPathException
696
704
:
697
- ( ( "for" | "let" ) DOLLAR ) => flworExpr
705
+ ( ( "for" | "let" ) ("tumbling" | "sliding" | DOLLAR ) ) => flworExpr
698
706
| ( "try" LCURLY ) => tryCatchExpr
699
707
| ( ( "some" | "every" ) DOLLAR ) => quantifiedExpr
700
708
| ( "if" LPAREN ) => ifExpr
@@ -801,7 +809,9 @@ flworExpr throws XPathException
801
809
802
810
initialClause throws XPathException
803
811
:
804
- ( forClause | letClause )
812
+ ( ( "for" DOLLAR ) => forClause
813
+ | ( "for" ( "tumbling" | "sliding" ) ) => windowClause
814
+ | letClause )
805
815
;
806
816
807
817
intermediateClause throws XPathException
@@ -831,6 +841,11 @@ letClause throws XPathException
831
841
"let"^ letVarBinding ( COMMA! letVarBinding )*
832
842
;
833
843
844
+ windowClause throws XPathException
845
+ :
846
+ "for"! ("tumbling"|"sliding") "window"^ inVarBinding windowStartCondition ( windowEndCondition )?
847
+ ;
848
+
834
849
inVarBinding throws XPathException
835
850
{ String varName; }
836
851
:
@@ -855,6 +870,37 @@ allowingEmpty
855
870
"allowing"! "empty"
856
871
;
857
872
873
+ windowStartCondition throws XPathException
874
+ :
875
+ "start"^ windowVars "when" exprSingle
876
+ ;
877
+
878
+ windowEndCondition throws XPathException
879
+ :
880
+ ( "only" )? "end"^ windowVars "when" exprSingle
881
+ ;
882
+
883
+ windowVars throws XPathException
884
+ { String currentItemName = null, positionalVarName = null, previousItemName = null, nextItemName = null; }
885
+ :
886
+ ( DOLLAR! currentItemName=eqName! )?
887
+ ( "at"! DOLLAR! positionalVarName=eqName! )?
888
+ ( "previous"! DOLLAR! previousItemName=eqName! )?
889
+ ( "next"! DOLLAR! nextItemName=eqName! )?
890
+ {
891
+ windowVars_AST = (org.exist.xquery.parser.XQueryAST)astFactory.create(WINDOW_VARS);
892
+ if (currentItemName != null)
893
+ windowVars_AST.addChild(astFactory.create(CURRENT_ITEM,currentItemName));
894
+ if (positionalVarName != null)
895
+ windowVars_AST.addChild(astFactory.create(POSITIONAL_VAR,positionalVarName));
896
+ if (previousItemName != null)
897
+ windowVars_AST.addChild(astFactory.create(PREVIOUS_ITEM,previousItemName));
898
+ if (nextItemName != null)
899
+ windowVars_AST.addChild(astFactory.create(NEXT_ITEM,nextItemName));
900
+ currentAST.root = (org.exist.xquery.parser.XQueryAST) windowVars_AST;
901
+ }
902
+ ;
903
+
858
904
letVarBinding throws XPathException
859
905
{ String varName; }
860
906
:
@@ -887,7 +933,6 @@ orderModifier
887
933
groupByClause throws XPathException
888
934
:
889
935
"group"! "by"! groupingSpecList
890
- // "group"! toGroupVarRef "as"! groupVarBinding "by"! groupSpecList
891
936
{ #groupByClause= #([GROUP_BY, "group by"], #groupByClause); }
892
937
;
893
938
@@ -899,7 +944,7 @@ groupingSpecList throws XPathException
899
944
groupingSpec throws XPathException
900
945
{ String groupKeyVarName; }
901
946
:
902
- DOLLAR! groupKeyVarName=varName! ( COLON! EQ! exprSingle )? ( "collation" STRING_LITERAL )?
947
+ DOLLAR! groupKeyVarName=varName! ( ( typeDeclaration )? COLON! EQ! exprSingle )? ( "collation" STRING_LITERAL )?
903
948
{ #groupingSpec = #(#[VARIABLE_BINDING, groupKeyVarName], #groupingSpec); }
904
949
;
905
950
@@ -2241,8 +2286,27 @@ reservedKeywords returns [String name]
2241
2286
" empty-sequence" { name = " empty-sequence" ; }
2242
2287
|
2243
2288
" schema-element" { name = " schema-element" ; }
2289
+ |
2290
+ " tumbling" { name = " tumbling" ; }
2291
+ |
2292
+ " sliding" { name = " sliding" ; }
2293
+ |
2294
+ " window" { name = " window" ; }
2295
+ |
2296
+ " start" { name = " start" ; }
2297
+ |
2298
+ " end" { name = " end" ; }
2299
+ |
2300
+ " only" { name = " only" ; }
2301
+ |
2302
+ " previous" { name = " previous" ; }
2303
+ |
2304
+ " next" { name = " next" ; }
2305
+ |
2306
+ " when" { name = " when" ; }
2244
2307
;
2245
2308
2309
+
2246
2310
/**
2247
2311
* The XQuery/ XPath lexical analyzer.
2248
2312
*/
0 commit comments