Evaluator.java
biz/hammurapi/eval/Evaluator.java
Violations
Inspector |
Message |
Severity |
Location |
Java Inspector 006 |
Missing default case for switch statement |
1 |
488:25
|
Java Inspector 031 |
Switch statement case without 'break' |
1 |
492:33
|
Java Inspector 048 |
Copyrights information should be present in each file. |
1 |
|
Java Inspector 070-B |
Cyclomatic complexity is too high: 31, maximum allowed is 20 |
1 |
130:9
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
54:9
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
113:35
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
232:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
245:31
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
281:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
289:15
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
302:15
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
397:43
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
400:51
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
408:51
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
430:27
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
463:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
526:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
544:19
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
547:19
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
549:23
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 31, maximum allowed is 12 |
2 |
130:9
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 14, maximum allowed is 12 |
2 |
319:5
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 13, maximum allowed is 12 |
2 |
386:9
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 19, maximum allowed is 12 |
2 |
450:5
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 14, maximum allowed is 12 |
2 |
562:5
|
Java Inspector 073 [java.lang.StringBuffer] |
In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . |
2 |
164:33
|
Java Inspector 073 [java.lang.StringBuffer] |
In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . |
2 |
504:25
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
59:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
94:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
106:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
130:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
214:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
264:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
319:5
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
386:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
450:5
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
562:5
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
628:9
|
Java Inspector 089 |
Type is not documented |
2 |
51:1
|
Java Inspector 089 |
Undocumented constructor |
2 |
59:9
|
Java Inspector 089 |
Undocumented method |
2 |
94:9
|
Java Inspector 089 |
Undocumented method |
2 |
106:9
|
Java Inspector 089 |
Undocumented method |
2 |
224:17
|
Java Inspector 089 |
Undocumented method |
2 |
237:17
|
Java Inspector 089 |
Parameter name is not documented |
2 |
645:9
|
Java Inspector 089 |
Method return value is not properly documented |
2 |
645:9
|
Java Inspector 005 |
Classes, interfaces, methods, and variables should be named according to Sun's naming conventions. |
3 |
52:9
|
Java Inspector 024 |
Avoid hardwired character literals |
3 |
646:33
|
Java Inspector 024 |
Avoid hardwired character literals |
3 |
646:38
|
Java Inspector 025 |
Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] |
3 |
166:53
|
Java Inspector 025 |
Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] |
3 |
169:53
|
Java Inspector 025 |
Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] |
3 |
172:53
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
60:30
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
86:78
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
144:63
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
165:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
165:83
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
166:56
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
168:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
168:83
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
169:56
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
171:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
171:83
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
172:56
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
204:30
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
204:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
204:113
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
204:133
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
220:93
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
270:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
270:85
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
270:121
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
321:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
321:72
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
321:107
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
338:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
338:73
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
338:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
351:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
351:73
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
351:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
364:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
364:73
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
364:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
375:39
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
460:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
460:92
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
500:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
500:92
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
504:59
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
504:91
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
507:44
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
580:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
592:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
603:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
614:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
625:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
633:78
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
635:63
|
Java Inspector 040 |
Parameter name methods clashes with field name in Evaluator |
3 |
450:94
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
59:9
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package biz.hammurapi.eval;
24
25import java.io.StringReader;
26import java.lang.reflect.Array;
27import java.lang.reflect.Method;
28import java.util.ArrayList;
29import java.util.Collection;
30import java.util.Enumeration;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34
35import org.apache.log4j.Logger;
36
37import antlr.RecognitionException;
38import antlr.TokenStreamException;
39import biz.hammurapi.antlr.AST;
40import biz.hammurapi.antlr.Token;
41import biz.hammurapi.config.BeanContext;
42import biz.hammurapi.config.Context;
43import biz.hammurapi.convert.Converter;
44
45
46
47
48
49
50
51public class Evaluator {
52 private static final Logger logger=Logger.getLogger(Evaluator.class);
53
54 private AST[] nodes;
55 private Converter converter;
56
57 private Collection methods=new ArrayList();
58
59 public Evaluator(String expression, Collection methods, Converter converter) throws EvaluationException {
60 logger.debug("New evaluator for expression: "+expression);
61 this.converter=converter;
62 ExpressionLexer lexer=new ExpressionLexer(new StringReader(expression));
63 lexer.setTokenObjectClass(Token.class.getName());
64 ExpressionRecognizer parser=new ExpressionRecognizer(lexer);
65 parser.setASTNodeClass(AST.class.getName());
66 try {
67 parser.expressionList();
68 } catch (RecognitionException e) {
69 throw new EvaluationException(e);
70 } catch (TokenStreamException e) {
71 throw new EvaluationException(e);
72 }
73
74 List nodeList=new ArrayList();
75 for (AST ast=(AST) parser.getAST().getFirstChild(); ast!=null; ast=(AST) ast.getNextSibling()) {
76 nodeList.add(ast);
77 }
78
79 nodes=(AST[]) nodeList.toArray(new AST[nodeList.size()]);
80
81 if (methods!=null) {
82 this.methods.addAll(methods);
83 }
84
85 try {
86 this.methods.add(new MethodEntry(null, Evaluator.class.getMethod("forEach", new Class[] {Object.class})));
87 } catch (SecurityException e) {
88 throw new EvaluationException(e);
89 } catch (NoSuchMethodException e) {
90 throw new EvaluationException(e);
91 }
92 }
93
94 public static MultiResult forEach(Object param) throws EvaluationException {
95 Collection values = new ArrayList();
96 populate(((SingleResult) param).getValue(), values);
97 return new MultiResult(null, values, null);
98 }
99
100 void print() {
101 if (nodes.length!=0) {
102 nodes[0].print(ExpressionRecognizer._tokenNames, true);
103 }
104 }
105
106 public Collection evaluate(Context context) throws EvaluationException {
107 Collection ret=new ArrayList();
108 for (int i=0; i<nodes.length; i++) {
109 Result result = evaluate(null, nodes[i], context);
110 if (result instanceof SingleResult) {
111 ret.add(((SingleResult) result).getValue());
112 } else {
113 Object[] values=((MultiResult) result).getValues();
114 for (int j=0; j<values.length; j++) {
115 ret.add(values[j]);
116 }
117 }
118 }
119 return ret;
120 }
121
122
123
124
125
126
127
128
129
130 private Result evaluate(Result res, AST ast, Context context) throws EvaluationException {
131 logAst(ast);
132 switch (ast.getType()) {
133 case ExpressionTokenTypes.MINUS:
134 return minus(res, ast, context);
135 case ExpressionTokenTypes.PLUS:
136 return plus(res, ast, context);
137 case ExpressionTokenTypes.LNOT:
138 return lnot(res, ast, context);
139 case ExpressionTokenTypes.TYPECAST:
140 return typecast(res, ast, context);
141 case ExpressionTokenTypes.METHOD_CALL:
142 return invoke(res, ast, context);
143 case ExpressionTokenTypes.ARRAY_DECLARATOR:
144 throw new EvaluationException("Handle it!");
145 case ExpressionTokenTypes.INDEX_OP:
146 return index(res, ast, context);
147 case ExpressionTokenTypes.DOT:
148 return dot(res, ast, context);
149 case ExpressionTokenTypes.IDENT:
150 Object obj = context.get(ast.getText());
151 return obj instanceof Result ? (Result) obj : new SingleResult(this.converter, null, obj);
152 case ExpressionTokenTypes.LITERAL_true:
153 return new SingleResult(this.converter, boolean.class, Boolean.TRUE);
154 case ExpressionTokenTypes.LITERAL_false:
155 return new SingleResult(this.converter, boolean.class, Boolean.FALSE);
156 case ExpressionTokenTypes.LITERAL_null:
157 return new SingleResult(this.converter, null, null);
158 case ExpressionTokenTypes.NUM_INT:
159 return new SingleResult(this.converter, int.class, new Integer(ast.getText()));
160 case ExpressionTokenTypes.CHAR_LITERAL:
161 return new SingleResult(this.converter, char.class, ast.getText().substring(0,1));
162 case ExpressionTokenTypes.STRING_LITERAL:
163 String rawText=ast.getText();
164 StringBuffer sb=new StringBuffer(rawText.substring(1, rawText.length()-1));
165 for (int i=sb.indexOf("\\n"); i!=-1; i=sb.indexOf("\\n")) {
166 sb.replace(i, i+2, "\n");
167 }
168 for (int i=sb.indexOf("\\r"); i!=-1; i=sb.indexOf("\\r")) {
169 sb.replace(i, i+2, "\r");
170 }
171 for (int i=sb.indexOf("\\t"); i!=-1; i=sb.indexOf("\\t")) {
172 sb.replace(i, i+2, "\t");
173 }
174 return new SingleResult(this.converter, String.class, sb.toString());
175 case ExpressionTokenTypes.NUM_FLOAT:
176 return new SingleResult(this.converter, float.class, new Float(ast.getText()));
177 case ExpressionTokenTypes.NUM_LONG:
178 return new SingleResult(this.converter, long.class, new Long(ast.getText()));
179 case ExpressionTokenTypes.NUM_DOUBLE:
180 return new SingleResult(this.converter, double.class, new Double(ast.getText()));
181 case ExpressionTokenTypes.LITERAL_boolean:
182 return new SingleResult(this.converter, boolean.class, null);
183 case ExpressionTokenTypes.LITERAL_byte:
184 return new SingleResult(this.converter, byte.class, null);
185 case ExpressionTokenTypes.LITERAL_char:
186 return new SingleResult(this.converter, char.class, null);
187 case ExpressionTokenTypes.LITERAL_short:
188 return new SingleResult(this.converter, short.class, null);
189 case ExpressionTokenTypes.LITERAL_float:
190 return new SingleResult(this.converter, float.class, null);
191 case ExpressionTokenTypes.LITERAL_long:
192 return new SingleResult(this.converter, long.class, null);
193 case ExpressionTokenTypes.LITERAL_double:
194 return new SingleResult(this.converter, double.class, null);
195 default:
196 throw new EvaluationException(ast);
197 }
198 }
199
200
201
202
203 private static void logAst(AST ast) {
204 logger.debug("Evaluating: ["+ExpressionRecognizer._tokenNames[ast.getType()]+"] "+ast.getLine()+":"+ast.getColumn()+" "+ast.toString());
205 }
206
207
208
209
210
211
212
213
214 private Result dot(Result res, AST ast, Context context) throws EvaluationException {
215 Result result=evaluate(res, (AST) ast.getFirstChild(), context);
216 String property = ast.getFirstChild().getNextSibling().getText();
217 if (result instanceof SingleResult) {
218 Object value = ((SingleResult) result).getValue();
219 if (value==null) {
220 throw new EvaluationException(ast.getFirstChild().getText()+" is null");
221 }
222
223 Context ctx= value instanceof Context ? (Context) value : new BeanContext(value) {
224 protected String translate(String name) {
225 return Evaluator.this.translate(name);
226 }
227 };
228 Object ret = ctx.get(property);
229 return ret instanceof Result ? (Result) ret : new SingleResult(this.converter, null, ret);
230 }
231
232 Object[] values = ((MultiResult) result).getValues();
233
234 Collection cres=new ArrayList();
235 for (int i=0; i<values.length; i++) {
236 Context ctx = values[i] instanceof Context ? (Context) values[i] : new BeanContext(values[i]) {
237 protected String translate(String name) {
238 return Evaluator.this.translate(name);
239 }
240 };
241 Object ret = ctx.get(property);
242 if (ret instanceof SingleResult) {
243 cres.add(((SingleResult) ret).getValue());
244 } else if (ret instanceof MultiResult) {
245 Object[] rets=((MultiResult) ret).getValues();
246 for (int j=0; j<rets.length; j++) {
247 cres.add(rets[j]);
248 }
249 } else {
250 cres.add(ret);
251 }
252 }
253 return new MultiResult(null, cres, converter);
254 }
255
256
257
258
259
260
261
262
263
264 private Result index(Result res, AST ast, Context context) throws EvaluationException {
265 AST objectNode = (AST) ast.getFirstChild();
266 Result result = evaluate(null, objectNode, context);
267 if (result instanceof SingleResult) {
268 Object obj=((SingleResult) result).getValue();
269 if (obj==null) {
270 throw new EvaluationException("Value "+objectNode.getText()+" is null at "+objectNode.getLine()+":"+objectNode.getColumn());
271 }
272
273 AST indexNode = (AST) objectNode.getNextSibling();
274 Result idr = evaluate(null, indexNode, context);
275 if (idr instanceof SingleResult) {
276 Object idx=((SingleResult) idr).getValue();
277 return new SingleResult(this.converter, null, index(ast, obj, indexNode, idx));
278 }
279
280 Collection values=new ArrayList();
281 Object[] idxa=((MultiResult) idr).getValues();
282 for (int i=0; i<idxa.length; i++) {
283 values.add(index(ast, obj, indexNode, idxa[i]));
284 }
285
286 return new MultiResult(null, values, converter);
287 }
288
289 Object[] objs=((MultiResult) result).getValues();
290
291 AST indexNode = (AST) objectNode.getNextSibling();
292 Collection values=new ArrayList();
293 Result idr = evaluate(null, indexNode, context);
294 if (idr instanceof SingleResult) {
295 Object idx=((SingleResult) idr).getValue();
296 for (int i=0; i<objs.length; i++) {
297 values.add(index(ast, objs[i], indexNode, idx));
298 }
299 return new MultiResult(null, values, converter);
300 }
301
302 Object[] idxa=((MultiResult) idr).getValues();
303 for (int j=0; j<objs.length; j++) {
304 for (int i=0; i<idxa.length; i++) {
305 values.add(index(ast, objs[j], indexNode, idxa[i]));
306 }
307 }
308
309 return new MultiResult(null, values, converter);
310 }
311
312
313
314
315
316
317
318
319 private Object index(AST ast, Object obj, AST indexNode, Object idx) throws EvaluationException {
320 if (idx==null) {
321 throw new EvaluationException("Index "+indexNode.getText()+" is null at "+indexNode.getLine()+":"+indexNode.getColumn());
322 }
323
324 if (obj.getClass().isArray()) {
325 return Array.get(obj, ((Number) converter.convert(idx, Number.class, null)).intValue());
326 }
327
328 if (obj instanceof Collection) {
329 int index=((Number) converter.convert(idx, Number.class, null)).intValue();
330 Iterator it=((Collection) obj).iterator();
331 for (int i=0; it.hasNext(); i++) {
332 Object next = it.next();
333 if (i==index) {
334 return next;
335 }
336 }
337
338 throw new EvaluationException("Index out of bounds: "+index+" at "+ast.getLine()+":"+ast.getColumn());
339 }
340
341 if (obj instanceof Iterator) {
342 int index=((Number) converter.convert(idx, Number.class, null)).intValue();
343 Iterator it=(Iterator) obj;
344 for (int i=0; it.hasNext(); i++) {
345 Object next = it.next();
346 if (i==index) {
347 return next;
348 }
349 }
350
351 throw new EvaluationException("Index out of bounds: "+index+" at "+ast.getLine()+":"+ast.getColumn());
352 }
353
354 if (obj instanceof Enumeration) {
355 int index=((Number) converter.convert(idx, Number.class, null)).intValue();
356 Enumeration enm=(Enumeration) obj;
357 for (int i=0; enm.hasMoreElements(); i++) {
358 Object nextElement = enm.nextElement();
359 if (i==index) {
360 return nextElement;
361 }
362 }
363
364 throw new EvaluationException("Index out of bounds: "+index+" at "+ast.getLine()+":"+ast.getColumn());
365 }
366
367 if (obj instanceof Context) {
368 return ((Context) obj).get(idx.toString());
369 }
370
371 if (obj instanceof Map) {
372 return ((Map) obj).get(idx);
373 }
374
375 throw new EvaluationException("Can't apply index operation to class "+obj.getClass().getName());
376 }
377
378
379
380
381
382
383
384
385
386 private Result invoke(Result res, AST ast, Context context) throws EvaluationException {
387 int paramCount = ast.getFirstChild().getNextSibling().getNumberOfChildren();
388 AST nameNode = (AST) ast.getFirstChild();
389 Object object;
390 String methodName;
391 switch (nameNode.getType()) {
392 case ExpressionRecognizer.DOT:
393 methodName = nameNode.getFirstChild().getNextSibling().getText();
394 Result result = evaluate(res, (AST) nameNode.getFirstChild(), context);
395 if (result instanceof MultiResult) {
396 Collection ret=new ArrayList();
397 Object[] values=((MultiResult) result).getValues();
398 for (int i=0; i<values.length; i++) {
399 ArrayList vCandidates=new ArrayList();
400 Method[] ma=values[i].getClass().getMethods();
401 for (int j=0; j<ma.length; j++) {
402 vCandidates.add(new MethodEntry(values[i], ma[j]));
403 }
404 Result ir = invokeInternal(res, context, paramCount, nameNode, vCandidates, methodName);
405 if (ir instanceof SingleResult) {
406 ret.add(((SingleResult) ir).getValue());
407 } else {
408 Object[] vv=((MultiResult) ir).getValues();
409 for (int k=0; k<vv.length; k++) {
410 ret.add(vv[k]);
411 }
412 }
413 }
414 return new MultiResult(null, ret, converter);
415 }
416 object = ((SingleResult) result).getValue();
417 break;
418 case ExpressionRecognizer.IDENT:
419 object=context;
420 methodName=nameNode.getText();
421 break;
422 default:
423 throw new EvaluationException(nameNode);
424 }
425
426 ArrayList candidates=new ArrayList();
427 if (object==null) {
428 candidates.addAll(methods);
429 } else {
430 Method[] ma=object.getClass().getMethods();
431 for (int i=0; i<ma.length; i++) {
432 candidates.add(new MethodEntry(object, ma[i]));
433 }
434 }
435
436 return invokeInternal(res, context, paramCount, nameNode, candidates, methodName);
437 }
438
439
440
441
442
443
444
445
446
447
448
449
450 private Result invokeInternal(Result res, Context context, int paramCount, AST nameNode, ArrayList methods, String methodName) throws EvaluationException {
451 Iterator it=methods.iterator();
452 while (it.hasNext()) {
453 MethodEntry me=(MethodEntry) it.next();
454 if (!me.name.equals(methodName) || me.method.getParameterTypes().length!=paramCount) {
455 it.remove();
456 }
457 }
458
459 if (methods.isEmpty()) {
460 throw new EvaluationException("No appropriate method '"+methodName+"'");
461 }
462
463 Result[] params=new Result[paramCount];
464 int idx=0;
465 boolean multiResult=false;
466 for (AST paramNode=(AST) nameNode.getNextSibling().getFirstChild(); paramNode!=null; paramNode=(AST) paramNode.getNextSibling(), idx++) {
467 params[idx]=evaluate(res, paramNode, context);
468 if (params[idx] instanceof MultiResult) {
469 multiResult=true;
470 }
471
472 if (params[idx].getType()!=null) {
473 it=methods.iterator();
474 while (it.hasNext()) {
475 MethodEntry me=(MethodEntry) it.next();
476 if (!me.method.getParameterTypes()[idx].isAssignableFrom(params[idx].getType())) {
477 it.remove();
478 }
479 }
480 }
481 }
482
483 it=methods.iterator();
484 Z: while (it.hasNext()) {
485 MethodEntry me=(MethodEntry) it.next();
486 Iterator jt=methods.iterator();
487 while (jt.hasNext()) {
488 switch (((MethodEntry) jt.next()).isMoreSpecific(me)) {
489 case 1:
490 it.remove();
491 break Z;
492 case -1:
493 jt.remove();
494 }
495 }
496 }
497
498
499 if (methods.isEmpty()) {
500 throw new EvaluationException("No appropriate method '"+methodName+"'");
501 }
502
503 if (methods.size()>1) {
504 StringBuffer msg=new StringBuffer("Ambiguous method '"+methodName+"': ");
505 it=methods.iterator();
506 while (it.hasNext()) {
507 msg.append("\n\t");
508 msg.append(((MethodEntry) it.next()).method);
509 }
510
511 throw new EvaluationException(msg.toString());
512 }
513
514 final MethodEntry methodEntry=(MethodEntry) methods.get(0);
515
516 if (multiResult) {
517 Collection ret=new ArrayList();
518 Collection args=new ArrayList();
519 args.add(new Object[params.length]);
520 for (int i=0; i<params.length; i++) {
521 args=setArgs(args, i, params[i], methodEntry.method.getParameterTypes()[i]);
522 }
523 return new MultiResult(methodEntry.method.getReturnType(), ret, converter);
524 }
525
526 Object[] args=new Object[params.length];
527 for (int i=0; i<params.length; i++) {
528 args[i]=converter.convert(((SingleResult) params[i]).getValue(), methodEntry.method.getParameterTypes()[i], null);
529 }
530
531 return new SingleResult(this.converter, methodEntry.method.getReturnType(), methodEntry.invoke(args));
532 }
533
534 private Collection setArgs(Collection args, int idx, Result arg, Class paramType) {
535 if (arg instanceof SingleResult) {
536 Iterator it=args.iterator();
537 while (it.hasNext()) {
538 ((Object[]) it.next())[idx]=converter.convert(((SingleResult) arg).getValue(), paramType, null);
539 }
540 return args;
541 }
542
543 Collection ret=new ArrayList();
544 Object[] values=((MultiResult) arg).getValues();
545 Iterator it=args.iterator();
546 while (it.hasNext()) {
547 Object[] objs = (Object[]) it.next();
548 for (int i=0; i<values.length; i++) {
549 Object[] cobjs=(Object[]) objs.clone();
550 cobjs[idx]=converter.convert(values[i], paramType, null);
551 ret.add(cobjs);
552 }
553 }
554 return ret;
555 }
556
557
558
559
560
561
562 private static void populate(Object object, Collection values) throws EvaluationException {
563 if (object.getClass().isArray()) {
564 for (int i=0, j=Array.getLength(object); i<j; i++) {
565 values.add(Array.get(object, i));
566 }
567 } else if (object instanceof Collection) {
568 values.addAll((Collection) object);
569 } else if (object instanceof Map) {
570 values.addAll(((Map) object).entrySet());
571 } else if (object instanceof Iterator) {
572 while (((Iterator) object).hasNext()) {
573 values.add(((Iterator) object).next());
574 }
575 } else if (object instanceof Enumeration) {
576 while (((Enumeration) object).hasMoreElements()) {
577 values.add(((Enumeration) object).nextElement());
578 }
579 } else {
580 throw new EvaluationException("forEach() is not applicable for "+object.getClass());
581 }
582 }
583
584
585
586
587
588
589
590 private Result typecast(Result res, AST ast, Context context) {
591 ast.print(ExpressionRecognizer._tokenNames, false);
592 throw new UnsupportedOperationException("Not yet implemented");
593 }
594
595
596
597
598
599
600
601 private Result lnot(Result res, AST ast, Context context) {
602 ast.print(ExpressionRecognizer._tokenNames, false);
603 throw new UnsupportedOperationException("Not yet implemented");
604 }
605
606
607
608
609
610
611
612 private Result plus(Result res, AST ast, Context context) {
613 ast.print(ExpressionRecognizer._tokenNames, false);
614 throw new UnsupportedOperationException("Not yet implemented");
615 }
616
617
618
619
620
621
622
623 private Result minus(Result res, AST ast, Context context) {
624 ast.print(ExpressionRecognizer._tokenNames, false);
625 throw new UnsupportedOperationException("Not yet implemented");
626 }
627
628 private String identifier(AST ast) throws EvaluationException {
629 switch (ast.getType()) {
630 case ExpressionTokenTypes.IDENT:
631 return ast.getText();
632 case ExpressionTokenTypes.DOT:
633 return identifier((AST) ast.getFirstChild())+"."+identifier((AST) ast.getFirstChild().getNextSibling());
634 default:
635 throw new EvaluationException("Unexpected node type: "+ExpressionRecognizer._tokenNames[ast.getType()]);
636 }
637 }
638
639
640
641
642
643
644
645 protected String translate(String name) {
646 return name.replace('_', ' ');
647 }
648}