1
2
3
4
5
6 package dev.metaschema.core.metapath.cst;
7
8 import org.antlr.v4.runtime.Token;
9 import org.antlr.v4.runtime.tree.ParseTree;
10 import org.antlr.v4.runtime.tree.TerminalNode;
11
12 import java.math.BigDecimal;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.LinkedHashMap;
16 import java.util.List;
17 import java.util.ListIterator;
18 import java.util.Map;
19 import java.util.stream.Collectors;
20 import java.util.stream.Stream;
21
22 import dev.metaschema.core.metapath.IExpression;
23 import dev.metaschema.core.metapath.InvalidMetapathGrammarException;
24 import dev.metaschema.core.metapath.StaticContext;
25 import dev.metaschema.core.metapath.StaticMetapathException;
26 import dev.metaschema.core.metapath.antlr.Metapath10;
27 import dev.metaschema.core.metapath.antlr.Metapath10Lexer;
28 import dev.metaschema.core.metapath.cst.items.ArraySequenceConstructor;
29 import dev.metaschema.core.metapath.cst.items.ArraySquareConstructor;
30 import dev.metaschema.core.metapath.cst.items.DecimalLiteral;
31 import dev.metaschema.core.metapath.cst.items.EmptySequence;
32 import dev.metaschema.core.metapath.cst.items.Except;
33 import dev.metaschema.core.metapath.cst.items.IntegerLiteral;
34 import dev.metaschema.core.metapath.cst.items.Intersect;
35 import dev.metaschema.core.metapath.cst.items.MapConstructor;
36 import dev.metaschema.core.metapath.cst.items.PostfixLookup;
37 import dev.metaschema.core.metapath.cst.items.Quantified;
38 import dev.metaschema.core.metapath.cst.items.Range;
39 import dev.metaschema.core.metapath.cst.items.SequenceExpression;
40 import dev.metaschema.core.metapath.cst.items.SimpleMap;
41 import dev.metaschema.core.metapath.cst.items.StringConcat;
42 import dev.metaschema.core.metapath.cst.items.StringLiteral;
43 import dev.metaschema.core.metapath.cst.items.UnaryLookup;
44 import dev.metaschema.core.metapath.cst.items.Union;
45 import dev.metaschema.core.metapath.cst.logic.And;
46 import dev.metaschema.core.metapath.cst.logic.GeneralComparison;
47 import dev.metaschema.core.metapath.cst.logic.IBooleanLogicExpression;
48 import dev.metaschema.core.metapath.cst.logic.If;
49 import dev.metaschema.core.metapath.cst.logic.Or;
50 import dev.metaschema.core.metapath.cst.logic.PredicateExpression;
51 import dev.metaschema.core.metapath.cst.logic.ValueComparison;
52 import dev.metaschema.core.metapath.cst.math.Addition;
53 import dev.metaschema.core.metapath.cst.math.Division;
54 import dev.metaschema.core.metapath.cst.math.IntegerDivision;
55 import dev.metaschema.core.metapath.cst.math.Modulo;
56 import dev.metaschema.core.metapath.cst.math.Multiplication;
57 import dev.metaschema.core.metapath.cst.math.Negate;
58 import dev.metaschema.core.metapath.cst.math.Subtraction;
59 import dev.metaschema.core.metapath.cst.path.Axis;
60 import dev.metaschema.core.metapath.cst.path.ContextItem;
61 import dev.metaschema.core.metapath.cst.path.FlagStep;
62 import dev.metaschema.core.metapath.cst.path.INodeTestExpression;
63 import dev.metaschema.core.metapath.cst.path.IWildcardMatcher;
64 import dev.metaschema.core.metapath.cst.path.KindNodeTest;
65 import dev.metaschema.core.metapath.cst.path.ModelInstanceStep;
66 import dev.metaschema.core.metapath.cst.path.NameNodeTest;
67 import dev.metaschema.core.metapath.cst.path.RelativeDoubleSlashPath;
68 import dev.metaschema.core.metapath.cst.path.RelativeSlashPath;
69 import dev.metaschema.core.metapath.cst.path.RootDoubleSlashPath;
70 import dev.metaschema.core.metapath.cst.path.RootSlashOnlyPath;
71 import dev.metaschema.core.metapath.cst.path.RootSlashPath;
72 import dev.metaschema.core.metapath.cst.path.Step;
73 import dev.metaschema.core.metapath.cst.path.WildcardNodeTest;
74 import dev.metaschema.core.metapath.cst.type.Cast;
75 import dev.metaschema.core.metapath.cst.type.Castable;
76 import dev.metaschema.core.metapath.cst.type.InstanceOf;
77 import dev.metaschema.core.metapath.cst.type.Treat;
78 import dev.metaschema.core.metapath.cst.type.TypeTestSupport;
79 import dev.metaschema.core.metapath.function.ComparisonFunctions;
80 import dev.metaschema.core.metapath.function.IArgument;
81 import dev.metaschema.core.metapath.item.atomic.IIntegerItem;
82 import dev.metaschema.core.metapath.item.function.IKeySpecifier;
83 import dev.metaschema.core.metapath.item.function.impl.AbstractKeySpecifier;
84 import dev.metaschema.core.metapath.type.IAtomicOrUnionType;
85 import dev.metaschema.core.metapath.type.IItemType;
86 import dev.metaschema.core.metapath.type.ISequenceType;
87 import dev.metaschema.core.metapath.type.Occurrence;
88 import dev.metaschema.core.qname.IEnhancedQName;
89 import dev.metaschema.core.util.CollectionUtil;
90 import dev.metaschema.core.util.ObjectUtils;
91 import edu.umd.cs.findbugs.annotations.NonNull;
92
93
94
95
96
97
98 @SuppressWarnings({
99 "PMD.GodClass", "PMD.CyclomaticComplexity",
100 "PMD.CouplingBetweenObjects"
101 })
102
103
104 public class BuildCSTVisitor
105 extends AbstractCSTVisitorBase {
106 @NonNull
107 private static final ISequenceType DEFAULT_FUNCTION_SEQUENCE_TYPE
108 = ISequenceType.of(IItemType.item(), Occurrence.ZERO_OR_MORE);
109
110 @NonNull
111 private final StaticContext context;
112
113
114
115
116
117
118
119 public BuildCSTVisitor(@NonNull StaticContext context) {
120 this.context = context;
121 }
122
123
124
125
126
127
128
129
130
131
132 @NonNull
133 protected StaticContext getContext() {
134 return context;
135 }
136
137 @Override
138 protected IExpression handleExpr(Metapath10.ExprContext ctx) {
139 return handleNAiryCollection(ctx, children -> {
140 assert children != null;
141 return new SequenceExpression(ObjectUtils.notNull(ctx.getText()), children);
142 });
143 }
144
145
146
147
148
149 @Override
150 protected IExpression handleStringLiteral(Metapath10.LiteralContext ctx) {
151 ParseTree tree = ctx.getChild(0);
152 return new StringLiteral(ObjectUtils.notNull(ctx.getText()), ObjectUtils.notNull(tree.getText()));
153 }
154
155 @Override
156 protected IExpression handleNumericLiteral(Metapath10.NumericliteralContext ctx) {
157 ParseTree tree = ctx.getChild(0);
158 Token token = (Token) tree.getPayload();
159
160 String text = ObjectUtils.notNull(ctx.getText());
161
162 IExpression retval;
163 switch (token.getType()) {
164 case Metapath10Lexer.IntegerLiteral:
165 retval = new IntegerLiteral(text, new BigInteger(token.getText()));
166 break;
167 case Metapath10Lexer.DecimalLiteral:
168 case Metapath10Lexer.DoubleLiteral:
169 retval = new DecimalLiteral(text, new BigDecimal(token.getText()));
170 break;
171 default:
172 throw new UnsupportedOperationException(token.getText());
173 }
174 return retval;
175 }
176
177
178
179
180
181 @Override
182 protected IExpression handleVarref(Metapath10.VarrefContext ctx) {
183 return new VariableReference(
184 ObjectUtils.notNull(ctx.getText()),
185 getContext().parseVariableName(
186 ObjectUtils.notNull(ctx.varname().eqname().getText())));
187 }
188
189
190
191
192
193 @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
194 @Override
195 protected IExpression handleForexpr(Metapath10.ForexprContext ctx) {
196 Metapath10.SimpleforclauseContext simpleForClause = ctx.simpleforclause();
197
198
199 int bindingCount = simpleForClause.getChildCount() / 2;
200
201 @NonNull
202 IExpression retval = ObjectUtils.notNull(ctx.exprsingle().accept(this));
203
204
205 for (int idx = bindingCount - 1; idx >= 0; idx--) {
206 Metapath10.SimpleforbindingContext simpleForBinding = simpleForClause.simpleforbinding(idx);
207
208 Metapath10.VarnameContext varName = simpleForBinding.varname();
209 Metapath10.ExprsingleContext exprSingle = simpleForBinding.exprsingle();
210
211 IExpression boundExpression = exprSingle.accept(this);
212 assert boundExpression != null;
213
214 IEnhancedQName qname = getContext().parseVariableName(
215 ObjectUtils.notNull(varName.eqname().getText()));
216
217 Let.VariableDeclaration variable = new Let.VariableDeclaration(qname, boundExpression);
218
219 retval = new For(ObjectUtils.notNull(ctx.getText()), variable, retval);
220 }
221 return retval;
222 }
223
224
225
226
227
228 @Override
229 protected IExpression handleLet(Metapath10.LetexprContext context) {
230 @NonNull
231 IExpression retval = ObjectUtils.notNull(context.exprsingle().accept(this));
232
233 Metapath10.SimpleletclauseContext letClause = context.simpleletclause();
234 List<Metapath10.SimpleletbindingContext> clauses = letClause.simpleletbinding();
235
236 ListIterator<Metapath10.SimpleletbindingContext> reverseListIterator = clauses.listIterator(clauses.size());
237 while (reverseListIterator.hasPrevious()) {
238 Metapath10.SimpleletbindingContext simpleCtx = reverseListIterator.previous();
239
240 IExpression boundExpression = simpleCtx.exprsingle().accept(this);
241 assert boundExpression != null;
242
243 IEnhancedQName varName = getContext().parseVariableName(
244 ObjectUtils.notNull(simpleCtx.varname().eqname().getText()));
245
246 retval = new Let(ObjectUtils.notNull(simpleCtx.getText()), varName, boundExpression, retval);
247 }
248 return retval;
249 }
250
251
252
253
254
255 @Override
256 protected MapConstructor handleMapConstructor(Metapath10.MapconstructorContext context) {
257 String text = ObjectUtils.notNull(context.getText());
258 return context.getChildCount() == 3
259
260 ? new MapConstructor(text, CollectionUtil.emptyList())
261
262 : nairyToCollection(context, 3, 2,
263 (ctx, idx) -> {
264 int pos = (idx - 3) / 2;
265 Metapath10.MapconstructorentryContext entry = ctx.mapconstructorentry(pos);
266 assert entry != null;
267 return new MapConstructor.Entry(
268 ObjectUtils.notNull(entry.getText()),
269 ObjectUtils.notNull(entry.mapkeyexpr().accept(this)),
270 ObjectUtils.notNull(entry.mapvalueexpr().accept(this)));
271 },
272 children -> {
273 assert children != null;
274 return new MapConstructor(text, children);
275 });
276 }
277
278
279
280
281
282 @Override
283 protected IExpression handleArrayConstructor(Metapath10.SquarearrayconstructorContext context) {
284 String text = ObjectUtils.notNull(context.getText());
285 return context.getChildCount() == 2
286
287 ? new ArraySquareConstructor(text, CollectionUtil.emptyList())
288
289 : nairyToCollection(context, 1, 2,
290 (ctx, idx) -> {
291 int pos = (idx - 1) / 2;
292 ParseTree tree = ctx.exprsingle(pos);
293 return visit(tree);
294 },
295 children -> {
296 assert children != null;
297 return new ArraySquareConstructor(text, children);
298 });
299 }
300
301 @Override
302 protected IExpression handleArrayConstructor(Metapath10.CurlyarrayconstructorContext ctx) {
303 return new ArraySequenceConstructor(ObjectUtils.notNull(ctx.getText()), visit(ctx.enclosedexpr()));
304 }
305
306
307
308
309
310
311 @NonNull
312 private IKeySpecifier toKeySpecifier(@NonNull Metapath10.KeyspecifierContext specifier) {
313 IKeySpecifier keySpecifier;
314 if (specifier.parenthesizedexpr() != null) {
315 keySpecifier = AbstractKeySpecifier.newParenthesizedExprKeySpecifier(
316 ObjectUtils.requireNonNull(specifier.parenthesizedexpr().accept(this)));
317 } else if (specifier.NCName() != null) {
318 keySpecifier = AbstractKeySpecifier.newNameKeySpecifier(
319 ObjectUtils.requireNonNull(specifier.NCName().getText()));
320 } else if (specifier.IntegerLiteral() != null) {
321 keySpecifier = AbstractKeySpecifier.newIntegerLiteralKeySpecifier(
322 IIntegerItem.valueOf(ObjectUtils.requireNonNull(specifier.IntegerLiteral().getText())));
323 } else if (specifier.STAR() != null) {
324 keySpecifier = AbstractKeySpecifier.newWildcardKeySpecifier();
325 } else {
326 throw new UnsupportedOperationException("unknown key specifier");
327 }
328 return keySpecifier;
329 }
330
331 @Override
332 protected IExpression handleUnarylookup(Metapath10.UnarylookupContext ctx) {
333 return new UnaryLookup(
334 ObjectUtils.notNull(ctx.getText()),
335 toKeySpecifier(ObjectUtils.requireNonNull(ctx.keyspecifier())));
336 }
337
338
339
340
341
342
343 @Override
344 protected IExpression handleEmptyParenthesizedexpr(Metapath10.ParenthesizedexprContext ctx) {
345 return EmptySequence.instance();
346 }
347
348
349
350
351
352
353 @Override
354 protected IExpression handleContextitemexpr(Metapath10.ContextitemexprContext ctx) {
355 return ContextItem.instance();
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370 @NonNull
371 protected Stream<IExpression> parseArgumentList(@NonNull Metapath10.ArgumentlistContext context) {
372 int numChildren = context.getChildCount();
373
374 Stream<IExpression> retval;
375 if (numChildren == 2) {
376
377 retval = Stream.empty();
378 } else {
379 retval = context.argument().stream()
380 .map(argument -> argument.exprsingle().accept(this));
381 }
382 assert retval != null;
383
384 return retval;
385 }
386
387 @Override
388 protected IExpression handleFunctioncall(Metapath10.FunctioncallContext ctx) {
389 List<IExpression> arguments = ObjectUtils.notNull(
390 parseArgumentList(ObjectUtils.notNull(ctx.argumentlist()))
391 .collect(Collectors.toUnmodifiableList()));
392
393 return new StaticFunctionCall(
394 ObjectUtils.notNull(ctx.getText()),
395 () -> getContext().lookupFunction(
396 ObjectUtils.notNull(ctx.eqname().getText()),
397 arguments.size()),
398 arguments);
399 }
400
401
402
403
404
405 @Override
406 public IExpression visitNamedfunctionref(Metapath10.NamedfunctionrefContext ctx) {
407
408 IEnhancedQName qname = getContext().parseFunctionName(ObjectUtils.notNull(ctx.eqname().getText()));
409 int arity = IIntegerItem.valueOf(ObjectUtils.requireNonNull(ctx.IntegerLiteral().getText()))
410 .toIntValueExact();
411 return new NamedFunctionReference(ObjectUtils.notNull(ctx.getText()), qname, arity);
412 }
413
414
415
416
417
418 @Override
419 public IExpression handleInlinefunctionexpr(Metapath10.InlinefunctionexprContext context) {
420
421 List<IArgument> parameters = ObjectUtils.notNull(context.paramlist() == null
422 ? CollectionUtil.emptyList()
423 : nairyToList(
424 ObjectUtils.notNull(context.paramlist()),
425 0,
426 2,
427 (ctx, idx) -> {
428 int pos = idx / 2;
429 Metapath10.ParamContext tree = ctx.param(pos);
430 return IArgument.of(
431 getContext().parseVariableName(ObjectUtils.notNull(tree.eqname().getText())),
432 tree.typedeclaration() == null
433 ? DEFAULT_FUNCTION_SEQUENCE_TYPE
434 : TypeTestSupport.parseSequenceType(
435 ObjectUtils.notNull(tree.typedeclaration().sequencetype()),
436 getContext()));
437 }));
438
439
440 ISequenceType resultSequenceType = context.sequencetype() == null
441 ? DEFAULT_FUNCTION_SEQUENCE_TYPE
442 : TypeTestSupport.parseSequenceType(
443 ObjectUtils.notNull(context.sequencetype()),
444 getContext());
445
446
447 IExpression body = visit(context.functionbody().enclosedexpr());
448
449 return new AnonymousFunctionCall(ObjectUtils.notNull(context.getText()), parameters, resultSequenceType, body);
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463 @NonNull
464 protected IExpression parsePredicate(@NonNull Metapath10.PredicateContext predicate) {
465
466 return visit(predicate.getChild(1));
467 }
468
469
470
471
472
473
474
475
476
477
478
479 @NonNull
480 protected List<IExpression> parsePredicates(@NonNull ParseTree context, int staringChild) {
481 int numChildren = context.getChildCount();
482 int numPredicates = numChildren - staringChild;
483
484 List<IExpression> predicates;
485 if (numPredicates == 0) {
486
487 predicates = CollectionUtil.emptyList();
488 } else if (numPredicates == 1) {
489
490 Metapath10.PredicateContext predicate
491 = ObjectUtils.notNull((Metapath10.PredicateContext) context.getChild(staringChild));
492 predicates = CollectionUtil.singletonList(parsePredicate(predicate));
493 } else {
494
495 predicates = new ArrayList<>(numPredicates);
496 for (int i = staringChild; i < numChildren; i++) {
497 Metapath10.PredicateContext predicate = ObjectUtils.notNull((Metapath10.PredicateContext) context.getChild(i));
498 predicates.add(parsePredicate(predicate));
499 }
500 }
501 return predicates;
502 }
503
504 @Override
505 protected IExpression handlePostfixexpr(Metapath10.PostfixexprContext context) {
506 String text = ObjectUtils.notNull(context.getText());
507 return handleGroupedNAiry(
508 context,
509 0,
510 1,
511 (ctx, idx, left) -> {
512 assert left != null;
513
514 ParseTree tree = ctx.getChild(idx);
515 IExpression result;
516 if (tree instanceof Metapath10.ArgumentlistContext) {
517
518 result = new FunctionCallAccessor(
519 text,
520 left,
521 ObjectUtils.notNull(parseArgumentList((Metapath10.ArgumentlistContext) tree)
522 .collect(Collectors.toUnmodifiableList())));
523 } else if (tree instanceof Metapath10.PredicateContext) {
524 result = new PredicateExpression(
525 text,
526 left,
527 CollectionUtil.singletonList(parsePredicate((Metapath10.PredicateContext) tree)));
528 } else if (tree instanceof Metapath10.LookupContext) {
529 result = new PostfixLookup(
530 text,
531 left,
532 toKeySpecifier(ObjectUtils.notNull(((Metapath10.LookupContext) tree).keyspecifier())));
533 } else {
534 result = visit(tree);
535 }
536 return result;
537 });
538 }
539
540
541
542
543
544 @Override
545 protected IExpression handlePredicate(Metapath10.PredicateContext ctx) {
546 return parsePredicate(ctx);
547 }
548
549 @Override
550 protected IExpression handleLookup(Metapath10.LookupContext ctx) {
551 throw new UnsupportedOperationException("needs to be implemented");
552 }
553
554 @Override
555 protected IExpression handlePathexpr(Metapath10.PathexprContext ctx) {
556 int numChildren = ctx.getChildCount();
557
558 IExpression retval;
559 ParseTree tree = ctx.getChild(0);
560 if (tree instanceof TerminalNode) {
561 String text = ObjectUtils.notNull(ctx.getText());
562 int type = ((TerminalNode) tree).getSymbol().getType();
563 switch (type) {
564 case Metapath10Lexer.SLASH:
565
566 if (numChildren == 2) {
567
568 retval = new RootSlashPath(text, visit(ctx.getChild(1)));
569 } else {
570 retval = new RootSlashOnlyPath(text);
571 }
572 break;
573 case Metapath10Lexer.SS:
574
575 retval = new RootDoubleSlashPath(text, visit(ctx.getChild(1)));
576 break;
577 default:
578 throw new UnsupportedOperationException(((TerminalNode) tree).getSymbol().getText());
579 }
580 } else {
581
582 retval = visit(tree);
583 }
584 return retval;
585 }
586
587
588
589
590
591
592 @Override
593 protected IExpression handleRelativepathexpr(Metapath10.RelativepathexprContext context) {
594 String text = ObjectUtils.notNull(context.getText());
595 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
596 assert left != null;
597
598 ParseTree operatorTree = ctx.getChild(idx);
599 IExpression right = visit(ctx.getChild(idx + 1));
600
601 int type = ((TerminalNode) operatorTree).getSymbol().getType();
602
603 IExpression retval;
604 switch (type) {
605 case Metapath10Lexer.SLASH:
606 retval = new RelativeSlashPath(text, left, right);
607 break;
608 case Metapath10Lexer.SS:
609 retval = new RelativeDoubleSlashPath(text, left, right);
610 break;
611 default:
612 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
613 }
614 return retval;
615 });
616 }
617
618
619
620
621
622 @Override
623 protected IExpression handleForwardstep(Metapath10.ForwardstepContext ctx) {
624 Metapath10.AbbrevforwardstepContext abbrev = ctx.abbrevforwardstep();
625 String text = ObjectUtils.notNull(ctx.getText());
626 Step retval;
627 if (abbrev == null) {
628 assert ctx.getChildCount() == 2;
629
630 Token token = (Token) ctx.forwardaxis().getChild(0).getPayload();
631
632 Axis axis;
633 switch (token.getType()) {
634 case Metapath10Lexer.KW_SELF:
635 axis = Axis.SELF;
636 break;
637 case Metapath10Lexer.KW_CHILD:
638 axis = Axis.CHILDREN;
639 break;
640 case Metapath10Lexer.KW_DESCENDANT:
641 axis = Axis.DESCENDANT;
642 break;
643 case Metapath10Lexer.KW_DESCENDANT_OR_SELF:
644 axis = Axis.DESCENDANT_OR_SELF;
645 break;
646 case Metapath10Lexer.KW_FLAG:
647 axis = Axis.FLAG;
648 break;
649 case Metapath10Lexer.KW_FOLLOWING_SIBLING:
650 axis = Axis.FOLLOWING_SIBLING;
651 break;
652 case Metapath10Lexer.KW_FOLLOWING:
653 axis = Axis.FOLLOWING;
654 break;
655 default:
656 throw new UnsupportedOperationException(token.getText());
657 }
658 retval = new Step(text, axis, parseNodeTest(ctx.nodetest(), false));
659 } else {
660 retval = new Step(text, Axis.CHILDREN, parseNodeTest(ctx.nodetest(), abbrev.AT() != null));
661 }
662 return retval;
663 }
664
665 @Override
666 protected IExpression handleReversestep(Metapath10.ReversestepContext ctx) {
667 assert ctx.getChildCount() == 2;
668 Token token = (Token) ctx.reverseaxis().getChild(0).getPayload();
669
670 Axis axis;
671 switch (token.getType()) {
672 case Metapath10Lexer.KW_PARENT:
673 axis = Axis.PARENT;
674 break;
675 case Metapath10Lexer.KW_ANCESTOR:
676 axis = Axis.ANCESTOR;
677 break;
678 case Metapath10Lexer.KW_ANCESTOR_OR_SELF:
679 axis = Axis.ANCESTOR_OR_SELF;
680 break;
681 case Metapath10Lexer.KW_PRECEDING_SIBLING:
682 axis = Axis.PRECEDING_SIBLING;
683 break;
684 case Metapath10Lexer.KW_PRECEDING:
685 axis = Axis.PRECEDING;
686 break;
687 default:
688 throw new UnsupportedOperationException(token.getText());
689 }
690 return new Step(ObjectUtils.notNull(ctx.getText()), axis, parseNodeTest(ctx.nodetest(), false));
691 }
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706 @NonNull
707 protected INodeTestExpression parseNodeTest(Metapath10.NodetestContext ctx, boolean flag) {
708 INodeTestExpression retval;
709 if (ctx.kindtest() != null) {
710 IItemType itemType = TypeTestSupport.parseKindTest(
711 ObjectUtils.notNull(ctx.kindtest()),
712 getContext());
713 retval = new KindNodeTest(ObjectUtils.notNull(ctx.getText()), itemType);
714 } else {
715 Metapath10.NametestContext nameTestCtx = ctx.nametest();
716 retval = parseNameTest(nameTestCtx, flag);
717 }
718 return retval;
719 }
720
721
722
723
724
725
726
727
728
729
730 @NonNull
731 protected INodeTestExpression parseNameTest(Metapath10.NametestContext ctx, boolean flag) {
732 ParseTree testType = ObjectUtils.requireNonNull(ctx.getChild(0));
733
734 StaticContext staticContext = getContext();
735
736 INodeTestExpression retval;
737 if (testType instanceof Metapath10.EqnameContext) {
738 String name = ObjectUtils.notNull(ctx.eqname().getText());
739 IEnhancedQName qname = flag
740 ? staticContext.parseFlagName(name)
741 : staticContext.parseModelName(name);
742
743 String text = ObjectUtils.notNull(ctx.getText());
744 if (!flag
745 && qname.getNamespace().isEmpty()
746 && staticContext.isUseWildcardWhenNamespaceNotDefaulted()) {
747
748 retval = new WildcardNodeTest(text, IWildcardMatcher.anyNamespace(ObjectUtils.notNull(qname.getLocalName())));
749 } else {
750 retval = new NameNodeTest(text, qname);
751 }
752 } else {
753 retval = handleWildcard((Metapath10.WildcardContext) testType);
754 }
755 return retval;
756 }
757
758 @Override
759 protected WildcardNodeTest handleWildcard(Metapath10.WildcardContext ctx) {
760 IWildcardMatcher matcher = null;
761 if (ctx.STAR() == null) {
762 if (ctx.CS() != null) {
763
764 String prefix = ObjectUtils.notNull(ctx.NCName().getText());
765 String namespace = getContext().lookupNamespaceForPrefix(prefix);
766 if (namespace == null) {
767 throw new IllegalStateException(String.format("Prefix '%s' did not map to a namespace.", prefix));
768 }
769 matcher = IWildcardMatcher.anyLocalName(namespace);
770 } else if (ctx.SC() != null) {
771
772 matcher = IWildcardMatcher.anyNamespace(ObjectUtils.notNull(ctx.NCName().getText()));
773 } else {
774
775 String bracedUriLiteral = ctx.BracedURILiteral().getText();
776 String namespace = ObjectUtils.notNull(bracedUriLiteral.substring(2, bracedUriLiteral.length() - 1));
777 matcher = IWildcardMatcher.anyLocalName(namespace);
778 }
779 }
780
781 return new WildcardNodeTest(ObjectUtils.notNull(ctx.getText()), matcher);
782 }
783
784
785
786
787
788 @Override
789 protected IExpression handleAxisstep(Metapath10.AxisstepContext ctx) {
790 IExpression step = visit(ctx.getChild(0));
791 ParseTree predicateTree = ctx.getChild(1);
792 assert predicateTree != null;
793
794 List<IExpression> predicates = parsePredicates(predicateTree, 0);
795
796 return predicates.isEmpty() ? step : new PredicateExpression(ObjectUtils.notNull(ctx.getText()), step, predicates);
797 }
798
799
800
801
802
803 @Override
804 protected IExpression handleAbbrevforwardstep(Metapath10.AbbrevforwardstepContext ctx) {
805 int numChildren = ctx.getChildCount();
806
807 String text = ObjectUtils.notNull(ctx.getText());
808 IExpression retval;
809 if (numChildren == 1) {
810 retval = new ModelInstanceStep(text, parseNodeTest(ctx.nodetest(), false));
811 } else {
812
813 retval = new FlagStep(text, parseNodeTest(ctx.nodetest(), true));
814 }
815 return retval;
816 }
817
818 @Override
819 protected IExpression handleAbbrevreversestep(Metapath10.AbbrevreversestepContext ctx) {
820 return new Step(ObjectUtils.notNull(ctx.getText()), Axis.PARENT);
821 }
822
823
824
825
826
827 @Override
828 protected IExpression handleRangeexpr(Metapath10.RangeexprContext ctx) {
829 assert ctx.getChildCount() == 3;
830
831 IExpression left = visit(ctx.getChild(0));
832 IExpression right = visit(ctx.getChild(2));
833
834 return new Range(ObjectUtils.notNull(ctx.getText()), left, right);
835 }
836
837
838
839
840
841 @Override
842 protected IExpression handleUnionexpr(Metapath10.UnionexprContext ctx) {
843 return handleNAiryCollection(ctx, children -> {
844 assert children != null;
845 return new Union(ObjectUtils.notNull(ctx.getText()), children);
846 });
847 }
848
849 @Override
850 protected IExpression handleIntersectexceptexpr(Metapath10.IntersectexceptexprContext context) {
851 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
852 assert left != null;
853
854 ParseTree operatorTree = ctx.getChild(idx);
855 IExpression right = visit(ctx.getChild(idx + 1));
856
857 int type = ((TerminalNode) operatorTree).getSymbol().getType();
858 String text = ObjectUtils.notNull(ctx.getText());
859 IExpression retval;
860 switch (type) {
861 case Metapath10Lexer.KW_INTERSECT:
862 retval = new Intersect(text, left, right);
863 break;
864 case Metapath10Lexer.KW_EXCEPT:
865 retval = new Except(text, left, right);
866 break;
867 default:
868 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
869 }
870 return retval;
871 });
872 }
873
874
875
876
877
878 @Override
879 protected IExpression handleAdditiveexpr(Metapath10.AdditiveexprContext context) {
880 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
881 ParseTree operatorTree = ctx.getChild(idx);
882 ParseTree rightTree = ctx.getChild(idx + 1);
883 IExpression right = rightTree.accept(this);
884
885 assert left != null;
886 assert right != null;
887
888 int type = ((TerminalNode) operatorTree).getSymbol().getType();
889 String text = ObjectUtils.notNull(ctx.getText());
890
891 IExpression retval;
892 switch (type) {
893 case Metapath10Lexer.PLUS:
894 retval = new Addition(text, left, right);
895 break;
896 case Metapath10Lexer.MINUS:
897 retval = new Subtraction(text, left, right);
898 break;
899 default:
900 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
901 }
902 return retval;
903 });
904 }
905
906 @Override
907 protected IExpression handleMultiplicativeexpr(Metapath10.MultiplicativeexprContext context) {
908 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
909 assert left != null;
910
911 ParseTree operatorTree = ctx.getChild(idx);
912 IExpression right = visit(ctx.getChild(idx + 1));
913
914 assert right != null;
915
916 int type = ((TerminalNode) operatorTree).getSymbol().getType();
917 String text = ObjectUtils.notNull(ctx.getText());
918 IExpression retval;
919 switch (type) {
920 case Metapath10Lexer.STAR:
921 retval = new Multiplication(text, left, right);
922 break;
923 case Metapath10Lexer.KW_DIV:
924 retval = new Division(text, left, right);
925 break;
926 case Metapath10Lexer.KW_IDIV:
927 retval = new IntegerDivision(text, left, right);
928 break;
929 case Metapath10Lexer.KW_MOD:
930 retval = new Modulo(text, left, right);
931 break;
932 default:
933 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
934 }
935 return retval;
936 });
937 }
938
939 @Override
940 protected IExpression handleUnaryexpr(Metapath10.UnaryexprContext ctx) {
941 int numChildren = ctx.getChildCount();
942 int negateCount = 0;
943
944 int idx = 0;
945 for (; idx < numChildren - 1; idx++) {
946 ParseTree tree = ctx.getChild(idx);
947 int type = ((TerminalNode) tree).getSymbol().getType();
948 switch (type) {
949 case Metapath10Lexer.PLUS:
950 break;
951 case Metapath10Lexer.MINUS:
952 negateCount++;
953 break;
954 default:
955 throw new UnsupportedOperationException(((TerminalNode) tree).getSymbol().getText());
956 }
957 }
958
959 IExpression retval = visit(ctx.getChild(idx));
960 if (negateCount % 2 != 0) {
961 retval = new Negate(ObjectUtils.notNull(ctx.getText()), retval);
962 }
963 return retval;
964 }
965
966
967
968
969
970
971 @Override
972 protected IExpression handleStringconcatexpr(Metapath10.StringconcatexprContext ctx) {
973 return handleNAiryCollection(ctx, children -> {
974 assert children != null;
975 return new StringConcat(ObjectUtils.notNull(ctx.getText()), children);
976 });
977 }
978
979
980
981
982
983 @Override
984 protected IExpression handleComparisonexpr(Metapath10.ComparisonexprContext ctx) {
985 assert ctx.getChildCount() == 3;
986
987 IExpression left = visit(ctx.getChild(0));
988 IExpression right = visit(ctx.getChild(2));
989
990
991 ParseTree operatorTree = ctx.getChild(1);
992 Object payload = operatorTree.getPayload();
993 String text = ObjectUtils.notNull(ctx.getText());
994 ComparisonFunctions.Operator operator;
995 IBooleanLogicExpression retval;
996 if (payload instanceof Metapath10.GeneralcompContext) {
997 Metapath10.GeneralcompContext compContext = (Metapath10.GeneralcompContext) payload;
998 int type = ((TerminalNode) compContext.getChild(0)).getSymbol().getType();
999 switch (type) {
1000 case Metapath10Lexer.EQ:
1001 operator = ComparisonFunctions.Operator.EQ;
1002 break;
1003 case Metapath10Lexer.NE:
1004 operator = ComparisonFunctions.Operator.NE;
1005 break;
1006 case Metapath10Lexer.LT:
1007 operator = ComparisonFunctions.Operator.LT;
1008 break;
1009 case Metapath10Lexer.LE:
1010 operator = ComparisonFunctions.Operator.LE;
1011 break;
1012 case Metapath10Lexer.GT:
1013 operator = ComparisonFunctions.Operator.GT;
1014 break;
1015 case Metapath10Lexer.GE:
1016 operator = ComparisonFunctions.Operator.GE;
1017 break;
1018 default:
1019 throw new UnsupportedOperationException(((TerminalNode) compContext.getChild(0)).getSymbol().getText());
1020 }
1021 retval = new GeneralComparison(text, left, operator, right);
1022 } else if (payload instanceof Metapath10.ValuecompContext) {
1023 Metapath10.ValuecompContext compContext = (Metapath10.ValuecompContext) payload;
1024 int type = ((TerminalNode) compContext.getChild(0)).getSymbol().getType();
1025 switch (type) {
1026 case Metapath10Lexer.KW_EQ:
1027 operator = ComparisonFunctions.Operator.EQ;
1028 break;
1029 case Metapath10Lexer.KW_NE:
1030 operator = ComparisonFunctions.Operator.NE;
1031 break;
1032 case Metapath10Lexer.KW_LT:
1033 operator = ComparisonFunctions.Operator.LT;
1034 break;
1035 case Metapath10Lexer.KW_LE:
1036 operator = ComparisonFunctions.Operator.LE;
1037 break;
1038 case Metapath10Lexer.KW_GT:
1039 operator = ComparisonFunctions.Operator.GT;
1040 break;
1041 case Metapath10Lexer.KW_GE:
1042 operator = ComparisonFunctions.Operator.GE;
1043 break;
1044 default:
1045 throw new UnsupportedOperationException(((TerminalNode) compContext.getChild(0)).getSymbol().getText());
1046 }
1047 retval = new ValueComparison(text, left, operator, right);
1048 } else {
1049 throw new UnsupportedOperationException();
1050 }
1051 return retval;
1052 }
1053
1054
1055
1056
1057
1058 @Override
1059 protected IExpression handleOrexpr(Metapath10.OrexprContext ctx) {
1060 return handleNAiryCollection(ctx, children -> {
1061 assert children != null;
1062 return new Or(ObjectUtils.notNull(ctx.getText()), children);
1063 });
1064 }
1065
1066 @Override
1067 protected IExpression handleAndexpr(Metapath10.AndexprContext ctx) {
1068 return handleNAiryCollection(ctx, children -> {
1069 assert children != null;
1070 return new And(ObjectUtils.notNull(ctx.getText()), children);
1071 });
1072 }
1073
1074
1075
1076
1077
1078 @Override
1079 protected IExpression handleIfexpr(Metapath10.IfexprContext ctx) {
1080 IExpression testExpr = visit(ctx.expr());
1081 IExpression thenExpr = visit(ctx.exprsingle(0));
1082 IExpression elseExpr = visit(ctx.exprsingle(1));
1083
1084 return new If(ObjectUtils.notNull(ctx.getText()), testExpr, thenExpr, elseExpr);
1085 }
1086
1087
1088
1089
1090
1091
1092 @Override
1093 protected IExpression handleQuantifiedexpr(Metapath10.QuantifiedexprContext ctx) {
1094 Quantified.Quantifier quantifier;
1095 int type = ((TerminalNode) ctx.getChild(0)).getSymbol().getType();
1096 switch (type) {
1097 case Metapath10Lexer.KW_SOME:
1098 quantifier = Quantified.Quantifier.SOME;
1099 break;
1100 case Metapath10Lexer.KW_EVERY:
1101 quantifier = Quantified.Quantifier.EVERY;
1102 break;
1103 default:
1104 throw new UnsupportedOperationException(((TerminalNode) ctx.getChild(0)).getSymbol().getText());
1105 }
1106
1107 int numVars = (ctx.getChildCount() - 2) / 5;
1108 Map<IEnhancedQName, IExpression> vars = new LinkedHashMap<>();
1109 int offset = 0;
1110 for (; offset < numVars; offset++) {
1111
1112 IEnhancedQName varName = getContext().parseVariableName(ObjectUtils.notNull(
1113 ctx.varname(offset).eqname().getText()));
1114
1115
1116 IExpression varExpr = visit(ctx.exprsingle(offset));
1117
1118 vars.put(varName, varExpr);
1119 }
1120
1121 IExpression satisfies = visit(ctx.exprsingle(offset));
1122
1123 return new Quantified(ObjectUtils.notNull(ctx.getText()), quantifier, vars, satisfies);
1124 }
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139 @Override
1140 protected IExpression handleInstanceofexpr(@NonNull Metapath10.InstanceofexprContext ctx) {
1141 IExpression left = visit(ctx.treatexpr());
1142 ISequenceType sequenceType = TypeTestSupport.parseSequenceType(
1143 ObjectUtils.notNull(ctx.sequencetype()),
1144 getContext());
1145 return new InstanceOf(ObjectUtils.notNull(ctx.getText()), left, sequenceType);
1146 }
1147
1148
1149
1150
1151
1152 @Override
1153 protected IExpression handleCastexpr(Metapath10.CastexprContext ctx) {
1154 IExpression left = visit(ctx.arrowexpr());
1155
1156 Metapath10.SingletypeContext singleType = ObjectUtils.notNull(ctx.singletype());
1157
1158 boolean allowEmptySequence = singleType.QM() != null;
1159
1160 IAtomicOrUnionType<?> type = getTypeForCast(ObjectUtils.notNull(singleType.simpletypename().getText()));
1161
1162 return new Cast(ObjectUtils.notNull(ctx.getText()), left, type, allowEmptySequence);
1163 }
1164
1165
1166
1167
1168
1169 @NonNull
1170 private IAtomicOrUnionType<?> getTypeForCast(@NonNull String name) {
1171 IAtomicOrUnionType<?> type;
1172 try {
1173 type = getContext().lookupAtomicType(name);
1174 } catch (StaticMetapathException ex) {
1175 if (StaticMetapathException.UNKNOWN_TYPE == ex.getErrorCode().getCode()) {
1176 throw new StaticMetapathException(
1177 StaticMetapathException.CAST_UNKNOWN_TYPE,
1178 String.format("Unknown type '%s'.", name),
1179 ex);
1180 }
1181 throw ex;
1182 }
1183
1184 if (IItemType.anyAtomic().equals(type)) {
1185 throw new StaticMetapathException(
1186 StaticMetapathException.CAST_ANY_ATOMIC,
1187 String.format("Type cannot be '%s',", IItemType.anyAtomic()));
1188 }
1189 return type;
1190 }
1191
1192 @Override
1193 protected IExpression handleCastableexpr(Metapath10.CastableexprContext ctx) {
1194 IExpression left = visit(ctx.castexpr());
1195
1196 Metapath10.SingletypeContext singleType = ObjectUtils.notNull(ctx.singletype());
1197
1198 boolean allowEmptySequence = singleType.QM() != null;
1199
1200 IAtomicOrUnionType<?> type = getTypeForCast(ObjectUtils.notNull(singleType.simpletypename().getText()));
1201
1202 return new Castable(ObjectUtils.notNull(ctx.getText()), left, type, allowEmptySequence);
1203 }
1204
1205
1206
1207
1208
1209 @Override
1210 protected IExpression handleTreatexpr(Metapath10.TreatexprContext ctx) {
1211 IExpression left = visit(ctx.castableexpr());
1212
1213 ISequenceType sequenceType = TypeTestSupport.parseSequenceType(
1214 ObjectUtils.notNull(ctx.sequencetype()),
1215 getContext());
1216
1217 return new Treat(ObjectUtils.notNull(ctx.getText()), left, sequenceType);
1218 }
1219
1220
1221
1222
1223
1224 @Override
1225 protected IExpression handleSimplemapexpr(Metapath10.SimplemapexprContext context) {
1226 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
1227 assert left != null;
1228
1229
1230 assert "!".equals(ctx.getChild(idx).getText());
1231 IExpression right = ObjectUtils.notNull(ctx.getChild(idx + 1).accept(this));
1232
1233 return new SimpleMap(ObjectUtils.notNull(ctx.getText()), left, right);
1234 });
1235 }
1236
1237
1238
1239
1240
1241 @Override
1242 protected IExpression handleArrowexpr(Metapath10.ArrowexprContext context) {
1243 return handleGroupedNAiry(context, 0, 3, (ctx, idx, left) -> {
1244
1245 assert "=>".equals(ctx.getChild(idx).getText());
1246
1247 int offset = (idx - 1) / 3;
1248
1249 Metapath10.ArgumentlistContext argumentCtx = ctx.getChild(Metapath10.ArgumentlistContext.class, offset);
1250
1251 try (Stream<IExpression> args = Stream.concat(
1252 Stream.of(left),
1253 parseArgumentList(ObjectUtils.notNull(argumentCtx)))) {
1254 assert args != null;
1255
1256
1257 List<IExpression> arguments = ObjectUtils.notNull(args
1258 .collect(Collectors.toUnmodifiableList()));
1259
1260 Metapath10.ArrowfunctionspecifierContext arrowCtx
1261 = ctx.getChild(Metapath10.ArrowfunctionspecifierContext.class, offset);
1262 if (arrowCtx.eqname() != null) {
1263
1264 return new StaticFunctionCall(
1265 ObjectUtils.notNull(arrowCtx.getText()),
1266 () -> getContext().lookupFunction(ObjectUtils.notNull(arrowCtx.eqname().getText()), arguments.size()),
1267 arguments);
1268 }
1269
1270 IExpression result;
1271 if (arrowCtx.varref() != null) {
1272
1273 result = new VariableReference(
1274 ObjectUtils.notNull(arrowCtx.getText()),
1275 getContext().parseVariableName(
1276 ObjectUtils.notNull(arrowCtx.varref().varname().eqname().getText())));
1277 } else if (arrowCtx.parenthesizedexpr() != null) {
1278
1279 result = visit(arrowCtx.parenthesizedexpr().expr());
1280 } else {
1281
1282 throw new InvalidMetapathGrammarException(
1283 String.format("Unable to get function name using arrow specifier '%s'.", arrowCtx.getText()));
1284 }
1285
1286 return new DynamicFunctionCall(
1287 ObjectUtils.notNull(arrowCtx.getText()),
1288 result,
1289 arguments);
1290 }
1291 });
1292 }
1293 }