1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl2;
18
19 import java.util.regex.Pattern;
20 import org.apache.commons.jexl2.parser.ASTAdditiveNode;
21 import org.apache.commons.jexl2.parser.ASTAdditiveOperator;
22 import org.apache.commons.jexl2.parser.ASTAmbiguous;
23 import org.apache.commons.jexl2.parser.ASTAndNode;
24 import org.apache.commons.jexl2.parser.ASTArrayAccess;
25 import org.apache.commons.jexl2.parser.ASTArrayLiteral;
26 import org.apache.commons.jexl2.parser.ASTAssignment;
27 import org.apache.commons.jexl2.parser.ASTBitwiseAndNode;
28 import org.apache.commons.jexl2.parser.ASTBitwiseComplNode;
29 import org.apache.commons.jexl2.parser.ASTBitwiseOrNode;
30 import org.apache.commons.jexl2.parser.ASTBitwiseXorNode;
31 import org.apache.commons.jexl2.parser.ASTBlock;
32 import org.apache.commons.jexl2.parser.ASTConstructorNode;
33 import org.apache.commons.jexl2.parser.ASTDivNode;
34 import org.apache.commons.jexl2.parser.ASTEQNode;
35 import org.apache.commons.jexl2.parser.ASTERNode;
36 import org.apache.commons.jexl2.parser.ASTEmptyFunction;
37 import org.apache.commons.jexl2.parser.ASTFalseNode;
38 import org.apache.commons.jexl2.parser.ASTForeachStatement;
39 import org.apache.commons.jexl2.parser.ASTFunctionNode;
40 import org.apache.commons.jexl2.parser.ASTGENode;
41 import org.apache.commons.jexl2.parser.ASTGTNode;
42 import org.apache.commons.jexl2.parser.ASTIdentifier;
43 import org.apache.commons.jexl2.parser.ASTIfStatement;
44 import org.apache.commons.jexl2.parser.ASTJexlScript;
45 import org.apache.commons.jexl2.parser.ASTLENode;
46 import org.apache.commons.jexl2.parser.ASTLTNode;
47 import org.apache.commons.jexl2.parser.ASTMapEntry;
48 import org.apache.commons.jexl2.parser.ASTMapLiteral;
49 import org.apache.commons.jexl2.parser.ASTMethodNode;
50 import org.apache.commons.jexl2.parser.ASTModNode;
51 import org.apache.commons.jexl2.parser.ASTMulNode;
52 import org.apache.commons.jexl2.parser.ASTNENode;
53 import org.apache.commons.jexl2.parser.ASTNRNode;
54 import org.apache.commons.jexl2.parser.ASTNotNode;
55 import org.apache.commons.jexl2.parser.ASTNullLiteral;
56 import org.apache.commons.jexl2.parser.ASTNumberLiteral;
57 import org.apache.commons.jexl2.parser.ASTOrNode;
58 import org.apache.commons.jexl2.parser.ASTReference;
59 import org.apache.commons.jexl2.parser.ASTReferenceExpression;
60 import org.apache.commons.jexl2.parser.ASTReturnStatement;
61 import org.apache.commons.jexl2.parser.ASTSizeFunction;
62 import org.apache.commons.jexl2.parser.ASTSizeMethod;
63 import org.apache.commons.jexl2.parser.ASTStringLiteral;
64 import org.apache.commons.jexl2.parser.ASTTernaryNode;
65 import org.apache.commons.jexl2.parser.ASTTrueNode;
66 import org.apache.commons.jexl2.parser.ASTUnaryMinusNode;
67 import org.apache.commons.jexl2.parser.ASTVar;
68 import org.apache.commons.jexl2.parser.ASTWhileStatement;
69 import org.apache.commons.jexl2.parser.JexlNode;
70
71 import org.apache.commons.jexl2.parser.ParserVisitor;
72 import org.apache.commons.jexl2.parser.SimpleNode;
73
74
75
76
77
78
79
80
81
82
83
84 final class Debugger implements ParserVisitor {
85
86 private final StringBuilder builder;
87
88 private JexlNode cause;
89
90 private int start;
91
92 private int end;
93
94
95
96
97 Debugger() {
98 builder = new StringBuilder();
99 cause = null;
100 start = 0;
101 end = 0;
102 }
103
104
105
106
107
108
109 public boolean debug(JexlNode node) {
110 start = 0;
111 end = 0;
112 if (node != null) {
113 builder.setLength(0);
114 this.cause = node;
115
116 JexlNode root = node;
117 while (root.jjtGetParent() != null) {
118 root = root.jjtGetParent();
119 }
120 root.jjtAccept(this, null);
121 }
122 return end > 0;
123 }
124
125
126
127
128 public String data() {
129 return builder.toString();
130 }
131
132
133
134
135
136
137
138
139 public String data(JexlNode node) {
140 start = 0;
141 end = 0;
142 if (node != null) {
143 builder.setLength(0);
144 this.cause = node;
145 node.jjtAccept(this, null);
146 }
147 return builder.toString();
148 }
149
150
151
152
153 public int start() {
154 return start;
155 }
156
157
158
159
160 public int end() {
161 return end;
162 }
163
164
165
166
167
168
169
170
171 private Object accept(JexlNode node, Object data) {
172 if (node == cause) {
173 start = builder.length();
174 }
175 Object value = node.jjtAccept(this, data);
176 if (node == cause) {
177 end = builder.length();
178 }
179 return value;
180 }
181
182
183
184
185
186
187
188 private Object acceptStatement(JexlNode child, Object data) {
189 Object value = accept(child, data);
190
191 if (child instanceof ASTBlock
192 || child instanceof ASTIfStatement
193 || child instanceof ASTForeachStatement
194 || child instanceof ASTWhileStatement) {
195 return value;
196 }
197 builder.append(";");
198 return value;
199 }
200
201
202
203
204
205
206
207
208
209 private Object check(JexlNode node, String image, Object data) {
210 if (node == cause) {
211 start = builder.length();
212 }
213 if (image != null) {
214 builder.append(image);
215 } else {
216 builder.append(node.toString());
217 }
218 if (node == cause) {
219 end = builder.length();
220 }
221 return data;
222 }
223
224
225
226
227
228
229
230
231
232
233 private Object infixChildren(JexlNode node, String infix, boolean paren, Object data) {
234 int num = node.jjtGetNumChildren();
235 if (paren) {
236 builder.append("(");
237 }
238 for (int i = 0; i < num; ++i) {
239 if (i > 0) {
240 builder.append(infix);
241 }
242 accept(node.jjtGetChild(i), data);
243 }
244 if (paren) {
245 builder.append(")");
246 }
247 return data;
248 }
249
250
251
252
253
254
255
256
257
258 private Object prefixChild(JexlNode node, String prefix, Object data) {
259 boolean paren = node.jjtGetChild(0).jjtGetNumChildren() > 1;
260 builder.append(prefix);
261 if (paren) {
262 builder.append("(");
263 }
264 accept(node.jjtGetChild(0), data);
265 if (paren) {
266 builder.append(")");
267 }
268 return data;
269 }
270
271
272 public Object visit(ASTAdditiveNode node, Object data) {
273
274 boolean paren = node.jjtGetParent() instanceof ASTMulNode
275 || node.jjtGetParent() instanceof ASTDivNode
276 || node.jjtGetParent() instanceof ASTModNode;
277 int num = node.jjtGetNumChildren();
278 if (paren) {
279 builder.append("(");
280 }
281 accept(node.jjtGetChild(0), data);
282 for (int i = 1; i < num; ++i) {
283 accept(node.jjtGetChild(i), data);
284 }
285 if (paren) {
286 builder.append(")");
287 }
288 return data;
289 }
290
291
292 public Object visit(ASTAdditiveOperator node, Object data) {
293 builder.append(' ');
294 builder.append(node.image);
295 builder.append(' ');
296 return data;
297 }
298
299
300 public Object visit(ASTAndNode node, Object data) {
301 return infixChildren(node, " && ", false, data);
302 }
303
304
305 public Object visit(ASTArrayAccess node, Object data) {
306 accept(node.jjtGetChild(0), data);
307 int num = node.jjtGetNumChildren();
308 for (int i = 1; i < num; ++i) {
309 builder.append("[");
310 accept(node.jjtGetChild(i), data);
311 builder.append("]");
312 }
313 return data;
314 }
315
316
317 public Object visit(ASTArrayLiteral node, Object data) {
318 int num = node.jjtGetNumChildren();
319 builder.append("[ ");
320 if (num > 0) {
321 accept(node.jjtGetChild(0), data);
322 for (int i = 1; i < num; ++i) {
323 builder.append(", ");
324 accept(node.jjtGetChild(i), data);
325 }
326 }
327 builder.append(" ]");
328 return data;
329 }
330
331
332 public Object visit(ASTAssignment node, Object data) {
333 return infixChildren(node, " = ", false, data);
334 }
335
336
337 public Object visit(ASTBitwiseAndNode node, Object data) {
338 return infixChildren(node, " & ", false, data);
339 }
340
341
342 public Object visit(ASTBitwiseComplNode node, Object data) {
343 return prefixChild(node, "~", data);
344 }
345
346
347 public Object visit(ASTBitwiseOrNode node, Object data) {
348 boolean paren = node.jjtGetParent() instanceof ASTBitwiseAndNode;
349 return infixChildren(node, " | ", paren, data);
350 }
351
352
353 public Object visit(ASTBitwiseXorNode node, Object data) {
354 boolean paren = node.jjtGetParent() instanceof ASTBitwiseAndNode;
355 return infixChildren(node, " ^ ", paren, data);
356 }
357
358
359 public Object visit(ASTBlock node, Object data) {
360 builder.append("{ ");
361 int num = node.jjtGetNumChildren();
362 for (int i = 0; i < num; ++i) {
363 JexlNode child = node.jjtGetChild(i);
364 acceptStatement(child, data);
365 }
366 builder.append(" }");
367 return data;
368 }
369
370
371 public Object visit(ASTDivNode node, Object data) {
372 return infixChildren(node, " / ", false, data);
373 }
374
375
376 public Object visit(ASTEmptyFunction node, Object data) {
377 builder.append("empty(");
378 accept(node.jjtGetChild(0), data);
379 builder.append(")");
380 return data;
381 }
382
383
384 public Object visit(ASTEQNode node, Object data) {
385 return infixChildren(node, " == ", false, data);
386 }
387
388
389 public Object visit(ASTERNode node, Object data) {
390 return infixChildren(node, " =~ ", false, data);
391 }
392
393
394 public Object visit(ASTFalseNode node, Object data) {
395 return check(node, "false", data);
396 }
397
398
399 public Object visit(ASTForeachStatement node, Object data) {
400 builder.append("for(");
401 accept(node.jjtGetChild(0), data);
402 builder.append(" : ");
403 accept(node.jjtGetChild(1), data);
404 builder.append(") ");
405 if (node.jjtGetNumChildren() > 2) {
406 acceptStatement(node.jjtGetChild(2), data);
407 } else {
408 builder.append(';');
409 }
410 return data;
411 }
412
413
414 public Object visit(ASTGENode node, Object data) {
415 return infixChildren(node, " >= ", false, data);
416 }
417
418
419 public Object visit(ASTGTNode node, Object data) {
420 return infixChildren(node, " > ", false, data);
421 }
422
423
424 private static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]");
425
426
427 public Object visit(ASTIdentifier node, Object data) {
428 String image = node.image;
429 if (QUOTED_IDENTIFIER.matcher(image).find()) {
430
431 image = "'" + node.image.replace("'", "\\'") + "'";
432 }
433 return check(node, image, data);
434 }
435
436
437 public Object visit(ASTIfStatement node, Object data) {
438 builder.append("if (");
439 accept(node.jjtGetChild(0), data);
440 builder.append(") ");
441 if (node.jjtGetNumChildren() > 1) {
442 acceptStatement(node.jjtGetChild(1), data);
443 if (node.jjtGetNumChildren() > 2) {
444 builder.append(" else ");
445 acceptStatement(node.jjtGetChild(2), data);
446 } else {
447 builder.append(';');
448 }
449 } else {
450 builder.append(';');
451 }
452 return data;
453 }
454
455
456 public Object visit(ASTNumberLiteral node, Object data) {
457 return check(node, node.image, data);
458 }
459
460
461 public Object visit(ASTJexlScript node, Object data) {
462 int num = node.jjtGetNumChildren();
463 for (int i = 0; i < num; ++i) {
464 JexlNode child = node.jjtGetChild(i);
465 acceptStatement(child, data);
466 }
467 return data;
468 }
469
470
471 public Object visit(ASTLENode node, Object data) {
472 return infixChildren(node, " <= ", false, data);
473 }
474
475
476 public Object visit(ASTLTNode node, Object data) {
477 return infixChildren(node, " < ", false, data);
478 }
479
480
481 public Object visit(ASTMapEntry node, Object data) {
482 accept(node.jjtGetChild(0), data);
483 builder.append(" : ");
484 accept(node.jjtGetChild(1), data);
485 return data;
486 }
487
488
489 public Object visit(ASTMapLiteral node, Object data) {
490 int num = node.jjtGetNumChildren();
491 builder.append("{ ");
492 if (num > 0) {
493 accept(node.jjtGetChild(0), data);
494 for (int i = 1; i < num; ++i) {
495 builder.append(", ");
496 accept(node.jjtGetChild(i), data);
497 }
498 } else {
499 builder.append(':');
500 }
501 builder.append(" }");
502 return data;
503 }
504
505
506 public Object visit(ASTConstructorNode node, Object data) {
507 int num = node.jjtGetNumChildren();
508 builder.append("new ");
509 builder.append("(");
510 accept(node.jjtGetChild(0), data);
511 for (int i = 1; i < num; ++i) {
512 builder.append(", ");
513 accept(node.jjtGetChild(i), data);
514 }
515 builder.append(")");
516 return data;
517 }
518
519
520 public Object visit(ASTFunctionNode node, Object data) {
521 int num = node.jjtGetNumChildren();
522 accept(node.jjtGetChild(0), data);
523 builder.append(":");
524 accept(node.jjtGetChild(1), data);
525 builder.append("(");
526 for (int i = 2; i < num; ++i) {
527 if (i > 2) {
528 builder.append(", ");
529 }
530 accept(node.jjtGetChild(i), data);
531 }
532 builder.append(")");
533 return data;
534 }
535
536
537 public Object visit(ASTMethodNode node, Object data) {
538 int num = node.jjtGetNumChildren();
539 accept(node.jjtGetChild(0), data);
540 builder.append("(");
541 for (int i = 1; i < num; ++i) {
542 if (i > 1) {
543 builder.append(", ");
544 }
545 accept(node.jjtGetChild(i), data);
546 }
547 builder.append(")");
548 return data;
549 }
550
551
552 public Object visit(ASTModNode node, Object data) {
553 return infixChildren(node, " % ", false, data);
554 }
555
556
557 public Object visit(ASTMulNode node, Object data) {
558 return infixChildren(node, " * ", false, data);
559 }
560
561
562 public Object visit(ASTNENode node, Object data) {
563 return infixChildren(node, " != ", false, data);
564 }
565
566
567 public Object visit(ASTNRNode node, Object data) {
568 return infixChildren(node, " !~ ", false, data);
569 }
570
571
572 public Object visit(ASTNotNode node, Object data) {
573 builder.append("!");
574 accept(node.jjtGetChild(0), data);
575 return data;
576 }
577
578
579 public Object visit(ASTNullLiteral node, Object data) {
580 check(node, "null", data);
581 return data;
582 }
583
584
585 public Object visit(ASTOrNode node, Object data) {
586
587 boolean paren = node.jjtGetParent() instanceof ASTAndNode;
588 return infixChildren(node, " || ", paren, data);
589 }
590
591
592 public Object visit(ASTReference node, Object data) {
593 int num = node.jjtGetNumChildren();
594 accept(node.jjtGetChild(0), data);
595 for (int i = 1; i < num; ++i) {
596 builder.append(".");
597 accept(node.jjtGetChild(i), data);
598 }
599 return data;
600 }
601
602
603 public Object visit(ASTReferenceExpression node, Object data) {
604 JexlNode first = node.jjtGetChild(0);
605 builder.append('(');
606 accept(first, data);
607 builder.append(')');
608 int num = node.jjtGetNumChildren();
609 for (int i = 1; i < num; ++i) {
610 builder.append("[");
611 accept(node.jjtGetChild(i), data);
612 builder.append("]");
613 }
614 return data;
615 }
616
617
618 public Object visit(ASTReturnStatement node, Object data) {
619 builder.append("return ");
620 accept(node.jjtGetChild(0), data);
621 return data;
622 }
623
624
625 public Object visit(ASTSizeFunction node, Object data) {
626 builder.append("size(");
627 accept(node.jjtGetChild(0), data);
628 builder.append(")");
629 return data;
630 }
631
632
633 public Object visit(ASTSizeMethod node, Object data) {
634 check(node, "size()", data);
635 return data;
636 }
637
638
639 public Object visit(ASTStringLiteral node, Object data) {
640 String img = node.image.replace("'", "\\'");
641 return check(node, "'" + img + "'", data);
642 }
643
644
645 public Object visit(ASTTernaryNode node, Object data) {
646 accept(node.jjtGetChild(0), data);
647 if (node.jjtGetNumChildren() > 2) {
648 builder.append("? ");
649 accept(node.jjtGetChild(1), data);
650 builder.append(" : ");
651 accept(node.jjtGetChild(2), data);
652 } else {
653 builder.append("?:");
654 accept(node.jjtGetChild(1), data);
655
656 }
657 return data;
658 }
659
660
661 public Object visit(ASTTrueNode node, Object data) {
662 check(node, "true", data);
663 return data;
664 }
665
666
667 public Object visit(ASTUnaryMinusNode node, Object data) {
668 return prefixChild(node, "-", data);
669 }
670
671
672 public Object visit(ASTVar node, Object data) {
673 builder.append("var ");
674 check(node, node.image, data);
675 return data;
676 }
677
678
679 public Object visit(ASTWhileStatement node, Object data) {
680 builder.append("while (");
681 accept(node.jjtGetChild(0), data);
682 builder.append(") ");
683 if (node.jjtGetNumChildren() > 1) {
684 acceptStatement(node.jjtGetChild(1), data);
685 } else {
686 builder.append(';');
687 }
688 return data;
689 }
690
691
692 public Object visit(SimpleNode node, Object data) {
693 throw new UnsupportedOperationException("unexpected type of node");
694 }
695
696
697 public Object visit(ASTAmbiguous node, Object data) {
698 throw new UnsupportedOperationException("unexpected type of node");
699 }
700 }