1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.internal;
18
19
20 import org.apache.commons.jexl3.JexlExpression;
21 import org.apache.commons.jexl3.JexlFeatures;
22 import org.apache.commons.jexl3.JexlInfo;
23 import org.apache.commons.jexl3.JexlScript;
24 import org.apache.commons.jexl3.parser.*;
25
26 import java.util.Collections;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.regex.Pattern;
30
31
32
33
34
35
36
37
38
39 public class Debugger extends ParserVisitor implements JexlInfo.Detail {
40
41 protected final StringBuilder builder = new StringBuilder();
42
43 protected JexlNode cause = null;
44
45 protected int start = 0;
46
47 protected int end = 0;
48
49 protected int indentLevel = 0;
50
51 protected int indent = 2;
52
53 protected int depth = Integer.MAX_VALUE;
54
55 protected String arrow = "->";
56
57 protected String lf = "\n";
58
59 protected boolean outputPragmas = false;
60
61
62
63
64 public Debugger() {
65
66 }
67
68
69
70
71 public void reset() {
72 builder.setLength(0);
73 cause = null;
74 start = 0;
75 end = 0;
76 indentLevel = 0;
77 indent = 2;
78 depth = Integer.MAX_VALUE;
79 }
80
81
82
83
84
85
86 protected JexlFeatures getFeatures(final JexlNode node) {
87 JexlNode walk = node;
88 while(walk != null) {
89 if (walk instanceof ASTJexlScript) {
90 final ASTJexlScript script = (ASTJexlScript) walk;
91 return script.getFeatures();
92 }
93 walk = walk.jjtGetParent();
94 }
95 return null;
96 }
97
98
99
100
101
102 protected void setArrowSymbol(final JexlNode node) {
103 final JexlFeatures features = getFeatures(node);
104 if (features != null && features.supportsFatArrow() && !features.supportsThinArrow()) {
105 arrow = "=>";
106 } else {
107 arrow = "->";
108 }
109 }
110
111
112
113
114
115
116 public boolean debug(final JexlExpression jscript) {
117 if (jscript instanceof Script) {
118 final Script script = (Script) jscript;
119 return debug(script.script);
120 }
121 return false;
122 }
123
124
125
126
127
128
129 public boolean debug(final JexlScript jscript) {
130 if (jscript instanceof Script) {
131 final Script script = (Script) jscript;
132 return debug(script.script);
133 }
134 return false;
135 }
136
137
138
139
140
141
142 public boolean debug(final JexlNode node) {
143 return debug(node, true);
144 }
145
146
147
148
149
150
151
152 public boolean debug(final JexlNode node, final boolean r) {
153 start = 0;
154 end = 0;
155 indentLevel = 0;
156 setArrowSymbol(node);
157 if (node != null) {
158 builder.setLength(0);
159 cause = node;
160
161 JexlNode walk = node;
162 if (r) {
163 while (walk.jjtGetParent() != null) {
164 walk = walk.jjtGetParent();
165 }
166 }
167 accept(walk, null);
168 }
169 return end > 0;
170 }
171
172
173
174
175 @Override
176 public String toString() {
177 return builder.toString();
178 }
179
180
181
182
183
184
185
186 public String data(final JexlNode node) {
187 start = 0;
188 end = 0;
189 indentLevel = 0;
190 setArrowSymbol(node);
191 if (node != null) {
192 builder.setLength(0);
193 cause = node;
194 accept(node, null);
195 }
196 return builder.toString();
197 }
198
199
200
201
202 @Override
203 public int start() {
204 return start;
205 }
206
207
208
209
210 @Override
211 public int end() {
212 return end;
213 }
214
215
216
217
218
219
220 public Debugger outputPragmas(final boolean flag) {
221 this.outputPragmas = flag;
222 return this;
223 }
224
225
226
227
228
229 public void setIndentation(final int level) {
230 indentation(level);
231 }
232
233
234
235
236
237
238 public Debugger indentation(final int level) {
239 indent = Math.max(level, 0);
240 indentLevel = 0;
241 return this;
242 }
243
244
245
246
247
248
249 public Debugger depth(final int rdepth) {
250 this.depth = rdepth;
251 return this;
252 }
253
254
255
256
257
258
259 public Debugger lineFeed(final String lf) {
260 this.lf = lf;
261 return this;
262 }
263
264
265
266
267
268
269
270 protected Object accept(final JexlNode node, final Object data) {
271 if (depth <= 0) {
272 builder.append("...");
273 return data;
274 }
275 if (node == cause) {
276 start = builder.length();
277 }
278 depth -= 1;
279 final Object value = node.jjtAccept(this, data);
280 depth += 1;
281 if (node == cause) {
282 end = builder.length();
283 }
284 return value;
285 }
286
287
288
289
290
291
292 private static boolean isStatement(final JexlNode child) {
293 return child instanceof ASTJexlScript
294 || child instanceof ASTBlock
295 || child instanceof ASTIfStatement
296 || child instanceof ASTForeachStatement
297 || child instanceof ASTWhileStatement
298 || child instanceof ASTDoWhileStatement
299 || child instanceof ASTAnnotation;
300 }
301
302
303
304
305
306
307 private static boolean semicolTerminated(final CharSequence cs) {
308 for(int i = cs.length() - 1; i >= 0; --i) {
309 final char c = cs.charAt(i);
310 if (c == ';') {
311 return true;
312 }
313 if (!Character.isWhitespace(c)) {
314 break;
315 }
316 }
317 return false;
318 }
319
320
321
322
323
324
325
326 protected Object acceptStatement(final JexlNode child, final Object data) {
327 final JexlNode parent = child.jjtGetParent();
328 if (indent > 0 && (parent instanceof ASTBlock || parent instanceof ASTJexlScript)) {
329 for (int i = 0; i < indentLevel; ++i) {
330 for(int s = 0; s < indent; ++s) {
331 builder.append(' ');
332 }
333 }
334 }
335 depth -= 1;
336 final Object value = accept(child, data);
337 depth += 1;
338
339 if (!isStatement(child) && !semicolTerminated(builder)) {
340 builder.append(';');
341 if (indent > 0) {
342 builder.append(lf);
343 } else {
344 builder.append(' ');
345 }
346 }
347 return value;
348 }
349
350
351
352
353
354
355
356
357
358 protected Object check(final JexlNode node, final String image, final Object data) {
359 if (node == cause) {
360 start = builder.length();
361 }
362 if (image != null) {
363 builder.append(image);
364 } else {
365 builder.append(node.toString());
366 }
367 if (node == cause) {
368 end = builder.length();
369 }
370 return data;
371 }
372
373
374
375
376
377
378
379
380
381
382 protected Object infixChildren(final JexlNode node, final String infix, final boolean paren, final Object data) {
383 final int num = node.jjtGetNumChildren();
384 if (paren) {
385 builder.append('(');
386 }
387 for (int i = 0; i < num; ++i) {
388 if (i > 0) {
389 builder.append(infix);
390 }
391 accept(node.jjtGetChild(i), data);
392 }
393 if (paren) {
394 builder.append(')');
395 }
396 return data;
397 }
398
399
400
401
402
403
404
405
406
407 protected Object prefixChild(final JexlNode node, final String prefix, final Object data) {
408 final boolean paren = node.jjtGetChild(0).jjtGetNumChildren() > 1;
409 builder.append(prefix);
410 if (paren) {
411 builder.append('(');
412 }
413 accept(node.jjtGetChild(0), data);
414 if (paren) {
415 builder.append(')');
416 }
417 return data;
418 }
419
420
421
422
423
424
425
426
427 protected Object postfixChild(final JexlNode node, final String prefix, final Object data) {
428 final boolean paren = node.jjtGetChild(0).jjtGetNumChildren() > 1;
429 if (paren) {
430 builder.append('(');
431 }
432 accept(node.jjtGetChild(0), data);
433 if (paren) {
434 builder.append(')');
435 }
436 builder.append(prefix);
437 return data;
438 }
439
440 @Override
441 protected Object visit(final ASTAddNode node, final Object data) {
442 return additiveNode(node, " + ", data);
443 }
444
445 @Override
446 protected Object visit(final ASTSubNode node, final Object data) {
447 return additiveNode(node, " - ", data);
448 }
449
450
451
452
453
454
455
456
457 protected Object additiveNode(final JexlNode node, final String op, final Object data) {
458
459 final boolean paren = node.jjtGetParent() instanceof ASTMulNode
460 || node.jjtGetParent() instanceof ASTDivNode
461 || node.jjtGetParent() instanceof ASTModNode;
462 final int num = node.jjtGetNumChildren();
463 if (paren) {
464 builder.append('(');
465 }
466 accept(node.jjtGetChild(0), data);
467 for (int i = 1; i < num; ++i) {
468 builder.append(op);
469 accept(node.jjtGetChild(i), data);
470 }
471 if (paren) {
472 builder.append(')');
473 }
474 return data;
475 }
476
477 @Override
478 protected Object visit(final ASTAndNode node, final Object data) {
479 return infixChildren(node, " && ", false, data);
480 }
481
482 @Override
483 protected Object visit(final ASTArrayAccess node, final Object data) {
484 final int num = node.jjtGetNumChildren();
485 for (int i = 0; i < num; ++i) {
486 builder.append('[');
487 accept(node.jjtGetChild(i), data);
488 builder.append(']');
489 }
490 return data;
491 }
492
493 @Override
494 protected Object visit(final ASTExtendedLiteral node, final Object data) {
495 builder.append("...");
496 return data;
497 }
498
499 @Override
500 protected Object visit(final ASTArrayLiteral node, final Object data) {
501 final int num = node.jjtGetNumChildren();
502 builder.append("[ ");
503 if (num > 0) {
504 accept(node.jjtGetChild(0), data);
505 for (int i = 1; i < num; ++i) {
506 builder.append(", ");
507 accept(node.jjtGetChild(i), data);
508 }
509 }
510 builder.append(" ]");
511 return data;
512 }
513
514 @Override
515 protected Object visit(final ASTRangeNode node, final Object data) {
516 return infixChildren(node, " .. ", false, data);
517 }
518
519 @Override
520 protected Object visit(final ASTAssignment node, final Object data) {
521 return infixChildren(node, " = ", false, data);
522 }
523
524 @Override
525 protected Object visit(final ASTBitwiseAndNode node, final Object data) {
526 return infixChildren(node, " & ", false, data);
527 }
528
529 @Override
530 protected Object visit(final ASTShiftRightNode node, final Object data) {
531 return infixChildren(node, " >> ", false, data);
532 }
533
534 @Override
535 protected Object visit(final ASTShiftRightUnsignedNode node, final Object data) {
536 return infixChildren(node, " >>> ", false, data);
537 }
538
539 @Override
540 protected Object visit(final ASTShiftLeftNode node, final Object data) {
541 return infixChildren(node, " << ", false, data);
542 }
543
544 @Override
545 protected Object visit(final ASTBitwiseComplNode node, final Object data) {
546 return prefixChild(node, "~", data);
547 }
548
549 @Override
550 protected Object visit(final ASTBitwiseOrNode node, final Object data) {
551 final boolean paren = node.jjtGetParent() instanceof ASTBitwiseAndNode;
552 return infixChildren(node, " | ", paren, data);
553 }
554
555 @Override
556 protected Object visit(final ASTBitwiseXorNode node, final Object data) {
557 final boolean paren = node.jjtGetParent() instanceof ASTBitwiseAndNode;
558 return infixChildren(node, " ^ ", paren, data);
559 }
560
561 @Override
562 protected Object visit(final ASTBlock node, final Object data) {
563 builder.append('{');
564 if (indent > 0) {
565 indentLevel += 1;
566 builder.append(lf);
567 } else {
568 builder.append(' ');
569 }
570 final int num = node.jjtGetNumChildren();
571 for (int i = 0; i < num; ++i) {
572 final JexlNode child = node.jjtGetChild(i);
573 acceptStatement(child, data);
574 }
575 if (indent > 0) {
576 indentLevel -= 1;
577 for (int i = 0; i < indentLevel; ++i) {
578 for(int s = 0; s < indent; ++s) {
579 builder.append(' ');
580 }
581 }
582 }
583 if (!Character.isSpaceChar(builder.charAt(builder.length() - 1))) {
584 builder.append(' ');
585 }
586 builder.append('}');
587 return data;
588 }
589
590 @Override
591 protected Object visit(final ASTDivNode node, final Object data) {
592 return infixChildren(node, " / ", false, data);
593 }
594
595 @Override
596 protected Object visit(final ASTEmptyFunction node, final Object data) {
597 builder.append("empty ");
598 accept(node.jjtGetChild(0), data);
599 return data;
600 }
601
602 @Override
603 protected Object visit(final ASTEQNode node, final Object data) {
604 return infixChildren(node, " == ", false, data);
605 }
606
607 @Override
608 protected Object visit(final ASTERNode node, final Object data) {
609 return infixChildren(node, " =~ ", false, data);
610 }
611
612 @Override
613 protected Object visit(final ASTSWNode node, final Object data) {
614 return infixChildren(node, " =^ ", false, data);
615 }
616
617 @Override
618 protected Object visit(final ASTEWNode node, final Object data) {
619 return infixChildren(node, " =$ ", false, data);
620 }
621
622 @Override
623 protected Object visit(final ASTNSWNode node, final Object data) {
624 return infixChildren(node, " !^ ", false, data);
625 }
626
627 @Override
628 protected Object visit(final ASTNEWNode node, final Object data) {
629 return infixChildren(node, " !$ ", false, data);
630 }
631
632 @Override
633 protected Object visit(final ASTFalseNode node, final Object data) {
634 return check(node, "false", data);
635 }
636
637 @Override
638 protected Object visit(final ASTContinue node, final Object data) {
639 return check(node, "continue", data);
640 }
641
642 @Override
643 protected Object visit(final ASTBreak node, final Object data) {
644 return check(node, "break", data);
645 }
646
647
648 @Override
649 protected Object visit(final ASTForeachStatement node, final Object data) {
650 final int form = node.getLoopForm();
651 builder.append("for(");
652 final JexlNode body;
653 if (form == 0) {
654
655 accept(node.jjtGetChild(0), data);
656 builder.append(" : ");
657 accept(node.jjtGetChild(1), data);
658 builder.append(") ");
659 body = node.jjtGetNumChildren() > 2? node.jjtGetChild(2) : null;
660 } else {
661
662 int nc = 0;
663
664 final JexlNode vars = (form & 1) != 0 ? node.jjtGetChild(nc++) : null;
665 final JexlNode predicate = (form & 2) != 0 ? node.jjtGetChild(nc++) : null;
666
667 final JexlNode step = (form & 4) != 0 ? node.jjtGetChild(nc++) : null;
668
669 body = (form & 8) != 0 ? node.jjtGetChild(nc) : null;
670 if (vars != null) {
671 accept(vars, data);
672 }
673 builder.append("; ");
674 if (predicate != null) {
675 accept(predicate, data);
676 }
677 builder.append("; ");
678 if (step != null) {
679 accept(step, data);
680 }
681 builder.append(") ");
682 }
683
684 if (body != null) {
685 accept(body, data);
686 } else {
687 builder.append(';');
688 }
689 return data;
690 }
691
692 @Override
693 protected Object visit(final ASTGENode node, final Object data) {
694 return infixChildren(node, " >= ", false, data);
695 }
696
697 @Override
698 protected Object visit(final ASTGTNode node, final Object data) {
699 return infixChildren(node, " > ", false, data);
700 }
701
702
703
704
705 protected static final Pattern QUOTED_IDENTIFIER =
706 Pattern.compile("[\\s]|[\\p{Punct}&&[^@#$_]]");
707
708
709
710
711
712
713 protected boolean needQuotes(final String str) {
714 return QUOTED_IDENTIFIER.matcher(str).find()
715 || "size".equals(str)
716 || "empty".equals(str);
717 }
718
719 @Override
720 protected Object visit(final ASTIdentifier node, final Object data) {
721 final String ns = node.getNamespace();
722 final String image = StringParser.escapeIdentifier(node.getName());
723 if (ns == null) {
724 return check(node, image, data);
725 }
726 final String nsid = StringParser.escapeIdentifier(ns) + ":" + image;
727 return check(node, nsid, data);
728 }
729
730 @Override
731 protected Object visit(final ASTIdentifierAccess node, final Object data) {
732 builder.append(node.isSafe() ? "?." : ".");
733 final String image = node.getName();
734 if (node.isExpression()) {
735 builder.append('`');
736 builder.append(image.replace("`", "\\`"));
737 builder.append('`');
738 } else if (needQuotes(image)) {
739
740 builder.append('\'');
741 builder.append(image.replace("'", "\\'"));
742 builder.append('\'');
743 } else {
744 builder.append(image);
745 }
746 return data;
747 }
748
749 @Override
750 protected Object visit(final ASTIfStatement node, final Object data) {
751 final int numChildren = node.jjtGetNumChildren();
752
753 builder.append("if (");
754 accept(node.jjtGetChild(0), data);
755 builder.append(") ");
756 acceptStatement(node.jjtGetChild(1), data);
757
758 for(int c = 2; c < numChildren - 1; c += 2) {
759 builder.append(" else if (");
760 accept(node.jjtGetChild(c), data);
761 builder.append(") ");
762 acceptStatement(node.jjtGetChild(c + 1), data);
763 }
764
765 if ((numChildren & 1) == 1) {
766 builder.append(" else ");
767 acceptStatement(node.jjtGetChild(numChildren - 1), data);
768 }
769 return data;
770 }
771
772 @Override
773 protected Object visit(final ASTNumberLiteral node, final Object data) {
774 return check(node, node.toString(), data);
775 }
776
777
778
779
780
781
782
783 protected String visitParameter(final String p, final Object data) {
784 return p;
785 }
786
787 private static boolean isLambdaExpr(final ASTJexlLambda lambda) {
788 return lambda.jjtGetNumChildren() == 1 && !isStatement(lambda.jjtGetChild(0));
789 }
790
791
792
793
794
795
796 private static void writePragmas(final StringBuilder builder, final Map<String, Object> pragmas) {
797 if (pragmas != null) {
798 for (final Map.Entry<String, Object> pragma : pragmas.entrySet()) {
799 final String key = pragma.getKey();
800 final Object value = pragma.getValue();
801 final Set<Object> values = value instanceof Set ? (Set) value : Collections.singleton(value);
802 for (final Object pragmaValue : values) {
803 builder.append("#pragma ");
804 builder.append(key);
805 builder.append(' ');
806 builder.append(pragmaValue.toString());
807 builder.append('\n');
808 }
809 }
810 }
811
812 }
813
814 @Override
815 protected Object visit(final ASTJexlScript node, final Object arg) {
816 if (outputPragmas) {
817 writePragmas(builder, node.getPragmas());
818 }
819 Object data = arg;
820 boolean named = false;
821
822 if (node instanceof ASTJexlLambda) {
823 final ASTJexlLambda lambda = (ASTJexlLambda) node;
824 final JexlNode parent = node.jjtGetParent();
825
826 final boolean expr = isLambdaExpr(lambda);
827 named = node.jjtGetChild(0) instanceof ASTVar;
828 final boolean assigned = parent instanceof ASTAssignment || named;
829 if (assigned && !expr) {
830 builder.append("function");
831 if (named) {
832 final ASTVar avar = (ASTVar) node.jjtGetChild(0);
833 builder.append(' ');
834 builder.append(avar.getName());
835 }
836 }
837 builder.append('(');
838 final String[] params = lambda.getParameters();
839 if (params != null ) {
840 final Scope scope = lambda.getScope();
841 final LexicalScope lexicalScope = lambda.getLexicalScope();
842 for (int p = 0; p < params.length; ++p) {
843 if (p > 0) {
844 builder.append(", ");
845 }
846 final String param = params[p];
847 final int symbol = scope.getSymbol(param);
848 if (lexicalScope.isConstant(symbol)) {
849 builder.append("const ");
850 } else if (scope.isLexical(symbol)) {
851 builder.append("let ");
852 }
853 builder.append(visitParameter(param, data));
854 }
855 }
856 builder.append(')');
857 if (assigned && !expr) {
858
859 builder.append(' ');
860 } else {
861 builder.append(arrow);
862
863 if (expr) {
864 builder.append(' ');
865 }
866 }
867 }
868
869 final int num = node.jjtGetNumChildren();
870 if (num == 1 && !(node instanceof ASTJexlLambda)) {
871 data = accept(node.jjtGetChild(0), data);
872 } else {
873 for (int i = named? 1 : 0; i < num; ++i) {
874 final JexlNode child = node.jjtGetChild(i);
875 acceptStatement(child, data);
876 }
877 }
878 return data;
879 }
880
881 @Override
882 protected Object visit(final ASTLENode node, final Object data) {
883 return infixChildren(node, " <= ", false, data);
884 }
885
886 @Override
887 protected Object visit(final ASTLTNode node, final Object data) {
888 return infixChildren(node, " < ", false, data);
889 }
890
891 @Override
892 protected Object visit(final ASTMapEntry node, final Object data) {
893 accept(node.jjtGetChild(0), data);
894 builder.append(" : ");
895 accept(node.jjtGetChild(1), data);
896 return data;
897 }
898
899 @Override
900 protected Object visit(final ASTSetLiteral node, final Object data) {
901 final int num = node.jjtGetNumChildren();
902 builder.append("{ ");
903 if (num > 0) {
904 accept(node.jjtGetChild(0), data);
905 for (int i = 1; i < num; ++i) {
906 builder.append(",");
907 accept(node.jjtGetChild(i), data);
908 }
909 }
910 builder.append(" }");
911 return data;
912 }
913
914 @Override
915 protected Object visit(final ASTMapLiteral node, final Object data) {
916 final int num = node.jjtGetNumChildren();
917 builder.append("{ ");
918 if (num > 0) {
919 accept(node.jjtGetChild(0), data);
920 for (int i = 1; i < num; ++i) {
921 builder.append(",");
922 accept(node.jjtGetChild(i), data);
923 }
924 } else {
925 builder.append(':');
926 }
927 builder.append(" }");
928 return data;
929 }
930
931 @Override
932 protected Object visit(final ASTConstructorNode node, final Object data) {
933 final int num = node.jjtGetNumChildren();
934 builder.append("new");
935 if (num > 0) {
936 final JexlNode c0 = node.jjtGetChild(0);
937 boolean first = true;
938 if (c0 instanceof ASTQualifiedIdentifier) {
939 builder.append(' ');
940 accept(c0, data);
941 builder.append('(');
942 } else {
943 first = false;
944 builder.append('(');
945 accept(c0, data);
946 }
947 for (int i = 1; i < num; ++i) {
948 if (!first) {
949 builder.append(", ");
950 } else {
951 first = true;
952 }
953 accept(node.jjtGetChild(i), data);
954 }
955 }
956 builder.append(")");
957 return data;
958 }
959
960 @Override
961 protected Object visit(final ASTFunctionNode node, final Object data) {
962 final int num = node.jjtGetNumChildren();
963 if (num == 3) {
964 accept(node.jjtGetChild(0), data);
965 builder.append(":");
966 accept(node.jjtGetChild(1), data);
967 accept(node.jjtGetChild(2), data);
968 } else if (num == 2) {
969 accept(node.jjtGetChild(0), data);
970 accept(node.jjtGetChild(1), data);
971 }
972 return data;
973 }
974
975 @Override
976 protected Object visit(final ASTMethodNode node, final Object data) {
977 final int num = node.jjtGetNumChildren();
978 if (num == 2) {
979 accept(node.jjtGetChild(0), data);
980 accept(node.jjtGetChild(1), data);
981 }
982 return data;
983 }
984
985 @Override
986 protected Object visit(final ASTArguments node, final Object data) {
987 final int num = node.jjtGetNumChildren();
988 builder.append("(");
989 if (num > 0) {
990 accept(node.jjtGetChild(0), data);
991 for (int i = 1; i < num; ++i) {
992 builder.append(", ");
993 accept(node.jjtGetChild(i), data);
994 }
995 }
996 builder.append(")");
997 return data;
998 }
999
1000 @Override
1001 protected Object visit(final ASTModNode node, final Object data) {
1002 return infixChildren(node, " % ", false, data);
1003 }
1004
1005 @Override
1006 protected Object visit(final ASTMulNode node, final Object data) {
1007 return infixChildren(node, " * ", false, data);
1008 }
1009
1010 @Override
1011 protected Object visit(final ASTNENode node, final Object data) {
1012 return infixChildren(node, " != ", false, data);
1013 }
1014
1015 @Override
1016 protected Object visit(final ASTNRNode node, final Object data) {
1017 return infixChildren(node, " !~ ", false, data);
1018 }
1019
1020 @Override
1021 protected Object visit(final ASTNotNode node, final Object data) {
1022 builder.append("!");
1023 accept(node.jjtGetChild(0), data);
1024 return data;
1025 }
1026
1027 @Override
1028 protected Object visit(final ASTNullLiteral node, final Object data) {
1029 check(node, "null", data);
1030 return data;
1031 }
1032
1033 @Override
1034 protected Object visit(final ASTOrNode node, final Object data) {
1035
1036 final boolean paren = node.jjtGetParent() instanceof ASTAndNode;
1037 return infixChildren(node, " || ", paren, data);
1038 }
1039
1040 @Override
1041 protected Object visit(final ASTReference node, final Object data) {
1042 final int num = node.jjtGetNumChildren();
1043 for (int i = 0; i < num; ++i) {
1044 accept(node.jjtGetChild(i), data);
1045 }
1046 return data;
1047 }
1048
1049 @Override
1050 protected Object visit(final ASTReferenceExpression node, final Object data) {
1051 final JexlNode first = node.jjtGetChild(0);
1052 builder.append('(');
1053 accept(first, data);
1054 builder.append(')');
1055 final int num = node.jjtGetNumChildren();
1056 for (int i = 1; i < num; ++i) {
1057 builder.append("[");
1058 accept(node.jjtGetChild(i), data);
1059 builder.append("]");
1060 }
1061 return data;
1062 }
1063
1064 @Override
1065 protected Object visit(final ASTReturnStatement node, final Object data) {
1066 builder.append("return ");
1067 accept(node.jjtGetChild(0), data);
1068 return data;
1069 }
1070
1071 @Override
1072 protected Object visit(final ASTSizeFunction node, final Object data) {
1073 builder.append("size ");
1074 accept(node.jjtGetChild(0), data);
1075 return data;
1076 }
1077
1078 @Override
1079 protected Object visit(final ASTQualifiedIdentifier node, final Object data) {
1080 final String img = node.getName();
1081 return this.check(node, img, data);
1082 }
1083
1084 @Override
1085 protected Object visit(final ASTStringLiteral node, final Object data) {
1086 final String img = StringParser.escapeString(node.getLiteral(), '\'');
1087 return this.check(node, img, data);
1088 }
1089
1090 @Override
1091 protected Object visit(final ASTJxltLiteral node, final Object data) {
1092 final String img = StringParser.escapeString(node.getLiteral(), '`');
1093 return this.check(node, img, data);
1094 }
1095
1096 @Override
1097 protected Object visit(final ASTRegexLiteral node, final Object data) {
1098 final String img = StringParser.escapeString(node.toString(), '/');
1099 return check(node, "~" + img, data);
1100 }
1101
1102 @Override
1103 protected Object visit(final ASTTernaryNode node, final Object data) {
1104 accept(node.jjtGetChild(0), data);
1105 if (node.jjtGetNumChildren() > 2) {
1106 builder.append("? ");
1107 accept(node.jjtGetChild(1), data);
1108 builder.append(" : ");
1109 accept(node.jjtGetChild(2), data);
1110 } else {
1111 builder.append("?: ");
1112 accept(node.jjtGetChild(1), data);
1113
1114 }
1115 return data;
1116 }
1117
1118 @Override
1119 protected Object visit(final ASTNullpNode node, final Object data) {
1120 accept(node.jjtGetChild(0), data);
1121 builder.append("??");
1122 accept(node.jjtGetChild(1), data);
1123 return data;
1124 }
1125
1126 @Override
1127 protected Object visit(final ASTTrueNode node, final Object data) {
1128 check(node, "true", data);
1129 return data;
1130 }
1131
1132 @Override
1133 protected Object visit(final ASTUnaryMinusNode node, final Object data) {
1134 return prefixChild(node, "-", data);
1135 }
1136
1137 @Override
1138 protected Object visit(final ASTUnaryPlusNode node, final Object data) {
1139 return prefixChild(node, "+", data);
1140 }
1141
1142 @Override
1143 protected Object visit(final ASTVar node, final Object data) {
1144 if (node.isConstant()) {
1145 builder.append("const ");
1146 } else if (node.isLexical()) {
1147 builder.append("let ");
1148 } else {
1149 builder.append("var ");
1150 }
1151 check(node, node.getName(), data);
1152 return data;
1153 }
1154
1155 @Override
1156 protected Object visit(final ASTDefineVars node, final Object data) {
1157 final int num = node.jjtGetNumChildren();
1158 if (num > 0) {
1159
1160 accept(node.jjtGetChild(0), data);
1161 for (int i = 1; i < num; ++i) {
1162 builder.append(", ");
1163 final JexlNode child = node.jjtGetChild(i);
1164 if (child instanceof ASTAssignment) {
1165 final ASTAssignment assign = (ASTAssignment) child;
1166 final int nc = assign.jjtGetNumChildren();
1167 final ASTVar var = (ASTVar) assign.jjtGetChild(0);
1168 builder.append(var.getName());
1169 if (nc > 1) {
1170 builder.append(" = ");
1171 accept(assign.jjtGetChild(1), data);
1172 }
1173 } else if (child instanceof ASTVar) {
1174 final ASTVar var = (ASTVar) child;
1175 builder.append(var.getName());
1176 } else {
1177
1178 accept(child, data);
1179 }
1180 }
1181 }
1182 return data;
1183 }
1184
1185 @Override
1186 protected Object visit(final ASTWhileStatement node, final Object data) {
1187 builder.append("while (");
1188 accept(node.jjtGetChild(0), data);
1189 builder.append(") ");
1190 if (node.jjtGetNumChildren() > 1) {
1191 acceptStatement(node.jjtGetChild(1), data);
1192 } else {
1193 builder.append(';');
1194 }
1195 return data;
1196 }
1197
1198 @Override
1199 protected Object visit(final ASTDoWhileStatement node, final Object data) {
1200 builder.append("do ");
1201 final int nc = node.jjtGetNumChildren();
1202 if (nc > 1) {
1203 acceptStatement(node.jjtGetChild(0), data);
1204 } else {
1205 builder.append(";");
1206 }
1207 builder.append(" while (");
1208 accept(node.jjtGetChild(nc - 1), data);
1209 builder.append(")");
1210 return data;
1211 }
1212
1213 @Override
1214 protected Object visit(final ASTSetAddNode node, final Object data) {
1215 return infixChildren(node, " += ", false, data);
1216 }
1217
1218 @Override
1219 protected Object visit(final ASTSetSubNode node, final Object data) {
1220 return infixChildren(node, " -= ", false, data);
1221 }
1222
1223 @Override
1224 protected Object visit(final ASTSetMultNode node, final Object data) {
1225 return infixChildren(node, " *= ", false, data);
1226 }
1227
1228 @Override
1229 protected Object visit(final ASTSetDivNode node, final Object data) {
1230 return infixChildren(node, " /= ", false, data);
1231 }
1232
1233 @Override
1234 protected Object visit(final ASTSetModNode node, final Object data) {
1235 return infixChildren(node, " %= ", false, data);
1236 }
1237
1238 @Override
1239 protected Object visit(final ASTSetAndNode node, final Object data) {
1240 return infixChildren(node, " &= ", false, data);
1241 }
1242
1243 @Override
1244 protected Object visit(final ASTSetOrNode node, final Object data) {
1245 return infixChildren(node, " |= ", false, data);
1246 }
1247
1248 @Override
1249 protected Object visit(final ASTSetXorNode node, final Object data) {
1250 return infixChildren(node, " ^= ", false, data);
1251 }
1252
1253 @Override
1254 protected Object visit(final ASTSetShiftRightNode node, final Object data) {
1255 return infixChildren(node, " >>= ", false, data);
1256 }
1257
1258 @Override
1259 protected Object visit(final ASTSetShiftRightUnsignedNode node, final Object data) {
1260 return infixChildren(node, " >>>= ", false, data);
1261 }
1262
1263 @Override
1264 protected Object visit(final ASTSetShiftLeftNode node, final Object data) {
1265 return infixChildren(node, " <<= ", false, data);
1266 }
1267
1268 @Override
1269 protected Object visit(final ASTGetDecrementNode node, final Object data) {
1270 return postfixChild(node, "--", data);
1271 }
1272
1273 @Override
1274 protected Object visit(final ASTGetIncrementNode node, final Object data) {
1275 return postfixChild(node, "++", data);
1276 }
1277
1278 @Override
1279 protected Object visit(final ASTDecrementGetNode node, final Object data) {
1280 return prefixChild(node, "--", data);
1281 }
1282
1283 @Override
1284 protected Object visit(final ASTIncrementGetNode node, final Object data) {
1285 return prefixChild(node, "++", data);
1286 }
1287
1288 @Override
1289 protected Object visit(final ASTAnnotation node, final Object data) {
1290 final int num = node.jjtGetNumChildren();
1291 builder.append('@');
1292 builder.append(node.getName());
1293 if (num > 0) {
1294 accept(node.jjtGetChild(0), data);
1295 }
1296 return null;
1297 }
1298
1299 @Override
1300 protected Object visit(final ASTAnnotatedStatement node, final Object data) {
1301 final int num = node.jjtGetNumChildren();
1302 for (int i = 0; i < num; ++i) {
1303 if (i > 0) {
1304 builder.append(' ');
1305 }
1306 final JexlNode child = node.jjtGetChild(i);
1307 acceptStatement(child, data);
1308 }
1309 return data;
1310 }
1311 }