KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > expression > ExpressionVisitor


1 /**************************************************************************************
2  * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
3  * http://aspectwerkz.codehaus.org *
4  * ---------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of the LGPL license *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  **************************************************************************************/

8 package org.codehaus.aspectwerkz.expression;
9
10 import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
11 import org.codehaus.aspectwerkz.expression.ast.ASTAnd;
12 import org.codehaus.aspectwerkz.expression.ast.ASTAttribute;
13 import org.codehaus.aspectwerkz.expression.ast.ASTCall;
14 import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
15 import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
16 import org.codehaus.aspectwerkz.expression.ast.ASTClassPattern;
17 import org.codehaus.aspectwerkz.expression.ast.ASTConstructorPattern;
18 import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
19 import org.codehaus.aspectwerkz.expression.ast.ASTExpression;
20 import org.codehaus.aspectwerkz.expression.ast.ASTFieldPattern;
21 import org.codehaus.aspectwerkz.expression.ast.ASTGet;
22 import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
23 import org.codehaus.aspectwerkz.expression.ast.ASTMethodPattern;
24 import org.codehaus.aspectwerkz.expression.ast.ASTModifier;
25 import org.codehaus.aspectwerkz.expression.ast.ASTNot;
26 import org.codehaus.aspectwerkz.expression.ast.ASTOr;
27 import org.codehaus.aspectwerkz.expression.ast.ASTParameter;
28 import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
29 import org.codehaus.aspectwerkz.expression.ast.ASTRoot;
30 import org.codehaus.aspectwerkz.expression.ast.ASTSet;
31 import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
32 import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
33 import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
34 import org.codehaus.aspectwerkz.expression.ast.ExpressionParserVisitor;
35 import org.codehaus.aspectwerkz.expression.ast.Node;
36 import org.codehaus.aspectwerkz.expression.ast.SimpleNode;
37 import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
38 import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
39 import org.codehaus.aspectwerkz.expression.regexp.TypePattern;
40 import org.codehaus.aspectwerkz.reflect.ClassInfo;
41 import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
42 import org.codehaus.aspectwerkz.reflect.FieldInfo;
43 import org.codehaus.aspectwerkz.reflect.MemberInfo;
44 import org.codehaus.aspectwerkz.reflect.MethodInfo;
45 import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
46 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
47 import org.codehaus.aspectwerkz.reflect.StaticInitializationInfo;
48
49 import java.lang.reflect.Modifier JavaDoc;
50 import java.util.ArrayList JavaDoc;
51 import java.util.Iterator JavaDoc;
52 import java.util.List JavaDoc;
53
54 import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
55 import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
56 import org.codehaus.aspectwerkz.expression.ast.ASTTarget;
57 import org.codehaus.aspectwerkz.expression.ast.ASTThis;
58 import org.codehaus.aspectwerkz.util.Util;
59
60 /**
61  * The expression visitor.
62  * If a runtime residual is required (target => instance of check sometimes), Undeterministic matching is used.
63  *
64  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
65  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
66  * @author Michael Nascimento
67  * @author <a HREF="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
68  */

