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