1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using XPathTokens;
  7 
  8 parser XPathParser
  9 {
 10     uselexer XPathLexer;
 11     main;
 12 
 13     Expr : System.XPath.XPathExpr*
 14         ::= OrExpr:orExpr{ return orExpr; }
 15         ;
 16 
 17     OrExpr(var UniquePtr<System.XPath.XPathExpr> expr) : System.XPath.XPathExpr*
 18         ::= (AndExpr:left{ expr.Reset(left); } (NAME{ Token token = lexer.GetToken(pos); pass = lexer.GetKeywordToken(token.match) == OR; } AndExpr:right{ expr.Reset(new System.XPath.XPathOrExpr(expr.Release(), right)); })*)
 19         {
 20             return expr.Release();
 21         }
 22         ;
 23 
 24     AndExpr(var UniquePtr<System.XPath.XPathExpr> expr) : System.XPath.XPathExpr*
 25         ::= (EqualityExpr:left{ expr.Reset(left); } (NAME{ Token token = lexer.GetToken(pos); pass = lexer.GetKeywordToken(token.match) == AND; } EqualityExpr:right{ expr.Reset(new System.XPath.XPathAndExpr(expr.Release(), right)); })*)
 26         {
 27             return expr.Release();
 28         }
 29         ;
 30 
 31     EqualityExpr(var UniquePtr<System.XPath.XPathExpr> expr, var System.XPath.Operator op) : System.XPath.XPathExpr*
 32         ::=
 33         (   RelationalExpr:left{ expr.Reset(left); }
 34             (   (EQ{ op = System.XPath.Operator.equal; } | NEQ{ op = System.XPath.Operator.notEqual; })
 35                 RelationalExpr:right!
 36                 {
 37                     switch (op)
 38                     {
 39                         case System.XPath.Operator.equal: expr.Reset(new System.XPath.XPathEqualExpr(expr.Release(), right)); break;
 40                         case System.XPath.Operator.notEqual: expr.Reset(new System.XPath.XPathNotEqualExpr(expr.Release(), right)); break;
 41                     }
 42                 }
 43             )*
 44         )
 45         {
 46             return expr.Release();
 47         }
 48         ;
 49 
 50     RelationalExpr(var UniquePtr<System.XPath.XPathExpr> expr, var System.XPath.Operator op) : System.XPath.XPathExpr*
 51         ::=
 52         (   AdditiveExpr:left{ expr.Reset(left); }
 53             (   (LEQ{ op = System.XPath.Operator.lessOrEqual; } | GEQ{ op = System.XPath.Operator.greaterOrEqual; } | LESS{ op = System.XPath.Operator.less; } | GREATER{ op = System.XPath.Operator.greater; })
 54                 AdditiveExpr:right!
 55                 {
 56                     switch (op)
 57                     {
 58                         case System.XPath.Operator.lessOrEqual: expr.Reset(new System.XPath.XPathLessOrEqualExpr(expr.Release(), right)); break;
 59                         case System.XPath.Operator.greaterOrEqual: expr.Reset(new System.XPath.XPathGreaterOrEqualExpr(expr.Release(), right)); break;
 60                         case System.XPath.Operator.less: expr.Reset(new System.XPath.XPathLessExpr(expr.Release(), right)); break;
 61                         case System.XPath.Operator.greater: expr.Reset(new System.XPath.XPathGreaterExpr(expr.Release(), right)); break;
 62                     }
 63                 }
 64             )*
 65         )
 66         {
 67             return expr.Release();
 68         }
 69         ;
 70 
 71     AdditiveExpr(var UniquePtr<System.XPath.XPathExpr> expr, var System.XPath.Operator op) : System.XPath.XPathExpr*
 72         ::=
 73         (   MultiplicativeExpr:left{ expr.Reset(left); }
 74             (   (PLUS{ op = System.XPath.Operator.plus; } | MINUS{ op = System.XPath.Operator.minus; })
 75                 MultiplicativeExpr:right!
 76                 {
 77                     switch (op)
 78                     {
 79                         case System.XPath.Operator.plus: expr.Reset(new System.XPath.XPathAddExpr(expr.Release(), right)); break;
 80                         case System.XPath.Operator.minus: expr.Reset(new System.XPath.XPathSubExpr(expr.Release(), right)); break;
 81                     }
 82                 }
 83             )*
 84         )
 85         {
 86             return expr.Release();
 87         }
 88         ;
 89 
 90     MultiplicativeExpr(var UniquePtr<System.XPath.XPathExpr> expr, var System.XPath.Operator op) : System.XPath.XPathExpr*
 91         ::=
 92         (   UnaryExpr:left{ expr.Reset(left); }
 93             (   (STAR{ op = System.XPath.Operator.mul; }
 94                 |   NAME
 95                 {
 96                     Token token = lexer.GetToken(pos);
 97                     switch (lexer.GetKeywordToken(token.match))
 98                     {
 99                         case DIV: op = System.XPath.Operator.div; break;
100                         case MOD: op = System.XPath.Operator.mod; break;
101                         default: pass = false; break;
102                     }
103                 }
104             )
105                 UnaryExpr:right!
106                 {
107                     switch (op)
108                     {
109                         case System.XPath.Operator.mul: expr.Reset(new System.XPath.XPathMulExpr(expr.Release(), right)); break;
110                         case System.XPath.Operator.div: expr.Reset(new System.XPath.XPathDivExpr(expr.Release(), right)); break;
111                         case System.XPath.Operator.mod: expr.Reset(new System.XPath.XPathModExpr(expr.Release(), right)); break;
112                     }
113                 }
114             )*
115         )
116         {
117             return expr.Release();
118         }
119         ;
120 
121     UnaryExpr : System.XPath.XPathExpr*
122         ::= MINUS UnaryExpr:subject{ return new System.XPath.XPathUnaryMinusExpr(subject); }
123         |   UnionExpr:unionExpr{ return unionExpr; }
124         ;
125 
126     UnionExpr(var UniquePtr<System.XPath.XPathExpr> expr) : System.XPath.XPathExpr*
127         ::= (PathExpr:left{ expr.Reset(left); } (UNION PathExpr:right{ expr.Reset(new System.XPath.XPathUnionExpr(expr.Release(), right)); })*)
128         {
129             return expr.Release();
130         }
131         ;
132 
133     PathExpr(var UniquePtr<System.XPath.XPathExpr> expr, var System.XPath.Operator op) : System.XPath.XPathExpr*
134         ::= (LocationPath:locationPath - FunctionCall:functionCall){ return locationPath; }
135         |   (FilterExpr:filterExpr{ expr.Reset(filterExpr); } ((SLASHSLASH{ op = System.XPath.Operator.slashSlash; } | SLASH{ op = System.XPath.Operator.slash; }) RelativeLocationPath:right
136             {
137                 switch (op)
138                 {
139                     case System.XPath.Operator.slashSlash:
140                     {
141                         return new System.XPath.XPathCombineStepExpr(expr.Release(),
142                             new System.XPath.XPathCombineStepExpr(new System.XPath.XPathLocationStepExpr(System.Dom.Axis.descendantOrSelf, new System.XPath.XPathAnyNodeTest()), right));
143                     }
144                     case System.XPath.Operator.slash:
145                     {
146                         return new System.XPath.XPathCombineStepExpr(expr.Release(), right);
147                     }
148                 }
149             }
150             )?
151         )
152         {
153             return expr.Release();
154         }
155         ;
156 
157     FilterExpr(var UniquePtr<System.XPath.XPathExpr> expr) : System.XPath.XPathExpr*
158         ::= (PrimaryExpr:primaryExpr{ expr.Reset(primaryExpr); } (Predicate:predicate{ expr.Reset(new System.XPath.XPathFilterExpr(expr.Release(), predicate)); })*)
159         {
160             return expr.Release();
161         }
162         ;
163 
164     LocationPath : System.XPath.XPathExpr*
165         ::= AbsoluteLocationPath:absoluteLocationPath{ return absoluteLocationPath; }
166         |   RelativeLocationPath:relativeLocationPath{ return relativeLocationPath; }
167         ;
168 
169     AbsoluteLocationPath(var UniquePtr<System.XPath.XPathExpr> expr) : System.XPath.XPathExpr*
170         ::=
171         (   AbbreviatedAbsoluteLocationPath:abbreviatedAbsoluteLocationPath{ expr.Reset(abbreviatedAbsoluteLocationPath); }
172         |   SLASH{ expr.Reset(new System.XPath.XPathRootNodeExpr()); } (RelativeLocationPath:right{ expr.Reset(new System.XPath.XPathCombineStepExpr(expr.Release(), right)); })?
173         )
174         {
175             return expr.Release();
176         }
177         ;
178 
179     AbbreviatedAbsoluteLocationPath : System.XPath.XPathExpr*
180         ::= SLASHSLASH RelativeLocationPath:right
181         {
182             return new System.XPath.XPathCombineStepExpr(new System.XPath.XPathRootNodeExpr(), new System.XPath.XPathCombineStepExpr(
183                 new System.XPath.XPathLocationStepExpr(System.Dom.Axis.descendantOrSelf, new System.XPath.XPathAnyNodeTest()), right));
184         }
185         ;
186 
187     RelativeLocationPath(var UniquePtr<System.XPath.XPathExpr> expr, var System.XPath.Operator op) : System.XPath.XPathExpr*
188         ::=
189         (
190             Step:left{ expr.Reset(left); } ((SLASHSLASH{ op = System.XPath.Operator.slashSlash; } | SLASH{ op = System.XPath.Operator.slash; }) Step:right
191             {
192                 switch (op)
193                 {
194                     case System.XPath.Operator.slashSlash:
195                     {
196                         expr.Reset(new System.XPath.XPathCombineStepExpr(expr.Release(), new System.XPath.XPathCombineStepExpr(
197                             new System.XPath.XPathLocationStepExpr(System.Dom.Axis.descendantOrSelf, new System.XPath.XPathAnyNodeTest()), right)));
198                         break;
199                     }
200                     case System.XPath.Operator.slash:
201                     {
202                         expr.Reset(new System.XPath.XPathCombineStepExpr(expr.Release(), right));
203                         break;
204                     }
205                 }
206             }
207             )*
208         )
209         {
210             return expr.Release();
211         }
212         ;
213 
214     Step(var UniquePtr<System.XPath.XPathLocationStepExpr> expr) : System.XPath.XPathLocationStepExpr*
215         ::=
216         (   AxisSpecifier:axis NodeTest:nodeTest{ expr.Reset(new System.XPath.XPathLocationStepExpr(axis, nodeTest)); } (Predicate:predicate{ expr->AddPredicate(predicate); })*
217         |   AbbreviatedStep:abbreviatedStep{ expr.Reset(abbreviatedStep); }
218         )
219         {
220             return expr.Release();
221         }
222         ;
223 
224     AxisSpecifier : System.Dom.Axis
225         ::= AxisName:axis COLONCOLON{ return axis;}
226         |   AbbreviatedAxisSpecifier:abbreviatedAxisSpecifier{ return abbreviatedAxisSpecifier; }
227         ;
228 
229     AxisName : System.Dom.Axis
230         ::= NAME
231         {
232             Token token = lexer.GetToken(pos);
233             switch (lexer.GetKeywordToken(token.match))
234             {
235                 case ANCESTOR:
236                 {
237                     return System.Dom.Axis.ancestor;
238                 }
239                 case ANCESTOR_OR_SELF:
240                 {
241                     return System.Dom.Axis.ancestorOrSelf;
242                 }
243                 case ATTRIBUTE:
244                 {
245                     return System.Dom.Axis.attribute;
246                 }
247                 case CHILD :
248                 {
249                     return System.Dom.Axis.child;
250                 }
251                 case DESCENDANT:
252                 {
253                     return System.Dom.Axis.descendant;
254                 }
255                 case DESCENDANT_OR_SELF:
256                 {
257                     return System.Dom.Axis.descendantOrSelf;
258                 }
259                 case FOLLOWING:
260                 {
261                     return System.Dom.Axis.following;
262                 }
263                 case FOLLOWING_SIBLING:
264                 {
265                     return System.Dom.Axis.followingSibling;
266                 }
267                 case NAMESPACE:
268                 {
269                     return System.Dom.Axis.ns;
270                 }
271                 case PARENT:
272                 {
273                     return System.Dom.Axis.parent;
274                 }
275                 case PRECEDING:
276                 {
277                     return System.Dom.Axis.preceding;
278                 }
279                 case PRECEDING_SIBLING:
280                 {
281                     return System.Dom.Axis.precedingSibling;
282                 }
283                 case SELF:
284                 {
285                     return System.Dom.Axis.self;
286                 }
287                 default:
288                 {
289                     pass = false;
290                     break;
291                 }
292             }
293         }
294         ;
295 
296     AbbreviatedAxisSpecifier : System.Dom.Axis
297         ::= AT{ return System.Dom.Axis.attribute; }
298         |   empty{ return System.Dom.Axis.child; }
299         ;
300 
301     NodeTest : System.XPath.XPathNodeTestExpr*
302         ::= NAME{ Token token = lexer.GetToken(pos); pass = lexer.GetKeywordToken(token.match) == PROCESSING_INSTRUCTION; } LPAREN Literal:pi RPAREN{ return new System.XPath.XPathPILiteralTest(pi); }
303         |   NodeType:nodeType LPAREN RPAREN{ return nodeType; }
304         |   NameTest:nameTest{ return nameTest; }
305         ;
306 
307     NodeType : System.XPath.XPathNodeTestExpr*
308         ::= NAME
309         {
310             Token token = lexer.GetToken(pos);
311             switch (lexer.GetKeywordToken(token.match))
312             {
313                 case COMMENT: return new System.XPath.XPathCommentNodeTest();
314                 case TEXT: return new System.XPath.XPathTextNodeTest();
315                 case PROCESSING_INSTRUCTION: return new System.XPath.XPathPINodeTest();
316                 case NODE: return new System.XPath.XPathAnyNodeTest();
317                 default:
318                 {
319                     pass = false;
320                     break;
321                 }
322             }
323         }
324         ;
325 
326     NameTest : System.XPath.XPathNodeTestExpr*
327         ::= STAR{ return new System.XPath.XPathPrincipalNodeTest(); }
328         |   NCName:ncname COLON STAR{ return new System.XPath.XPathPrefixTest(ncname); }
329         |   QName:qname{ return new System.XPath.XPathNameTest(qname); }
330         ;
331 
332     AbbreviatedStep : System.XPath.XPathLocationStepExpr*
333         ::= DOTDOT{ return new System.XPath.XPathLocationStepExpr(System.Dom.Axis.parent, new System.XPath.XPathAnyNodeTest()); }
334         |   DOT{ return new System.XPath.XPathLocationStepExpr(System.Dom.Axis.self, new System.XPath.XPathAnyNodeTest()); }
335         ;
336 
337     Literal : System.XPath.XPathExpr*
338         ::= DQSTRING
339         { 
340             Token token = lexer.GetToken(pos); 
341             ustring str = System.XPath.ParseDQString(lexer.FileName(), token);
342             return new System.XPath.XPathLiteral(str); 
343         }
344         |   SQSTRING
345         { 
346             Token token = lexer.GetToken(pos); 
347             ustring str = System.XPath.ParseSQString(lexer.FileName(), token);
348             return new System.XPath.XPathLiteral(str); 
349         }
350         ;
351 
352     Number : System.XPath.XPathExpr*
353         ::= NUMBER
354         { 
355             Token token = lexer.GetToken(pos); 
356             ustring str = token.match.ToString();
357             return new System.XPath.XPathNumberExpr(str); 
358         }
359         ;
360 
361     Predicate : System.XPath.XPathExpr*
362         ::= (LBRACKET PredicateExpr:expr RBRACKET){ return expr; }
363         ;
364 
365     PredicateExpr : System.XPath.XPathExpr*
366         ::= Expr:expr{ return expr; }
367         ;
368 
369     PrimaryExpr : System.XPath.XPathExpr*
370         ::= FunctionCall:functionCall{ return functionCall; }
371         |   VariableReference:variableReference{ return variableReference; }
372         |   (LPAREN Expr:expr RPAREN){ return expr; }
373         |   Literal:literal{ return literal; }
374         |   Number:number{ return number; }
375         ;
376 
377     VariableReference : System.XPath.XPathExpr*
378         ::= (DOLLAR QName:qname){ return new System.XPath.XPathVariableReference(qname); }
379         ;
380 
381     FunctionCall(var UniquePtr<System.XPath.XPathFunctionCall> functionCall) : System.XPath.XPathExpr*
382         ::= (FunctionName:functionName LPAREN{ functionCall.Reset(new System.XPath.XPathFunctionCall(functionName)); } (Argument:arg{ functionCall->AddArgument(arg); } % COMMA)? RPAREN)
383         {
384             return functionCall.Release();
385         }
386         ;
387 
388     FunctionName : ustring
389         ::= (QName:qname - NodeType:nodeType){ return qname; }
390         ;
391 
392     Argument : System.XPath.XPathExpr*
393         ::= Expr:expr{ return expr; }
394         ;
395 
396     QName : ustring
397         ::= PrefixedName:prefixedName{ return prefixedName; }
398         |   UnprefixedName:unprefixedName{ return unprefixedName; }
399         ;
400 
401     PrefixedName : ustring
402         ::= (Prefix:prefix COLON LocalPart:localPart){ return prefix + u":" + localPart; }
403         ;
404 
405     Prefix : ustring
406         ::= NCName:ncname{ return ncname; }
407         ;
408 
409     UnprefixedName : ustring
410         ::= LocalPart:localPart{ return localPart; }
411         ;
412 
413     LocalPart : ustring
414         ::= NCName:ncname{ return ncname; }
415         ;
416 
417     NCName : ustring
418         ::= NAME{ Token token = lexer.GetToken(pos); return token.match.ToString(); }
419         ;
420 
421 }