69 public class ExpressionVisitor implements ExpressionParserVisitor {
70
71     protected Node m_root;
72     protected String JavaDoc m_expression;
73     protected String JavaDoc m_namespace;
74
75     /**
76      * The expressionInfo this visitor is built on
77      */

78     protected ExpressionInfo m_expressionInfo;
79
80     /**
81      * Creates a new expression.
82      *
83      * @param expressionInfo the expressionInfo this visitor is built on for expression with signature
84      * @param expression the expression as a string
85      * @param namespace the namespace
86      * @param root the AST root
87      */

88     public ExpressionVisitor(final ExpressionInfo expressionInfo,
89                              final String JavaDoc expression,
90                              final String JavaDoc namespace,
91                              final Node root) {
92         m_expressionInfo = expressionInfo;
93         m_expression = expression;
94         m_namespace = namespace;
95         m_root = root;
96     }
97
98     /**
99      * Matches the expression context.
100      * If undetermined, assume true.
101      * Do not use for poincut reference - see matchUndeterministic
102      *
103      * @param context
104      * @return
105      */

106     public boolean match(final ExpressionContext context) {
107         Boolean JavaDoc match = ((Boolean JavaDoc) visit(m_root, context));
108         // undeterministic is assumed to be "true" at this stage
109
// since it won't be composed anymore with a NOT (unless
110
// thru pointcut reference ie a new visitor)
111
return (match != null) ? match.booleanValue() : true;
112     }
113
114     protected Boolean JavaDoc matchUndeterministic(final ExpressionContext context) {
115         Boolean JavaDoc match = ((Boolean JavaDoc) visit(m_root, context));
116         return match;
117     }
118
119     // ============ Boot strap =============
120
public Object JavaDoc visit(Node node, Object JavaDoc data) {
121         return node.jjtGetChild(0).jjtAccept(this, data);
122     }
123
124     public Object JavaDoc visit(SimpleNode node, Object JavaDoc data) {
125         return node.jjtGetChild(0).jjtAccept(this, data);
126     }
127
128     public Object JavaDoc visit(ASTRoot node, Object JavaDoc data) {
129         return node.jjtGetChild(0).jjtAccept(this, data);
130     }
131
132     public Object JavaDoc visit(ASTExpression node, Object JavaDoc data) {
133         return node.jjtGetChild(0).jjtAccept(this, data);
134     }
135
136     // ============ Logical operators =============
137
public Object JavaDoc visit(ASTOr node, Object JavaDoc data) {
138         // the AND and OR can have more than 2 nodes [see jjt grammar]
139
Boolean JavaDoc matchL = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
140         Boolean JavaDoc matchR = (Boolean JavaDoc) node.jjtGetChild(1).jjtAccept(this, data);
141         Boolean JavaDoc intermediate = Undeterministic.or(matchL, matchR);
142         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
143             Boolean JavaDoc matchNext = (Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, data);
144             intermediate = Undeterministic.or(intermediate, matchNext);
145         }
146         return intermediate;
147     }
148
149     public Object JavaDoc visit(ASTAnd node, Object JavaDoc data) {
150         // the AND and OR can have more than 2 nodes [see jjt grammar]
151
Boolean JavaDoc matchL = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
152         Boolean JavaDoc matchR = (Boolean JavaDoc) node.jjtGetChild(1).jjtAccept(this, data);
153         Boolean JavaDoc intermediate = Undeterministic.and(matchL, matchR);
154         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
155             Boolean JavaDoc matchNext = (Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, data);
156             intermediate = Undeterministic.and(intermediate, matchNext);
157         }
158         return intermediate;
159     }
160
161     public Object JavaDoc visit(ASTNot node, Object JavaDoc data) {
162         Boolean JavaDoc match = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
163         return Undeterministic.not(match);
164     }
165
166     // ============ Pointcut types =============
167
public Object JavaDoc visit(ASTPointcutReference node, Object JavaDoc data) {
168         ExpressionContext context = (ExpressionContext) data;
169         ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
170         ExpressionVisitor expression = namespace.getExpression(node.getName());
171         return expression.matchUndeterministic(context);
172     }
173
174     public Object JavaDoc visit(ASTExecution node, Object JavaDoc data) {
175         ExpressionContext context = (ExpressionContext) data;
176         if (context.hasExecutionPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
177             return visitAnnotatedNode(node, context.getReflectionInfo());
178         } else {
179             return Boolean.FALSE;
180         }
181     }
182
183     public Object JavaDoc visit(ASTCall node, Object JavaDoc data) {
184         ExpressionContext context = (ExpressionContext) data;
185         if (context.hasCallPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
186             return visitAnnotatedNode(node, context.getReflectionInfo());
187         } else {
188             return Boolean.FALSE;
189         }
190     }
191
192     public Object JavaDoc visit(ASTSet node, Object JavaDoc data) {
193         ExpressionContext context = (ExpressionContext) data;
194         if (context.hasSetPointcut() && context.hasFieldInfo()) {
195             return visitAnnotatedNode(node, context.getReflectionInfo());
196         } else {
197             return Boolean.FALSE;
198         }
199     }
200
201     public Object JavaDoc visit(ASTGet node, Object JavaDoc data) {
202         ExpressionContext context = (ExpressionContext) data;
203         if (context.hasGetPointcut() && context.hasFieldInfo()) {
204             return visitAnnotatedNode(node, context.getReflectionInfo());
205         } else {
206             return Boolean.FALSE;
207         }
208     }
209
210     public Object JavaDoc visit(ASTHandler node, Object JavaDoc data) {
211         ExpressionContext context = (ExpressionContext) data;
212         if (context.hasHandlerPointcut() && context.hasClassInfo()) {
213             return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
214         } else {
215             return Boolean.FALSE;
216         }
217     }
218
219     public Object JavaDoc visit(ASTStaticInitialization node, Object JavaDoc data) {
220         ExpressionContext context = (ExpressionContext) data;
221         
222         if (context.hasStaticInitializationPointcut() && context.hasReflectionInfo()) {
223             ReflectionInfo reflectInfo = context.getReflectionInfo();
224             
225             if(reflectInfo instanceof StaticInitializationInfo) {
226                 ClassInfo declaringClassInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
227
228                 // In an annotated subtree, only the last child node may represent the pattern
229
Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
230                 if (!(patternNode instanceof ASTAttribute)) {
231                     Boolean JavaDoc matchPattern = (Boolean JavaDoc) patternNode.jjtAccept(this, reflectInfo);
232                     if (Boolean.FALSE.equals(matchPattern)) {
233                         return Boolean.FALSE;
234                     }
235                 }
236
237                 // match on annotation if no pattern node or matched already
238
boolean matchedAnnotations = visitAttributes(node, declaringClassInfo);
239                 if (!matchedAnnotations) {
240                     return Boolean.FALSE;
241                 } else {
242                     return Boolean.TRUE;
243                 }
244             } else {
245                 return Boolean.FALSE;
246             }
247         } else {
248             return Boolean.FALSE;
249         }
250     }
251
252     public Object JavaDoc visit(ASTWithin node, Object JavaDoc data) {
253         ExpressionContext context = (ExpressionContext) data;
254         if (context.hasWithinReflectionInfo()) {
255             ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
256             ReflectionInfo withinInfo = null;
257             
258             if(reflectInfo instanceof MemberInfo) {
259                 withinInfo = ((MemberInfo) reflectInfo).getDeclaringType();
260             } else if(reflectInfo instanceof ClassInfo) {
261                 withinInfo = reflectInfo;
262             } else {
263                 return Boolean.FALSE;
264             }
265             return visitAnnotatedNode(
266                     node,
267                     withinInfo);
268         } else {
269             return null;
270         }
271     }
272
273     public Object JavaDoc visit(ASTWithinCode node, Object JavaDoc data) {
274         ExpressionContext context = (ExpressionContext) data;
275         
276         if(!context.hasWithinReflectionInfo()) {
277             return null;
278         }
279         
280         ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
281         
282         if(node.isStaticInitializer()) {
283             if(reflectInfo instanceof StaticInitializationInfo) {
284                 // Ignore the ASTStaticInitialization node in this context
285
SimpleNode staticClinitNode = (SimpleNode) node.jjtGetChild(0);
286                 ClassInfo declaringClassInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
287                 
288                 boolean matchedAnnotations = visitAttributes(staticClinitNode, declaringClassInfo);
289                 if(!matchedAnnotations) {
290                     return Boolean.FALSE;
291                 }
292                 
293                 // In an annotated subtree, the last child node represents the pattern
294
Node lastNode = staticClinitNode.jjtGetChild(staticClinitNode.jjtGetNumChildren() - 1);
295                 if(lastNode instanceof ASTAttribute) {
296                     return Boolean.TRUE;
297                 } else {
298                     return lastNode.jjtAccept(this, reflectInfo);
299                 }
300             } else {
301                 return Boolean.FALSE;
302             }
303         } else {
304             return visitAnnotatedNode(
305                     node,
306                     reflectInfo
307                     );
308         }
309     }
310
311
312     public Object JavaDoc visit(ASTHasMethod node, Object JavaDoc data) {
313         ExpressionContext context = (ExpressionContext) data;
314
315         // we are matching on the CALLER info
316
// for execution() pointcut, this is equals to CALLEE info
317
ReflectionInfo info = context.getWithinReflectionInfo();
318         ClassInfo classInfo = info instanceof MemberInfo
319                 ? ((MemberInfo) info).getDeclaringType()
320                 : (ClassInfo) info;
321         
322         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
323         boolean hasPatternNode = !(patternNode instanceof ASTAttribute);
324
325         MethodInfo[] methodInfos = classInfo.getMethods();
326         for (int i = 0; i < methodInfos.length; i++) {
327             if (hasPatternNode) {
328                 if(Boolean.FALSE.equals(patternNode.jjtAccept(this, methodInfos[i]))) {
329                     continue;
330                 }
331             }
332
333             boolean matchAnnotations = visitAttributes(node, methodInfos[i]);
334             if (matchAnnotations) {
335                 return Boolean.TRUE;
336             }
337         }
338
339         ConstructorInfo[] constructorInfos = classInfo.getConstructors();
340         for (int i = 0; i < constructorInfos.length; i++) {
341             if (hasPatternNode) {
342                 if(Boolean.FALSE.equals(patternNode.jjtAccept(this, constructorInfos[i]))) {
343                     continue;
344                 }
345             }
346
347             boolean matchAnnotations = visitAttributes(node, constructorInfos[i]);
348             if (matchAnnotations) {
349                 return Boolean.TRUE;
350             }
351         }
352
353         return Boolean.FALSE;
354     }
355
356     public Object JavaDoc visit(ASTHasField node, Object JavaDoc data) {
357         ExpressionContext context = (ExpressionContext) data;
358
359         // we are matching on the CALLER info
360
// for execution() pointcut, this is equals to CALLEE info
361
ReflectionInfo info = context.getWithinReflectionInfo();
362         ClassInfo classInfo = (info instanceof MemberInfo) ?
363                               ((MemberInfo) info).getDeclaringType() : (ClassInfo) info;
364
365         Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
366         boolean hasPatternNode = !(patternNode instanceof ASTAttribute);
367
368         FieldInfo[] fieldInfos = classInfo.getFields();
369         for (int i = 0; i < fieldInfos.length; i++) {
370             if (hasPatternNode) {
371                 if (Boolean.FALSE.equals(patternNode.jjtAccept(this, fieldInfos[i]))) {
372                     continue;
373                 }
374             }
375
376             boolean matchAnnotations = visitAttributes(node, fieldInfos[i]);
377             if (matchAnnotations) {
378                 return Boolean.TRUE;
379             }
380         }
381
382         return Boolean.FALSE;
383     }
384
385     public Object JavaDoc visit(ASTTarget node, Object JavaDoc data) {
386         ExpressionContext context = (ExpressionContext) data;
387         ReflectionInfo info = context.getReflectionInfo();
388
389 // //TODO - seems to be the case for AJ - not intuitive
390
// if (info instanceof ConstructorInfo) {
391
// // target(..) does not match for constructors
392
// return Boolean.FALSE;
393
// }
394
ClassInfo declaringType = null;
395         if (info instanceof MemberInfo) {
396             // if method/field is static, target(..) is evaluated to false
397
if (Modifier.isStatic(((MemberInfo) info).getModifiers())) {
398                 return Boolean.FALSE;
399             }
400
401             declaringType = ((MemberInfo) info).getDeclaringType();
402         } else if (info instanceof ClassInfo) {
403             declaringType = (ClassInfo) info;
404         } else {
405             return Boolean.FALSE;
406         }
407
408         String JavaDoc boundedTypeName = node.getBoundedType(m_expressionInfo);
409         // check if the context we match is an interface call, while the bounded type of target(..) is not an
410
// interface. In such a case we will need a runtime check
411
if (declaringType.isInterface()) {
412             // if we are a instanceof (subinterface) of the bounded type, then we don't need a runtime check
413
if (ClassInfoHelper.instanceOf(declaringType, boundedTypeName)) {
414                 return Boolean.TRUE;
415             } else {
416                 //System.out.println("*** RT check for " + boundedTypeName + " when I am " + declaringType.getName());
417
// a runtime check with instance of will be required
418
return null;
419             }
420         } else {
421             return Util.booleanValueOf(ClassInfoHelper.instanceOf(declaringType, boundedTypeName));
422         }
423     }
424
425     public Object JavaDoc visit(ASTThis node, Object JavaDoc data) {
426         ExpressionContext context = (ExpressionContext) data;
427         // for execution pointcut, this(..) is used to match the callee info
428
// and we are assuming here that withinInfo is properly set to reflectionInfo
429
if (context.hasWithinReflectionInfo()) {
430             ReflectionInfo withinInfo = context.getWithinReflectionInfo();
431             if (withinInfo instanceof MemberInfo) {
432                 // if method is static (callee for execution or caller for call/get/set), this(..) is evaluated to false
433
if (Modifier.isStatic(((MemberInfo) withinInfo).getModifiers())) {
434                     return Boolean.FALSE;
435                 }
436                 return Util.booleanValueOf(
437                         ClassInfoHelper.instanceOf(
438                                 ((MemberInfo) withinInfo).getDeclaringType(),
439                                 node.getBoundedType(m_expressionInfo)
440                         )
441                 );
442             } else if (withinInfo instanceof ClassInfo) {
443                 return Util.booleanValueOf(
444                         ClassInfoHelper.instanceOf((ClassInfo) withinInfo, node.getBoundedType(m_expressionInfo))
445                 );
446             }
447         }
448         return Boolean.FALSE;
449     }
450
451     public Object JavaDoc visit(ASTCflow node, Object JavaDoc data) {
452         return null;
453     }
454
455     public Object JavaDoc visit(ASTCflowBelow node, Object JavaDoc data) {
456         return null;
457     }
458
459     // ============ Patterns =============
460
public Object JavaDoc visit(ASTClassPattern node, Object JavaDoc data) {
461         if (data instanceof ClassInfo) {
462             ClassInfo classInfo = (ClassInfo) data;
463             TypePattern typePattern = node.getTypePattern();
464
465             if (typePattern.matchType(classInfo)
466                 && visitModifiers(node, classInfo)) {
467                 return Boolean.TRUE;
468             } else {
469                 return Boolean.FALSE;
470             }
471         } else if (data instanceof StaticInitializationInfo) {
472             ClassInfo classInfo = ((StaticInitializationInfo) data).getDeclaringType();
473             
474             if(node.getTypePattern().matchType(classInfo)) {
475                 return Boolean.TRUE;
476             } else {
477                 return Boolean.FALSE;
478             }
479             
480 // return new Boolean(node.getTypePattern().matchType(classInfo));
481
}
482         
483         return Boolean.FALSE;
484     }
485
486     public Object JavaDoc visit(ASTMethodPattern node, Object JavaDoc data) {
487         if (data instanceof MethodInfo) {
488             MethodInfo methodInfo = (MethodInfo) data;
489             if (node.getMethodNamePattern().matches(methodInfo.getName())
490                 && node.getDeclaringTypePattern().matchType(methodInfo.getDeclaringType())
491                 && node.getReturnTypePattern().matchType(methodInfo.getReturnType())
492                 && visitModifiers(node, methodInfo)
493                 && visitParameters(node, methodInfo.getParameterTypes())) {
494                 return Boolean.TRUE;
495             }
496         }
497
498         return Boolean.FALSE;
499     }
500
501     public Object JavaDoc visit(ASTConstructorPattern node, Object JavaDoc data) {
502         if (data instanceof ConstructorInfo) {
503             ConstructorInfo constructorMetaData = (ConstructorInfo) data;
504             if (node.getDeclaringTypePattern().matchType(constructorMetaData.getDeclaringType())
505                 && visitModifiers(node, constructorMetaData)
506                 && visitParameters(node, constructorMetaData.getParameterTypes())) {
507                 return Boolean.TRUE;
508             }
509         }
510         return Boolean.FALSE;
511     }
512
513     public Object JavaDoc visit(ASTFieldPattern node, Object JavaDoc data) {
514         if (data instanceof FieldInfo) {
515             FieldInfo fieldInfo = (FieldInfo) data;
516             if (node.getFieldNamePattern().matches(fieldInfo.getName())
517                 && node.getDeclaringTypePattern().matchType(fieldInfo.getDeclaringType())
518                 && node.getFieldTypePattern().matchType(fieldInfo.getType())
519                 && visitModifiers(node, fieldInfo)) {
520                 return Boolean.TRUE;
521             }
522         }
523         return Boolean.FALSE;
524     }
525
526     public Object JavaDoc visit(ASTParameter node, Object JavaDoc data) {
527         ClassInfo parameterType = (ClassInfo) data;
528         if (node.getDeclaringClassPattern().matchType(parameterType)) {
529             return Boolean.TRUE;
530         } else {
531             return Boolean.FALSE;
532         }
533     }
534
535     public Object JavaDoc visit(ASTArgs node, Object JavaDoc data) {
536         ExpressionContext ctx = (ExpressionContext) data;
537         if (node.jjtGetNumChildren() <= 0) {
538             // args(EMPTY)
539
return (getParametersCount(ctx) == 0) ? Boolean.TRUE : Boolean.FALSE;
540         } else {
541             // check for ".." as first node
542
int expressionParameterCount = node.jjtGetNumChildren();// the number of node minus eager one.
543
boolean isFirstArgEager = ((ASTArgParameter) node.jjtGetChild(0)).getTypePattern().isEagerWildCard();
544             boolean isLastArgEager = ((ASTArgParameter) node.jjtGetChild(node.jjtGetNumChildren() - 1))
545                     .getTypePattern().isEagerWildCard();
546             // args(..)
547
if (isFirstArgEager && expressionParameterCount == 1) {
548                 return Boolean.TRUE;
549             }
550             int contextParametersCount = getParametersCount(ctx);
551             if (isFirstArgEager && isLastArgEager) {
552                 expressionParameterCount -= 2;
553                 if (expressionParameterCount == 0) {
554                     // expression is "args(.., ..)"
555
return Boolean.TRUE;
556                 }
557                 // we need to find a starting position - args(..,int, bar, ..)
558
// foo(int) //int is ok
559
// foo(bar,int,bar) //int is ok
560
// foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
561
int matchCount = 0;
562                 int ictx = 0;
563                 for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
564                     if (ictx >= contextParametersCount) {
565                         // too many args in args()
566
matchCount = -1;
567                         break;
568                     }
569                     ctx.setCurrentTargetArgsIndex(ictx);
570                     // do we have an eager wildcard in the middle ?
571
boolean isEager = ((ASTArgParameter) node.jjtGetChild(iexp + 1)).getTypePattern().isEagerWildCard();
572                     if (isEager) {
573                         // TODO - ignore for now, but not really supported - eager in the middle will match one
574
}
575                     if (Boolean.TRUE.equals((Boolean JavaDoc) node.jjtGetChild(iexp + 1).jjtAccept(this, ctx))) {
576                         matchCount += 1;
577                         ictx++;
578                     } else {
579                         // assume matched by starting ".." and rewind expression index
580
matchCount = 0;
581                         ictx++;
582                         iexp = -1;
583                     }
584                 }
585                 if (matchCount == expressionParameterCount) {
586                     return Boolean.TRUE;
587                 } else {
588                     return Boolean.FALSE;
589                 }
590             } else if (isFirstArgEager) {
591                 expressionParameterCount--;
592                 if (contextParametersCount >= expressionParameterCount) {
593                     // do a match from last to first, break when args() nodes are exhausted
594
for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
595                         ctx.setCurrentTargetArgsIndex(contextParametersCount - 1 - i);
596                         if (Boolean.TRUE.equals(
597                                 (Boolean JavaDoc) node.jjtGetChild(expressionParameterCount - i).jjtAccept(
598                                         this,
599                                         ctx
600                                 )
601                         )) {
602                             ;//go on with "next" arg
603
} else {
604                             return Boolean.FALSE;
605                         }
606                     }
607                     return Boolean.TRUE;
608                 } else {
609                     //args() as more args than context we try to match
610
return Boolean.FALSE;
611                 }
612             } else if (isLastArgEager) {
613                 expressionParameterCount--;
614                 if (contextParametersCount >= expressionParameterCount) {
615                     // do a match from first to last, break when args() nodes are exhausted
616
for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
617                         ctx.setCurrentTargetArgsIndex(i);
618                         if (Boolean.TRUE.equals((Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, ctx))) {
619                             ;//go on with next arg
620
} else {
621                             return Boolean.FALSE;
622                         }
623                     }
624                     return Boolean.TRUE;
625                 } else {
626                     return Boolean.FALSE;
627                 }
628             } else {
629                 // no eager wildcard in args()
630
// check that args length are equals
631
if (expressionParameterCount == contextParametersCount) {
632                     for (int i = 0; i < node.jjtGetNumChildren(); i++) {
633                         ctx.setCurrentTargetArgsIndex(i);
634                         if (Boolean.TRUE.equals((Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, ctx))) {
635                             ;//go on with next arg
636
} else {
637                             return Boolean.FALSE;
638                         }
639                     }
640                     return Boolean.TRUE;
641                 } else {
642                     return Boolean.FALSE;
643      &nb