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 import org.apache.commons.jexl3.JxltEngine;
20 import org.apache.commons.jexl3.internal.TemplateEngine.CompositeExpression;
21 import org.apache.commons.jexl3.internal.TemplateEngine.ConstantExpression;
22 import org.apache.commons.jexl3.internal.TemplateEngine.DeferredExpression;
23 import org.apache.commons.jexl3.internal.TemplateEngine.ImmediateExpression;
24 import org.apache.commons.jexl3.internal.TemplateEngine.NestedExpression;
25 import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
26 import org.apache.commons.jexl3.parser.ASTBlock;
27 import org.apache.commons.jexl3.parser.ASTFunctionNode;
28 import org.apache.commons.jexl3.parser.ASTIdentifier;
29 import org.apache.commons.jexl3.parser.ASTJexlScript;
30 import org.apache.commons.jexl3.parser.ASTNumberLiteral;
31 import org.apache.commons.jexl3.parser.JexlNode;
32
33
34
35
36
37 public class TemplateDebugger extends Debugger {
38
39 private ASTJexlScript script;
40
41 private TemplateExpression[] exprs;
42
43
44
45
46 public TemplateDebugger() {
47
48 }
49
50 @Override
51 protected Object acceptStatement(final JexlNode child, final Object data) {
52
53 if (exprs == null) {
54 return super.acceptStatement(child, data);
55 }
56 final TemplateExpression te = getPrintStatement(child);
57 if (te != null) {
58
59 newJxltLine();
60 return visit(te, data);
61 }
62
63 newJexlLine();
64 return super.acceptStatement(child, data);
65 }
66
67
68
69
70
71
72 public boolean debug(final JxltEngine.Expression je) {
73 if (je instanceof TemplateExpression) {
74 final TemplateEngine.TemplateExpression te = (TemplateEngine.TemplateExpression) je;
75 return visit(te, this) != null;
76 }
77 return false;
78 }
79
80
81
82
83
84
85 public boolean debug(final JxltEngine.Template jt) {
86 if (!(jt instanceof TemplateScript)) {
87 return false;
88 }
89 final TemplateScript ts = (TemplateScript) jt;
90
91 this.exprs = ts.getExpressions() == null ? new TemplateExpression[0] : ts.getExpressions();
92 this.script = ts.getScript();
93 start = 0;
94 end = 0;
95 indentLevel = 0;
96 builder.setLength(0);
97 cause = script;
98 final int num = script.jjtGetNumChildren();
99 for (int i = 0; i < num; ++i) {
100 final JexlNode child = script.jjtGetChild(i);
101 acceptStatement(child, null);
102 }
103
104 if (builder.length() > 0 && builder.charAt(builder.length() - 1) != '\n') {
105 builder.append('\n');
106 }
107 end = builder.length();
108 return end > 0;
109 }
110
111
112
113
114
115
116 private TemplateExpression getPrintStatement(final JexlNode child) {
117 if (exprs != null && child instanceof ASTFunctionNode) {
118 final ASTFunctionNode node = (ASTFunctionNode) child;
119 final ASTIdentifier ns = (ASTIdentifier) node.jjtGetChild(0);
120 final JexlNode args = node.jjtGetChild(1);
121 if ("jexl".equals(ns.getNamespace())
122 && "print".equals(ns.getName())
123 && args.jjtGetNumChildren() == 1
124 && args.jjtGetChild(0) instanceof ASTNumberLiteral) {
125 final ASTNumberLiteral exprn = (ASTNumberLiteral) args.jjtGetChild(0);
126 final int n = exprn.getLiteral().intValue();
127 if (n >= 0 && n < exprs.length) {
128 return exprs[n];
129 }
130 }
131 }
132 return null;
133 }
134
135
136
137
138 private void newJexlLine() {
139 final int length = builder.length();
140 if (length == 0) {
141 builder.append("$$ ");
142 } else {
143 for (int i = length - 1; i >= 0; --i) {
144 final char c = builder.charAt(i);
145 switch (c) {
146 case '\n':
147 builder.append("$$ ");
148 return;
149 case '}':
150 builder.append("\n$$ ");
151 return;
152 case ' ':
153 case ';':
154 return;
155 default:
156 }
157 }
158 }
159 }
160
161
162
163
164 private void newJxltLine() {
165 final int length = builder.length();
166 for (int i = length - 1; i >= 0; --i) {
167 final char c = builder.charAt(i);
168 switch (c) {
169 case '\n':
170 case ';':
171 return;
172 case '}':
173 builder.append('\n');
174 return;
175 default:
176 }
177 }
178 }
179
180 @Override
181 public void reset() {
182 super.reset();
183
184 exprs = null;
185 script = null;
186 }
187
188 @Override
189 protected Object visit(final ASTBlock node, final Object data) {
190
191 if (exprs == null) {
192 return super.visit(node, data);
193 }
194
195 builder.append('{');
196 if (indent > 0) {
197 indentLevel += 1;
198 builder.append('\n');
199 } else {
200 builder.append(' ');
201 }
202 final int num = node.jjtGetNumChildren();
203 for (int i = 0; i < num; ++i) {
204 final JexlNode child = node.jjtGetChild(i);
205 acceptStatement(child, data);
206 }
207
208 newJexlLine();
209 if (indent > 0) {
210 indentLevel -= 1;
211 for (int i = 0; i < indentLevel; ++i) {
212 for(int s = 0; s < indent; ++s) {
213 builder.append(' ');
214 }
215 }
216 }
217 builder.append('}');
218
219 return data;
220 }
221
222
223
224
225
226
227
228 private Object visit(final CompositeExpression expr, final Object data) {
229 for (final TemplateExpression ce : expr.exprs) {
230 visit(ce, data);
231 }
232 return data;
233 }
234
235
236
237
238
239
240
241 private Object visit(final ConstantExpression expr, final Object data) {
242 expr.asString(builder);
243 return data;
244 }
245
246
247
248
249
250
251
252 private Object visit(final DeferredExpression expr, final Object data) {
253 builder.append(expr.isImmediate() ? '$' : '#');
254 builder.append('{');
255 super.accept(expr.node, data);
256 builder.append('}');
257 return data;
258 }
259
260
261
262
263
264
265
266 private Object visit(final ImmediateExpression expr, final Object data) {
267 builder.append(expr.isImmediate() ? '$' : '#');
268 builder.append('{');
269 super.accept(expr.node, data);
270 builder.append('}');
271 return data;
272 }
273
274
275
276
277
278
279
280 private Object visit(final NestedExpression expr, final Object data) {
281 super.accept(expr.node, data);
282 return data;
283 }
284
285
286
287
288
289
290 private Object visit(final TemplateExpression expr, final Object data) {
291 Object r;
292 switch (expr.getType()) {
293 case CONSTANT:
294 r = visit((ConstantExpression) expr, data);
295 break;
296 case IMMEDIATE:
297 r = visit((ImmediateExpression) expr, data);
298 break;
299 case DEFERRED:
300 r = visit((DeferredExpression) expr, data);
301 break;
302 case NESTED:
303 r = visit((NestedExpression) expr, data);
304 break;
305 case COMPOSITE:
306 r = visit((CompositeExpression) expr, data);
307 break;
308 default:
309 r = null;
310 }
311 return r;
312 }
313
314 }