1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.metapath;
28
29 import gov.nist.secauto.metaschema.core.metapath.IComparison.Operator;
30 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Lexer;
31 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.AbbrevforwardstepContext;
32 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.AbbrevreversestepContext;
33 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.AdditiveexprContext;
34 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.AndexprContext;
35 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ArgumentlistContext;
36 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ArrowexprContext;
37 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.AxisstepContext;
38 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ComparisonexprContext;
39 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ContextitemexprContext;
40 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.EqnameContext;
41 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ExprContext;
42 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ForwardstepContext;
43 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.FunctioncallContext;
44 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.GeneralcompContext;
45 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.IntersectexceptexprContext;
46 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.LetexprContext;
47 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.LiteralContext;
48 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.MultiplicativeexprContext;
49 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.NumericliteralContext;
50 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.OrexprContext;
51 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.PathexprContext;
52 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.PostfixexprContext;
53 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.PredicateContext;
54 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.RelativepathexprContext;
55 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ReversestepContext;
56 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.SimpleletbindingContext;
57 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.SimpleletclauseContext;
58 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.StringconcatexprContext;
59 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.UnaryexprContext;
60 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.UnionexprContext;
61 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.ValuecompContext;
62 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.VarrefContext;
63 import gov.nist.secauto.metaschema.core.metapath.antlr.metapath10Parser.WildcardContext;
64 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
65 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
66
67 import org.antlr.v4.runtime.ParserRuleContext;
68 import org.antlr.v4.runtime.Token;
69 import org.antlr.v4.runtime.tree.ParseTree;
70 import org.antlr.v4.runtime.tree.TerminalNode;
71
72 import java.math.BigDecimal;
73 import java.math.BigInteger;
74 import java.util.ArrayList;
75 import java.util.List;
76 import java.util.ListIterator;
77 import java.util.Objects;
78 import java.util.function.BiFunction;
79 import java.util.function.Function;
80 import java.util.stream.Collectors;
81 import java.util.stream.Stream;
82
83 import edu.umd.cs.findbugs.annotations.NonNull;
84
85 @SuppressWarnings("PMD.CouplingBetweenObjects")
86 class BuildAstVisitor
87 extends AbstractAstVisitor<IExpression> {
88
89 @SuppressWarnings("null")
90 @Override
91 @NonNull
92 public IExpression visit(ParseTree tree) {
93 return super.visit(tree);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 @NonNull
119 protected <CONTEXT extends ParserRuleContext, NODE extends IExpression> IExpression
120 handleNAiryCollection(
121 @NonNull CONTEXT context,
122 @NonNull Function<List<NODE>, IExpression> supplier) {
123 return handleNAiryCollection(context, 1, 2, (ctx, idx) -> {
124
125 ParseTree tree = ctx.getChild(idx + 1);
126 @SuppressWarnings({ "unchecked", "null" })
127 @NonNull NODE node = (NODE) tree.accept(this);
128 return node;
129 }, supplier);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158 @NonNull
159 protected <CONTEXT extends ParserRuleContext, EXPRESSION extends IExpression> IExpression
160 handleNAiryCollection(
161 @NonNull CONTEXT context,
162 int startIndex,
163 int step,
164 @NonNull BiFunction<CONTEXT, Integer, EXPRESSION> parser,
165 @NonNull Function<List<EXPRESSION>, IExpression> supplier) {
166 int numChildren = context.getChildCount();
167
168 if (numChildren == 0) {
169 throw new IllegalStateException("there should always be a child expression");
170 } else if (startIndex > numChildren) {
171 throw new IllegalStateException("Start index is out of bounds");
172 }
173
174 ParseTree leftTree = context.getChild(0);
175 @SuppressWarnings({ "unchecked", "null" })
176 @NonNull EXPRESSION leftResult = (EXPRESSION) leftTree.accept(this);
177
178 IExpression retval;
179 if (numChildren == 1) {
180 retval = leftResult;
181 } else {
182 List<EXPRESSION> children = new ArrayList<>(numChildren - 1 / step);
183 children.add(leftResult);
184 for (int i = startIndex; i < numChildren; i = i + step) {
185 EXPRESSION result = parser.apply(context, i);
186 children.add(result);
187 }
188 IExpression result = ObjectUtils.notNull(supplier.apply(children));
189 retval = result;
190 }
191 return retval;
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 protected <CONTEXT extends ParserRuleContext> IExpression handleGroupedNAiry(
218 @NonNull CONTEXT context,
219 int startingIndex,
220 int step,
221 @NonNull ITriFunction<CONTEXT, Integer, IExpression, IExpression> parser) {
222 int numChildren = context.getChildCount();
223 if (startingIndex >= numChildren) {
224 throw new IndexOutOfBoundsException(
225 String.format("The starting index '%d' exceeds the child count '%d'",
226 startingIndex,
227 numChildren));
228 }
229
230 IExpression retval = null;
231 if (numChildren > 0) {
232 ParseTree leftTree = context.getChild(startingIndex);
233 IExpression result = ObjectUtils.notNull(leftTree.accept(this));
234
235 for (int i = startingIndex + 1; i < numChildren; i = i + step) {
236 result = parser.apply(context, i, result);
237 }
238 retval = result;
239 }
240 return retval;
241 }
242
243 @Override
244 protected IExpression handleExpr(ExprContext ctx) {
245 return handleNAiryCollection(ctx, children -> {
246 assert children != null;
247 return new Metapath(children);
248 });
249 }
250
251 @Override
252 protected IExpression handleOrexpr(OrexprContext ctx) {
253 return handleNAiryCollection(ctx, children -> {
254 assert children != null;
255 return new Or(children);
256 });
257 }
258
259 @Override
260 protected IExpression handleAndexpr(AndexprContext ctx) {
261 return handleNAiryCollection(ctx, children -> {
262 assert children != null;
263 return new And(children);
264 });
265 }
266
267 @Override
268 protected IExpression handleComparisonexpr(ComparisonexprContext ctx) {
269 assert ctx.getChildCount() == 3;
270
271 IExpression left = visit(ctx.getChild(0));
272 IExpression right = visit(ctx.getChild(2));
273
274
275 ParseTree operatorTree = ctx.getChild(1);
276 Object payload = operatorTree.getPayload();
277 Operator operator;
278
279 IComparison retval;
280 if (payload instanceof GeneralcompContext) {
281 GeneralcompContext compContext = (GeneralcompContext) payload;
282 int type = ((TerminalNode) compContext.getChild(0)).getSymbol().getType();
283 switch (type) {
284 case metapath10Lexer.EQ:
285 operator = Operator.EQ;
286 break;
287 case metapath10Lexer.NE:
288 operator = Operator.NE;
289 break;
290 case metapath10Lexer.LT:
291 operator = Operator.LT;
292 break;
293 case metapath10Lexer.LE:
294 operator = Operator.LE;
295 break;
296 case metapath10Lexer.GT:
297 operator = Operator.GT;
298 break;
299 case metapath10Lexer.GE:
300 operator = Operator.GE;
301 break;
302 default:
303 throw new UnsupportedOperationException(((TerminalNode) compContext.getChild(0)).getSymbol().getText());
304 }
305 retval = new GeneralComparison(left, operator, right);
306 } else if (payload instanceof ValuecompContext) {
307 ValuecompContext compContext = (ValuecompContext) payload;
308 int type = ((TerminalNode) compContext.getChild(0)).getSymbol().getType();
309 switch (type) {
310 case metapath10Lexer.KW_EQ:
311 operator = Operator.EQ;
312 break;
313 case metapath10Lexer.KW_NE:
314 operator = Operator.NE;
315 break;
316 case metapath10Lexer.KW_LT:
317 operator = Operator.LT;
318 break;
319 case metapath10Lexer.KW_LE:
320 operator = Operator.LE;
321 break;
322 case metapath10Lexer.KW_GT:
323 operator = Operator.GT;
324 break;
325 case metapath10Lexer.KW_GE:
326 operator = Operator.GE;
327 break;
328 default:
329 throw new UnsupportedOperationException(((TerminalNode) compContext.getChild(0)).getSymbol().getText());
330 }
331 retval = new ValueComparison(left, operator, right);
332 } else {
333 throw new UnsupportedOperationException();
334 }
335 return retval;
336 }
337
338 @Override
339 protected IExpression handleStringconcatexpr(StringconcatexprContext ctx) {
340 return handleNAiryCollection(ctx, children -> {
341 assert children != null;
342 return new StringConcat(children);
343 });
344 }
345
346 @Override
347 protected IExpression handleAdditiveexpr(AdditiveexprContext context) {
348 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
349 ParseTree operatorTree = ctx.getChild(idx);
350 ParseTree rightTree = ctx.getChild(idx + 1);
351 IExpression right = rightTree.accept(this);
352
353 assert left != null;
354 assert right != null;
355
356 int type = ((TerminalNode) operatorTree).getSymbol().getType();
357
358 IExpression retval;
359 switch (type) {
360 case metapath10Lexer.PLUS:
361 retval = new Addition(left, right);
362 break;
363 case metapath10Lexer.MINUS:
364 retval = new Subtraction(left, right);
365 break;
366 default:
367 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
368 }
369 return retval;
370 });
371 }
372
373 @Override
374 protected IExpression handleMultiplicativeexpr(MultiplicativeexprContext context) {
375 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
376 ParseTree operatorTree = ctx.getChild(idx);
377 ParseTree rightTree = ctx.getChild(idx + 1);
378 IExpression right = rightTree.accept(this);
379
380 assert left != null;
381 assert right != null;
382
383 int type = ((TerminalNode) operatorTree).getSymbol().getType();
384 IExpression retval;
385 switch (type) {
386 case metapath10Lexer.STAR:
387 retval = new Multiplication(left, right);
388 break;
389 case metapath10Lexer.KW_DIV:
390 retval = new Division(left, right);
391 break;
392 case metapath10Lexer.KW_IDIV:
393 retval = new IntegerDivision(left, right);
394 break;
395 case metapath10Lexer.KW_MOD:
396 retval = new Modulo(left, right);
397 break;
398 default:
399 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
400 }
401 return retval;
402 });
403 }
404
405 @Override
406 protected IExpression handleUnionexpr(UnionexprContext ctx) {
407 return handleNAiryCollection(ctx, children -> {
408 assert children != null;
409 return new Union(children);
410 });
411 }
412
413 @Override
414 protected IExpression handleIntersectexceptexpr(IntersectexceptexprContext context) {
415 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
416 ParseTree operatorTree = ctx.getChild(idx);
417 ParseTree rightTree = ctx.getChild(idx + 1);
418 IExpression right = rightTree.accept(this);
419
420 assert left != null;
421 assert right != null;
422
423 int type = ((TerminalNode) operatorTree).getSymbol().getType();
424
425 IExpression retval;
426 switch (type) {
427 case metapath10Lexer.KW_INTERSECT:
428 retval = new Intersect(left, right);
429 break;
430 case metapath10Lexer.KW_EXCEPT:
431 retval = new Except(left, right);
432 break;
433 default:
434 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
435 }
436 return retval;
437 });
438 }
439
440 @SuppressWarnings("resource")
441 @Override
442 protected IExpression handleArrowexpr(ArrowexprContext context) {
443
444
445 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
446
447 assert "=>".equals(ctx.getChild(idx).getText());
448
449 FunctioncallContext fcCtx = ctx.getChild(FunctioncallContext.class, idx + 1);
450 String name = fcCtx.eqname().getText();
451 assert name != null;
452
453 Stream<IExpression> args = parseArgumentList(ObjectUtils.notNull(fcCtx.argumentlist()));
454 args = Stream.concat(Stream.of(left), args);
455 assert args != null;
456
457 return new FunctionCall(name, ObjectUtils.notNull(args.collect(Collectors.toUnmodifiableList())));
458 });
459 }
460
461 @Override
462 protected IExpression handleUnaryexpr(UnaryexprContext ctx) {
463 int numChildren = ctx.getChildCount();
464 int negateCount = 0;
465
466 int idx = 0;
467 for (; idx < numChildren - 1; idx++) {
468 ParseTree tree = ctx.getChild(idx);
469 int type = ((TerminalNode) tree).getSymbol().getType();
470 switch (type) {
471 case metapath10Lexer.PLUS:
472 break;
473 case metapath10Lexer.MINUS:
474 negateCount++;
475 break;
476 default:
477 throw new UnsupportedOperationException(((TerminalNode) tree).getSymbol().getText());
478 }
479 }
480
481 ParseTree expr = ctx.getChild(0);
482 IExpression retval = expr.accept(this);
483 assert retval != null;
484 if (negateCount % 2 != 0) {
485 retval = new Negate(retval);
486 }
487 return retval;
488 }
489
490 @Override
491 protected IExpression handlePathexpr(PathexprContext ctx) {
492 int numChildren = ctx.getChildCount();
493
494 IExpression retval;
495 ParseTree tree = ctx.getChild(0);
496 if (tree instanceof TerminalNode) {
497 int type = ((TerminalNode) tree).getSymbol().getType();
498 switch (type) {
499 case metapath10Lexer.SLASH:
500
501 if (numChildren == 2) {
502
503 ParseTree pathTree = ctx.getChild(1);
504 retval = new RootSlashPath(ObjectUtils.notNull(pathTree.accept(this)));
505 } else {
506 retval = new RootSlashOnlyPath();
507 }
508 break;
509 case metapath10Lexer.SS:
510
511 ParseTree pathTree = ctx.getChild(1);
512 IExpression node = pathTree.accept(this);
513 assert node != null;
514 retval = new RootDoubleSlashPath(node);
515 break;
516 default:
517 throw new UnsupportedOperationException(((TerminalNode) tree).getSymbol().getText());
518 }
519 } else {
520
521 retval = tree.accept(this);
522 }
523 return retval;
524 }
525
526 @Override
527 protected IExpression handleRelativepathexpr(RelativepathexprContext context) {
528 return handleGroupedNAiry(context, 0, 2, (ctx, idx, left) -> {
529 ParseTree operatorTree = ctx.getChild(idx);
530 ParseTree rightTree = ctx.getChild(idx + 1);
531 IExpression rightResult = rightTree.accept(this);
532
533 assert left != null;
534 assert rightResult != null;
535
536 int type = ((TerminalNode) operatorTree).getSymbol().getType();
537
538 IExpression retval;
539 switch (type) {
540 case metapath10Lexer.SLASH:
541 retval = new RelativeSlashPath(left, rightResult);
542 break;
543 case metapath10Lexer.SS:
544 retval = new RelativeDoubleSlashPath(left, rightResult);
545 break;
546 default:
547 throw new UnsupportedOperationException(((TerminalNode) operatorTree).getSymbol().getText());
548 }
549 return retval;
550 });
551 }
552
553 @SuppressWarnings("null")
554 @NonNull
555 protected IExpression parsePredicate(@NonNull PredicateContext context) {
556
557 ParseTree tree = context.getChild(1);
558 return tree.accept(this);
559 }
560
561 @NonNull
562 protected List<IExpression> parsePredicates(@NonNull ParseTree context, int staringChild) {
563 int numChildren = context.getChildCount();
564 int numPredicates = numChildren - staringChild;
565
566 List<IExpression> predicates;
567 if (numPredicates == 0) {
568
569 predicates = CollectionUtil.emptyList();
570 } else if (numPredicates == 1) {
571
572 PredicateContext predicate = ObjectUtils.notNull((PredicateContext) context.getChild(staringChild));
573 predicates = CollectionUtil.singletonList(parsePredicate(predicate));
574 } else {
575
576 predicates = new ArrayList<>(numPredicates);
577 for (int i = staringChild; i < numChildren; i++) {
578 PredicateContext predicate = ObjectUtils.notNull((PredicateContext) context.getChild(i));
579 predicates.add(parsePredicate(predicate));
580 }
581 }
582 return predicates;
583 }
584
585 @Override
586 protected IExpression handlePostfixexpr(PostfixexprContext ctx) {
587 int numChildren = ctx.getChildCount();
588 ParseTree primaryTree = ctx.getChild(0);
589 IExpression retval = ObjectUtils.notNull(primaryTree.accept(this));
590
591 List<IExpression> predicates = numChildren > 1 ? parsePredicates(ctx, 1) : CollectionUtil.emptyList();
592
593 if (!predicates.isEmpty()) {
594 retval = new Predicate(retval, predicates);
595 }
596 return retval;
597
598 }
599
600 @Override
601 protected IExpression handleAxisstep(AxisstepContext ctx) {
602 IExpression step = ctx.getChild(0).accept(this);
603 assert step != null;
604
605 ParseTree predicateTree = ctx.getChild(1);
606 assert predicateTree != null;
607
608 List<IExpression> predicates = parsePredicates(predicateTree, 0);
609
610 return predicates.isEmpty() ? step : new Predicate(step, predicates);
611 }
612
613 @Override
614 protected IExpression handleForwardstep(ForwardstepContext ctx) {
615 assert ctx.getChildCount() == 2;
616
617 Token token = (Token) ctx.forwardaxis().getChild(0).getPayload();
618
619 Axis axis;
620 switch (token.getType()) {
621 case metapath10Lexer.KW_SELF:
622 axis = Axis.SELF;
623 break;
624 case metapath10Lexer.KW_CHILD:
625 axis = Axis.CHILDREN;
626 break;
627 case metapath10Lexer.KW_DESCENDANT:
628 axis = Axis.DESCENDANT;
629 break;
630 case metapath10Lexer.KW_DESCENDANT_OR_SELF:
631 axis = Axis.DESCENDANT_OR_SELF;
632 break;
633 default:
634 throw new UnsupportedOperationException(token.getText());
635 }
636 return new Step(axis, ObjectUtils.notNull(ctx.nametest().accept(this)));
637 }
638
639 @Override
640 protected IExpression handleAbbrevforwardstep(AbbrevforwardstepContext ctx) {
641 int numChildren = ctx.getChildCount();
642
643 IExpression retval;
644 if (numChildren == 1) {
645 ParseTree tree = ctx.getChild(0);
646 retval = new ModelInstance(ObjectUtils.notNull(tree.accept(this)));
647 } else {
648
649 ParseTree tree = ctx.getChild(1);
650 retval = new Flag(ObjectUtils.notNull(tree.accept(this)));
651
652 }
653 return retval;
654 }
655
656 @Override
657 protected IExpression handleReversestep(ReversestepContext ctx) {
658 assert ctx.getChildCount() == 2;
659
660 Token token = (Token) ctx.reverseaxis().getChild(0).getPayload();
661
662 Axis axis;
663 switch (token.getType()) {
664 case metapath10Lexer.KW_PARENT:
665 axis = Axis.PARENT;
666 break;
667 case metapath10Lexer.KW_ANCESTOR:
668 axis = Axis.ANCESTOR;
669 break;
670 case metapath10Lexer.KW_ANCESTOR_OR_SELF:
671 axis = Axis.ANCESTOR_OR_SELF;
672 break;
673 default:
674 throw new UnsupportedOperationException(token.getText());
675 }
676 return new Step(axis, ObjectUtils.notNull(ctx.nametest().accept(this)));
677 }
678
679 @Override
680 protected IExpression handleAbbrevreversestep(AbbrevreversestepContext ctx) {
681 return Axis.PARENT;
682 }
683
684 @Override
685 protected IExpression handleStringLiteral(LiteralContext ctx) {
686 ParseTree tree = ctx.getChild(0);
687 return new StringLiteral(ObjectUtils.notNull(tree.getText()));
688 }
689
690 @Override
691 protected IExpression handleNumericLiteral(NumericliteralContext ctx) {
692 ParseTree tree = ctx.getChild(0);
693 Token token = (Token) tree.getPayload();
694 IExpression retval;
695 switch (token.getType()) {
696 case metapath10Lexer.IntegerLiteral:
697 retval = new IntegerLiteral(new BigInteger(token.getText()));
698 break;
699 case metapath10Lexer.DecimalLiteral:
700 case metapath10Lexer.DoubleLiteral:
701 retval = new DecimalLiteral(new BigDecimal(token.getText()));
702 break;
703 default:
704 throw new UnsupportedOperationException(token.getText());
705 }
706 return retval;
707 }
708
709 @Override
710 protected IExpression handleContextitemexpr(ContextitemexprContext ctx) {
711 return ContextItem.instance();
712 }
713
714 @NonNull
715 protected Stream<IExpression> parseArgumentList(@NonNull ArgumentlistContext context) {
716 int numChildren = context.getChildCount();
717
718 Stream<IExpression> retval;
719 if (numChildren == 2) {
720
721 retval = Stream.empty();
722 } else {
723 retval = context.argument().stream()
724 .map(argument -> {
725 return argument.exprsingle().accept(this);
726 });
727 }
728 assert retval != null;
729
730 return retval;
731 }
732
733 @Override
734 protected IExpression handleFunctioncall(FunctioncallContext ctx) {
735 EqnameContext nameCtx = ctx.eqname();
736 String name = nameCtx.getText();
737
738 assert name != null;
739
740 return new FunctionCall(
741 name,
742 ObjectUtils.notNull(parseArgumentList(ObjectUtils.notNull(ctx.argumentlist()))
743 .collect(Collectors.toUnmodifiableList())));
744 }
745
746 @Override
747 protected IExpression handleEqname(EqnameContext ctx) {
748 ParseTree tree = ctx.getChild(0);
749 String name = ((TerminalNode) tree).getText();
750
751 assert name != null;
752
753 return new Name(name);
754 }
755
756 @Override
757 protected IExpression handleWildcard(WildcardContext ctx) {
758 return new Wildcard();
759 }
760
761 @FunctionalInterface
762 interface ITriFunction<T, U, V, R> {
763
764 R apply(T argT, U argU, V argV);
765
766 default <W> ITriFunction<T, U, V, W> andThen(Function<? super R, ? extends W> after) {
767 Objects.requireNonNull(after);
768 return (T t, U u, V v) -> after.apply(apply(t, u, v));
769 }
770 }
771
772 @Override
773 protected IExpression handleLet(LetexprContext context) {
774 @NonNull IExpression retval = ObjectUtils.notNull(context.exprsingle().accept(this));
775
776 SimpleletclauseContext letClause = context.simpleletclause();
777 List<SimpleletbindingContext> clauses = letClause.simpleletbinding();
778
779 ListIterator<SimpleletbindingContext> reverseListIterator = clauses.listIterator(clauses.size());
780 while (reverseListIterator.hasPrevious()) {
781 SimpleletbindingContext simpleCtx = reverseListIterator.previous();
782
783 Name varName = (Name) simpleCtx.varname().accept(this);
784 IExpression boundExpression = simpleCtx.exprsingle().accept(this);
785
786 assert varName != null;
787 assert boundExpression != null;
788
789 retval = new Let(varName, boundExpression, retval);
790 }
791 return retval;
792 }
793
794 @Override
795 protected IExpression handleVarref(VarrefContext ctx) {
796 Name varName = (Name) ctx.varname().accept(this);
797 assert varName != null;
798 return new VariableReference(varName);
799 }
800 }