View Javadoc

1   /*
2    $Id: Verifier.java,v 1.48 2005/11/13 16:42:11 blackdrag Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package org.codehaus.groovy.classgen;
47  
48  import groovy.lang.Closure;
49  import groovy.lang.GroovyObject;
50  import groovy.lang.MetaClass;
51  
52  import java.lang.reflect.Modifier;
53  import java.util.ArrayList;
54  import java.util.Iterator;
55  import java.util.List;
56  
57  import org.codehaus.groovy.ast.ClassHelper;
58  import org.codehaus.groovy.ast.ClassNode;
59  import org.codehaus.groovy.ast.CodeVisitorSupport;
60  import org.codehaus.groovy.ast.ConstructorNode;
61  import org.codehaus.groovy.ast.FieldNode;
62  import org.codehaus.groovy.ast.GroovyClassVisitor;
63  import org.codehaus.groovy.ast.InnerClassNode;
64  import org.codehaus.groovy.ast.MethodNode;
65  import org.codehaus.groovy.ast.Parameter;
66  import org.codehaus.groovy.ast.PropertyNode;
67  import org.codehaus.groovy.ast.expr.ArgumentListExpression;
68  import org.codehaus.groovy.ast.expr.BinaryExpression;
69  import org.codehaus.groovy.ast.expr.BooleanExpression;
70  import org.codehaus.groovy.ast.expr.ClosureExpression;
71  import org.codehaus.groovy.ast.expr.ConstantExpression;
72  import org.codehaus.groovy.ast.expr.Expression;
73  import org.codehaus.groovy.ast.expr.FieldExpression;
74  import org.codehaus.groovy.ast.expr.MethodCallExpression;
75  import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
76  import org.codehaus.groovy.ast.expr.VariableExpression;
77  import org.codehaus.groovy.ast.stmt.BlockStatement;
78  import org.codehaus.groovy.ast.stmt.EmptyStatement;
79  import org.codehaus.groovy.ast.stmt.ExpressionStatement;
80  import org.codehaus.groovy.ast.stmt.IfStatement;
81  import org.codehaus.groovy.ast.stmt.ReturnStatement;
82  import org.codehaus.groovy.ast.stmt.Statement;
83  import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
84  import org.codehaus.groovy.syntax.Types;
85  import org.codehaus.groovy.syntax.Token;
86  import org.codehaus.groovy.syntax.RuntimeParserException;
87  import org.objectweb.asm.Opcodes;
88  
89  /***
90   * Verifies the AST node and adds any defaulted AST code before
91   * bytecode generation occurs.
92   * 
93   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
94   * @version $Revision: 1.48 $
95   */
96  public class Verifier implements GroovyClassVisitor, Opcodes {
97  
98      public static final String __TIMESTAMP = "__timeStamp";
99  	private ClassNode classNode;
100     private MethodNode methodNode;
101 
102     public ClassNode getClassNode() {
103         return classNode;
104     }
105 
106     public MethodNode getMethodNode() {
107         return methodNode;
108     }
109 
110     /***
111      * add code to implement GroovyObject
112      * @param node
113      */
114     public void visitClass(ClassNode node) {
115         this.classNode = node;
116                 
117         if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
118             //interfaces have no construcotrs, but this code expects one, 
119             //so creta a dummy and don't add it to the class node
120             ConstructorNode dummy = new ConstructorNode(0,null);
121             addFieldInitialization(node, dummy);
122             node.visitContents(this);
123             return;
124         }
125         
126         addDefaultParameterMethods(node);
127 
128         if (!node.isDerivedFromGroovyObject()) {
129             node.addInterface(ClassHelper.make(GroovyObject.class));
130 
131             // lets add a new field for the metaclass
132             StaticMethodCallExpression initMetaClassCall =
133                 new StaticMethodCallExpression(
134                     ClassHelper.make(ScriptBytecodeAdapter.class),
135                     "getMetaClass",
136                     VariableExpression.THIS_EXPRESSION);
137 
138             PropertyNode metaClassProperty =
139                 node.addProperty("metaClass", ACC_PUBLIC, ClassHelper.make(MetaClass.class), initMetaClassCall, null, null);
140             metaClassProperty.setSynthetic(true);
141             FieldNode metaClassField = metaClassProperty.getField();
142             metaClassField.setModifiers(metaClassField.getModifiers() | ACC_TRANSIENT);
143 
144             FieldExpression metaClassVar = new FieldExpression(metaClassField);
145             IfStatement initMetaClassField =
146                 new IfStatement(
147                     new BooleanExpression(
148                         new BinaryExpression(metaClassVar, Token.newSymbol( Types.COMPARE_EQUAL, -1, -1), ConstantExpression.NULL)),
149                     new ExpressionStatement(new BinaryExpression(metaClassVar, Token.newSymbol( Types.EQUAL, -1, -1), initMetaClassCall)),
150                     EmptyStatement.INSTANCE);
151 
152             node.addSyntheticMethod(
153                 "getMetaClass",
154                 ACC_PUBLIC,
155                 ClassHelper.make(MetaClass.class),
156                 Parameter.EMPTY_ARRAY,
157                 new BlockStatement(new Statement[] { initMetaClassField, new ReturnStatement(metaClassVar)})
158             );
159 
160             // @todo we should check if the base class implements the invokeMethod method
161 
162             // lets add the invokeMethod implementation
163             ClassNode superClass = node.getSuperClass();
164             boolean addDelegateObject =
165                 (node instanceof InnerClassNode && superClass.equals(Closure.class.getName()))
166                     || superClass.equals(ClassHelper.GSTRING_TYPE);
167 
168             // don't do anything as the base class implements the invokeMethod
169             if (!addDelegateObject) {
170                 node.addSyntheticMethod(
171                     "invokeMethod",
172                     ACC_PUBLIC,
173                     ClassHelper.OBJECT_TYPE,
174                     new Parameter[] {
175                         new Parameter(ClassHelper.STRING_TYPE, "method"),
176                         new Parameter(ClassHelper.OBJECT_TYPE, "arguments")},
177                     new BlockStatement(
178                         new Statement[] {
179                             initMetaClassField,
180                             new ReturnStatement(
181                                 new MethodCallExpression(
182                                     metaClassVar,
183                                     "invokeMethod",
184                                     new ArgumentListExpression(
185                                         new Expression[] {
186                                             VariableExpression.THIS_EXPRESSION,
187                                             new VariableExpression("method"),
188                                             new VariableExpression("arguments")})))
189                 }));
190 
191                 if (!node.isScript()) {
192                     node.addSyntheticMethod(
193                         "getProperty",
194                         ACC_PUBLIC,
195                         ClassHelper.OBJECT_TYPE,
196                         new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "property")},
197                         new BlockStatement(
198                             new Statement[] {
199                                 initMetaClassField,
200                                 new ReturnStatement(
201                                     new MethodCallExpression(
202                                         metaClassVar,
203                                         "getProperty",
204                                         new ArgumentListExpression(
205                                             new Expression[] {
206                                                 VariableExpression.THIS_EXPRESSION,
207                                                 new VariableExpression("property")})))
208                     }));
209 
210                     node.addSyntheticMethod(
211                         "setProperty",
212                         ACC_PUBLIC,
213                         ClassHelper.VOID_TYPE,
214                         new Parameter[] {
215                             new Parameter(ClassHelper.STRING_TYPE, "property"),
216                             new Parameter(ClassHelper.OBJECT_TYPE, "value")},
217                         new BlockStatement(
218                             new Statement[] {
219                                 initMetaClassField,
220                                 new ExpressionStatement(
221                                     new MethodCallExpression(
222                                         metaClassVar,
223                                         "setProperty",
224                                         new ArgumentListExpression(
225                                             new Expression[] {
226                                                 VariableExpression.THIS_EXPRESSION,
227                                                 new VariableExpression("property"),
228                                                 new VariableExpression("value")})))
229                     }));
230                 }
231             }
232         }
233 
234         if (node.getDeclaredConstructors().isEmpty()) {
235             ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, null);
236             constructor.setSynthetic(true);
237             node.addConstructor(constructor);
238         }
239         
240         if (!(node instanceof InnerClassNode)) {// add a static timestamp field to the class
241             FieldNode timeTagField = new FieldNode(
242                     Verifier.__TIMESTAMP,
243                     Modifier.PUBLIC | Modifier.STATIC,
244                     ClassHelper.Long_TYPE,
245                     //"",
246                     node,
247                     new ConstantExpression(new Long(System.currentTimeMillis())));
248             // alternatively , FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
249             timeTagField.setSynthetic(true);
250             node.addField(timeTagField);
251         }
252 
253         addFieldInitialization(node);
254 
255         node.visitContents(this);
256     }
257     public void visitConstructor(ConstructorNode node) {
258         CodeVisitorSupport checkSuper = new CodeVisitorSupport() {
259             boolean firstMethodCall = true;
260             String type=null;
261             public void visitMethodCallExpression(MethodCallExpression call) {
262                 if (!firstMethodCall) return;
263                 firstMethodCall = false;
264                 String name = call.getMethod();
265                 if (!name.equals("super") && !name.equals("this")) return;
266                 type=name;
267                 call.getArguments().visit(this);
268                 type=null;
269             }
270             public void visitVariableExpression(VariableExpression expression) {
271                 if (type==null) return;
272                 String name = expression.getName();
273                 if (!name.equals("this") && !name.equals("super")) return;
274                 throw new RuntimeParserException("cannot reference "+name+" inside of "+type+"(....) before supertype constructor has been called",expression);
275             }            
276         };
277         Statement s = node.getCode();
278         //todo why can a statement can be null?
279         if (s == null) return;
280         s.visit(checkSuper);
281     }
282 
283     public void visitMethod(MethodNode node) {
284         this.methodNode = node;
285         Statement statement = node.getCode();
286         if (!node.isVoidMethod()) {
287             if (statement instanceof ExpressionStatement) {
288                 ExpressionStatement expStmt = (ExpressionStatement) statement;
289                 node.setCode(new ReturnStatement(expStmt.getExpression()));
290             }
291             else if (statement instanceof BlockStatement) {
292                 BlockStatement block = (BlockStatement) statement;
293 
294                 // lets copy the list so we create a new block
295                 List list = new ArrayList(block.getStatements());
296                 if (!list.isEmpty()) {
297                     int idx = list.size() - 1;
298                     Statement last = (Statement) list.get(idx);
299                     if (last instanceof ExpressionStatement) {
300                         ExpressionStatement expStmt = (ExpressionStatement) last;
301                         list.set(idx, new ReturnStatement(expStmt.getExpression()));
302                     }
303                     else if (!(last instanceof ReturnStatement)) {
304                         list.add(new ReturnStatement(ConstantExpression.NULL));
305                     }
306                 }
307                 else {
308                     list.add(new ReturnStatement(ConstantExpression.NULL));
309                 }
310 
311                 node.setCode(new BlockStatement(filterStatements(list)));
312             }
313         }
314         else if (!node.isAbstract()) {
315         	BlockStatement newBlock = new BlockStatement();
316             if (statement instanceof BlockStatement) {
317                 newBlock.addStatements(filterStatements(((BlockStatement)statement).getStatements()));
318             }
319             else {
320                 newBlock.addStatement(filterStatement(statement));
321             }
322             newBlock.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
323             node.setCode(newBlock);
324         }
325         if (node.getName().equals("main") && node.isStatic()) {
326             Parameter[] params = node.getParameters();
327             if (params.length == 1) {
328                 Parameter param = params[0];
329                 if (param.getType() == null || param.getType()==ClassHelper.OBJECT_TYPE) {
330                     param.setType(ClassHelper.STRING_TYPE.makeArray());
331                 }
332             }
333         }
334         statement = node.getCode();
335         if (statement!=null) statement.visit(new VerifierCodeVisitor(this));
336     }
337 
338     public void visitField(FieldNode node) {
339     }
340 
341     public void visitProperty(PropertyNode node) {
342         String name = node.getName();
343         FieldNode field = node.getField();
344 
345         String getterName = "get" + capitalize(name);
346         String setterName = "set" + capitalize(name);
347 
348         Statement getterBlock = node.getGetterBlock();
349         if (getterBlock == null) {
350             if (!node.isPrivate() && classNode.getGetterMethod(getterName) == null) {
351                 getterBlock = createGetterBlock(node, field);
352             }
353         }
354         Statement setterBlock = node.getSetterBlock();
355         if (setterBlock == null) {
356             if (!node.isPrivate() && classNode.getSetterMethod(setterName) == null) {
357                 setterBlock = createSetterBlock(node, field);
358             }
359         }
360 
361         if (getterBlock != null) {
362             MethodNode getter =
363                 new MethodNode(getterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, getterBlock);
364             getter.setSynthetic(true);
365             classNode.addMethod(getter);
366             visitMethod(getter);
367 
368             if (ClassHelper.boolean_TYPE==node.getType() || ClassHelper.Boolean_TYPE==node.getType()) {
369                 String secondGetterName = "is" + capitalize(name);
370                 MethodNode secondGetter =
371                     new MethodNode(secondGetterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, getterBlock);
372                 secondGetter.setSynthetic(true);
373                 classNode.addMethod(secondGetter);
374                 visitMethod(secondGetter);
375             }
376         }
377         if (setterBlock != null) {
378             Parameter[] setterParameterTypes = { new Parameter(node.getType(), "value")};
379             MethodNode setter =
380                 new MethodNode(setterName, node.getModifiers(), ClassHelper.VOID_TYPE, setterParameterTypes, setterBlock);
381             setter.setSynthetic(true);
382             classNode.addMethod(setter);
383             visitMethod(setter);
384         }
385     }
386 
387     // Implementation methods
388     //-------------------------------------------------------------------------
389     
390     /***
391      * Creates a new helper method for each combination of default parameter expressions 
392      */
393     protected void addDefaultParameterMethods(ClassNode node) {
394         List methods = new ArrayList(node.getMethods());
395         for (Iterator iter = methods.iterator(); iter.hasNext();) {
396             MethodNode method = (MethodNode) iter.next();
397             if (method.hasDefaultValue()) {
398                 Parameter[] parameters = method.getParameters();
399                 int counter = 0;
400                 ArrayList paramValues = new ArrayList();
401                 int size = parameters.length;
402                 for (int i = size - 1; i >= 0; i--) {
403                     Parameter parameter = parameters[i];
404                     if (parameter != null && parameter.hasInitialExpression()) {
405                         paramValues.add(new Integer(i));
406                         paramValues.add(parameter.getInitialExpression());
407                         counter++;
408                     }
409                 }
410 
411                 for (int j = 1; j <= counter; j++) {
412                     Parameter[] newParams =  new Parameter[parameters.length - j];
413                     ArgumentListExpression arguments = new ArgumentListExpression();
414                     int index = 0;
415                     int k = 1;
416                     for (int i = 0; i < parameters.length; i++) {
417                         if (k > counter - j && parameters[i] != null && parameters[i].hasInitialExpression()) {
418                             arguments.addExpression(parameters[i].getInitialExpression());
419                             k++;
420                         }
421                         else if (parameters[i] != null && parameters[i].hasInitialExpression()) {
422                             newParams[index++] = parameters[i];
423                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
424                             k++;
425                         }
426                         else {
427                             newParams[index++] = parameters[i];
428                             arguments.addExpression(new VariableExpression(parameters[i].getName()));
429                         }
430                     }
431 
432                     MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
433                     Statement code = null;
434                     if (method.isVoidMethod()) {
435                         code = new ExpressionStatement(expression);
436                     }
437                     else {
438                         code = new ReturnStatement(expression);
439                     }
440                     node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code);
441                 }
442             }
443         }
444     }
445 
446     /***
447      * Adds a new method which defaults the values for all the parameters starting 
448      * from and including the given index
449      * 
450      * @param node the class to add the method
451      * @param method the given method to add a helper of
452      * @param parameters the parameters of the method to add a helper for
453      * @param index the index of the first default value expression parameter to use
454      */
455     protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int depth, ArrayList values) {
456         // lets create a method using this expression
457         Parameter[] newParams = new Parameter[parameters.length - depth];
458         int index = 0;
459         ArgumentListExpression arguments = new ArgumentListExpression();
460         for (int i = 0; i < parameters.length; i++) {
461             if (parameters[i] != null && parameters[i].hasInitialExpression()) {
462                 newParams[index++] = parameters[i];
463                 arguments.addExpression(new VariableExpression(parameters[i].getName()));
464             }
465             else {
466                 arguments.addExpression(parameters[i].getInitialExpression());
467             }
468         }
469 
470         MethodCallExpression expression =
471             new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
472         Statement code = null;
473         if (method.isVoidMethod()) {
474             code = new ExpressionStatement(expression);
475         }
476         else {
477             code = new ReturnStatement(expression);
478         }
479 
480         node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code);
481     }
482 
483     /***
484      * Adds a new method which defaults the values for all the parameters starting 
485      * from and including the given index
486      * 
487      * @param node the class to add the method
488      * @param method the given method to add a helper of
489      * @param parameters the parameters of the method to add a helper for
490      * @param index the index of the first default value expression parameter to use
491      */
492     protected void addDefaultParameterMethod(ClassNode node, MethodNode method, Parameter[] parameters, int index) {
493         // lets create a method using this expression
494         Parameter[] newParams = new Parameter[index];
495         System.arraycopy(parameters, 0, newParams, 0, index);
496 
497         ArgumentListExpression arguments = new ArgumentListExpression();
498         int size = parameters.length;
499         for (int i = 0; i < size; i++) {
500             if (i < index) {
501                 arguments.addExpression(new VariableExpression(parameters[i].getName()));
502             }
503             else {
504                 Expression defaultValue = parameters[i].getInitialExpression();
505                 if (defaultValue == null) {
506                     throw new RuntimeParserException(
507                         "The " + parameters[i].getName() + " parameter must have a default value",
508                         method);
509                 }
510                 else {
511                     arguments.addExpression(defaultValue);
512                 }
513             }
514         }
515 
516         MethodCallExpression expression =
517             new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
518         Statement code = null;
519         if (method.isVoidMethod()) {
520             code = new ExpressionStatement(expression);
521             }
522         else {
523             code = new ReturnStatement(expression);
524         }
525 
526         node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, code);
527     }
528 
529     protected void addClosureCode(InnerClassNode node) {
530         // add a new invoke
531     }
532 
533     protected void addFieldInitialization(ClassNode node) {
534         for (Iterator iter = node.getDeclaredConstructors().iterator(); iter.hasNext();) {
535             addFieldInitialization(node, (ConstructorNode) iter.next());
536         }
537     }
538 
539     protected void addFieldInitialization(ClassNode node, ConstructorNode constructorNode) {
540         List statements = new ArrayList();
541         List staticStatements = new ArrayList();
542         for (Iterator iter = node.getFields().iterator(); iter.hasNext();) {
543             addFieldInitialization(statements, staticStatements, constructorNode, (FieldNode) iter.next());
544         }
545         if (!statements.isEmpty()) {
546             Statement code = constructorNode.getCode();
547             List otherStatements = new ArrayList();
548             if (code instanceof BlockStatement) {
549                 BlockStatement block = (BlockStatement) code;
550                 otherStatements.addAll(block.getStatements());
551             }
552             else if (code != null) {
553                 otherStatements.add(code);
554             }
555             if (!otherStatements.isEmpty()) {
556                 Statement first = (Statement) otherStatements.get(0);
557                 if (isSuperMethodCall(first)) {
558                     otherStatements.remove(0);
559                     statements.add(0, first);
560                 }
561                 statements.addAll(otherStatements);
562             }
563             constructorNode.setCode(new BlockStatement(statements));
564         }
565 
566         if (!staticStatements.isEmpty()) {
567             node.addStaticInitializerStatements(staticStatements);
568         }
569     }
570 
571     protected void addFieldInitialization(
572         List list,
573         List staticList,
574         ConstructorNode constructorNode,
575         FieldNode fieldNode) {
576         Expression expression = fieldNode.getInitialExpression();
577         if (expression != null) {
578             ExpressionStatement statement =
579                 new ExpressionStatement(
580                     new BinaryExpression(
581                         new FieldExpression(fieldNode),
582                         Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()),
583                         expression));
584             if (fieldNode.isStatic()) {
585                 staticList.add(statement);
586             }
587             else {
588                 list.add(statement);
589             }
590         }
591     }
592 
593     protected boolean isSuperMethodCall(Statement first) {
594         if (first instanceof ExpressionStatement) {
595             ExpressionStatement exprStmt = (ExpressionStatement) first;
596             Expression expr = exprStmt.getExpression();
597             if (expr instanceof MethodCallExpression) {
598                 return MethodCallExpression.isSuperMethodCall((MethodCallExpression) expr);
599             }
600         }
601         return false;
602     }
603 
604     /***
605      * Capitalizes the start of the given bean property name
606      */
607     public static String capitalize(String name) {
608         return name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
609     }
610 
611     protected Statement createGetterBlock(PropertyNode propertyNode, FieldNode field) {
612         Expression expression = new FieldExpression(field);
613         return new ReturnStatement(expression);
614     }
615 
616     protected Statement createSetterBlock(PropertyNode propertyNode, FieldNode field) {
617         Expression expression = new FieldExpression(field);
618         return new ExpressionStatement(
619             new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("value")));
620     }
621 
622     /***
623      * Filters the given statements
624      */
625     protected List filterStatements(List list) {
626         List answer = new ArrayList(list.size());
627         for (Iterator iter = list.iterator(); iter.hasNext();) {
628             answer.add(filterStatement((Statement) iter.next()));
629         }
630         return answer;
631     }
632 
633     protected Statement filterStatement(Statement statement) {
634         if (statement instanceof ExpressionStatement) {
635             ExpressionStatement expStmt = (ExpressionStatement) statement;
636             Expression expression = expStmt.getExpression();
637             if (expression instanceof ClosureExpression) {
638                 ClosureExpression closureExp = (ClosureExpression) expression;
639                 if (!closureExp.isParameterSpecified()) {
640                     return closureExp.getCode();
641                 }
642             }
643         }
644         return statement;
645     }
646 
647 }