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 java.io.Writer;
20 import java.util.Arrays;
21
22 import org.apache.commons.jexl3.JexlContext;
23 import org.apache.commons.jexl3.JexlInfo;
24 import org.apache.commons.jexl3.JexlOptions;
25 import org.apache.commons.jexl3.JxltEngine;
26 import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
27 import org.apache.commons.jexl3.introspection.JexlMethod;
28 import org.apache.commons.jexl3.introspection.JexlUberspect;
29 import org.apache.commons.jexl3.parser.ASTArguments;
30 import org.apache.commons.jexl3.parser.ASTFunctionNode;
31 import org.apache.commons.jexl3.parser.ASTIdentifier;
32 import org.apache.commons.jexl3.parser.ASTJexlLambda;
33 import org.apache.commons.jexl3.parser.ASTJexlScript;
34 import org.apache.commons.jexl3.parser.JexlNode;
35
36
37
38
39
40
41 public class TemplateInterpreter extends Interpreter {
42
43
44
45
46 public static class Arguments {
47
48 Engine jexl;
49
50
51 JexlOptions options;
52
53
54 JexlContext jcontext;
55
56
57 Frame jframe;
58
59
60 TemplateExpression[] expressions;
61
62
63 Writer out;
64
65
66
67
68
69
70 Arguments(final Engine e) {
71 this.jexl = e;
72 }
73
74
75
76
77
78
79
80 Arguments context(final JexlContext j) {
81 this.jcontext = j;
82 return this;
83 }
84
85
86
87
88
89
90
91 Arguments expressions(final TemplateExpression[] e) {
92 this.expressions = e;
93 return this;
94 }
95
96
97
98
99
100
101
102 Arguments frame(final Frame f) {
103 this.jframe = f;
104 return this;
105 }
106
107
108
109
110
111
112
113 Arguments options(final JexlOptions o) {
114 this.options = o;
115 return this;
116 }
117
118
119
120
121
122
123
124 Arguments writer(final Writer o) {
125 this.out = o;
126 return this;
127 }
128 }
129
130
131 final TemplateExpression[] exprs;
132
133
134 final Writer writer;
135
136
137
138
139
140
141 protected TemplateInterpreter(final Arguments args) {
142 super(args.jexl, args.options, args.jcontext, args.jframe);
143 exprs = args.expressions;
144 writer = args.out;
145 block = new LexicalFrame(frame, null);
146 }
147
148
149
150
151
152
153
154
155
156
157
158 private void doPrint(final JexlInfo info, final Object arg) {
159 try {
160 if (writer != null) {
161 if (arg instanceof CharSequence) {
162 writer.write(arg.toString());
163 } else if (arg != null) {
164 final Object[] value = {arg};
165 final JexlUberspect uber = jexl.getUberspect();
166 final JexlMethod method = uber.getMethod(writer, "print", value);
167 if (method != null) {
168 method.invoke(writer, value);
169 } else {
170 writer.write(arg.toString());
171 }
172 }
173 }
174 } catch (final java.io.IOException xio) {
175 throw TemplateEngine.createException(info, "call print", null, xio);
176 } catch (final java.lang.Exception xany) {
177 throw TemplateEngine.createException(info, "invoke print", null, xany);
178 }
179 }
180
181
182
183
184
185
186
187
188
189 public void include(final JxltEngine.Template script, final Object... args) {
190 script.evaluate(context, writer, args);
191 }
192
193
194
195
196
197
198 public void print(final int e) {
199 if (e < 0 || e >= exprs.length) {
200 return;
201 }
202 TemplateEngine.TemplateExpression expr = exprs[e];
203 if (expr.isDeferred()) {
204 expr = expr.prepare(context, frame, options);
205 }
206 if (expr instanceof TemplateEngine.CompositeExpression) {
207 printComposite((TemplateEngine.CompositeExpression) expr);
208 } else {
209 doPrint(expr.getInfo(), expr.evaluate(this));
210 }
211 }
212
213
214
215
216
217
218 private void printComposite(final TemplateEngine.CompositeExpression composite) {
219 final TemplateEngine.TemplateExpression[] composites = composite.exprs;
220 Object value;
221 for (final TemplateExpression expr : composites) {
222 value = expr.evaluate(this);
223 doPrint(expr.getInfo(), value);
224 }
225 }
226
227 @Override
228 protected Object resolveNamespace(final String prefix, final JexlNode node) {
229 return "jexl".equals(prefix)? this : super.resolveNamespace(prefix, node);
230 }
231
232
233
234
235
236
237
238
239
240
241 @Override
242 protected Object visit(final ASTFunctionNode node, final Object data) {
243 final int argc = node.jjtGetNumChildren();
244 if (argc == 2) {
245 final ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(0);
246 if ("jexl".equals(functionNode.getNamespace())) {
247 final String functionName = functionNode.getName();
248 final ASTArguments argNode = (ASTArguments) node.jjtGetChild(1);
249 if ("print".equals(functionName)) {
250
251 final Object[] argv = visit(argNode, null);
252 if (argv != null && argv.length > 0 && argv[0] instanceof Number) {
253 print(((Number) argv[0]).intValue());
254 return null;
255 }
256 }
257 if ("include".equals(functionName)) {
258
259 Object[] argv = visit(argNode, null);
260 if (argv != null && argv.length > 0 && argv[0] instanceof TemplateScript) {
261 final TemplateScript script = (TemplateScript) argv[0];
262 argv = argv.length > 1? Arrays.copyOfRange(argv, 1, argv.length) : null;
263 include(script, argv);
264 return null;
265 }
266 }
267
268 throw new JxltEngine.Exception(node.jexlInfo(), "no callable template function " + functionName, null);
269 }
270 }
271 return super.visit(node, data);
272 }
273
274 @Override
275 protected Object visit(final ASTIdentifier node, final Object data) {
276 final String name = node.getName();
277 if ("$jexl".equals(name)) {
278 return writer;
279 }
280 return super.visit(node, data);
281 }
282
283 @Override
284 protected Object visit(final ASTJexlScript script, final Object data) {
285 if (script instanceof ASTJexlLambda && !((ASTJexlLambda) script).isTopLevel()) {
286 return new Closure(this, (ASTJexlLambda) script) {
287 @Override
288 protected Interpreter createInterpreter(final JexlContext context, final Frame local, final JexlOptions options) {
289 final TemplateInterpreter.Arguments targs = new TemplateInterpreter.Arguments(jexl)
290 .context(context)
291 .options(options)
292 .frame(local)
293 .expressions(exprs)
294 .writer(writer);
295 return jexl.createTemplateInterpreter(targs);
296 }
297 };
298 }
299
300 final Object[] stack = saveStack();
301 try {
302 return runScript(script, data);
303 } finally {
304 restoreStack(stack);
305 }
306 }
307
308 private Object[] saveStack() {
309 return frame != null && frame.stack != null? frame.stack.clone() : null;
310 }
311
312 private void restoreStack(Object[] stack) {
313 if (stack != null) {
314 System.arraycopy(stack, 0, frame.stack, 0, stack.length);
315 }
316 }
317
318 }