001: /*
002: $Id: Verifier.java 4598 2006-12-22 20:21:21Z blackdrag $
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package org.codehaus.groovy.classgen;
047:
048: import groovy.lang.GroovyObject;
049: import groovy.lang.MetaClass;
050:
051: import java.lang.reflect.Modifier;
052: import java.util.ArrayList;
053: import java.util.Iterator;
054: import java.util.List;
055:
056: import org.codehaus.groovy.ast.ClassHelper;
057: import org.codehaus.groovy.ast.ClassNode;
058: import org.codehaus.groovy.ast.CodeVisitorSupport;
059: import org.codehaus.groovy.ast.ConstructorNode;
060: import org.codehaus.groovy.ast.FieldNode;
061: import org.codehaus.groovy.ast.GroovyClassVisitor;
062: import org.codehaus.groovy.ast.InnerClassNode;
063: import org.codehaus.groovy.ast.MethodNode;
064: import org.codehaus.groovy.ast.Parameter;
065: import org.codehaus.groovy.ast.PropertyNode;
066: import org.codehaus.groovy.ast.VariableScope;
067: import org.codehaus.groovy.ast.expr.ArgumentListExpression;
068: import org.codehaus.groovy.ast.expr.BinaryExpression;
069: import org.codehaus.groovy.ast.expr.BooleanExpression;
070: import org.codehaus.groovy.ast.expr.ClosureExpression;
071: import org.codehaus.groovy.ast.expr.ConstantExpression;
072: import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
073: import org.codehaus.groovy.ast.expr.Expression;
074: import org.codehaus.groovy.ast.expr.FieldExpression;
075: import org.codehaus.groovy.ast.expr.MethodCallExpression;
076: import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
077: import org.codehaus.groovy.ast.expr.VariableExpression;
078: import org.codehaus.groovy.ast.stmt.BlockStatement;
079: import org.codehaus.groovy.ast.stmt.EmptyStatement;
080: import org.codehaus.groovy.ast.stmt.ExpressionStatement;
081: import org.codehaus.groovy.ast.stmt.IfStatement;
082: import org.codehaus.groovy.ast.stmt.ReturnStatement;
083: import org.codehaus.groovy.ast.stmt.Statement;
084: import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
085: import org.codehaus.groovy.syntax.Types;
086: import org.codehaus.groovy.syntax.Token;
087: import org.codehaus.groovy.syntax.RuntimeParserException;
088: import org.objectweb.asm.Opcodes;
089:
090: /**
091: * Verifies the AST node and adds any defaulted AST code before
092: * bytecode generation occurs.
093: *
094: * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
095: * @version $Revision: 4598 $
096: */
097: public class Verifier implements GroovyClassVisitor, Opcodes {
098:
099: public static final String __TIMESTAMP = "__timeStamp";
100: private ClassNode classNode;
101: private MethodNode methodNode;
102:
103: public ClassNode getClassNode() {
104: return classNode;
105: }
106:
107: public MethodNode getMethodNode() {
108: return methodNode;
109: }
110:
111: /**
112: * add code to implement GroovyObject
113: * @param node
114: */
115: public void visitClass(ClassNode node) {
116: this .classNode = node;
117:
118: if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0) {
119: //interfaces have no construcotrs, but this code expects one,
120: //so creta a dummy and don't add it to the class node
121: ConstructorNode dummy = new ConstructorNode(0, null);
122: addInitialization(node, dummy);
123: node.visitContents(this );
124: return;
125: }
126:
127: addDefaultParameterMethods(node);
128: addDefaultParameterConstructors(node);
129:
130: if (!node.isDerivedFromGroovyObject()) {
131: node.addInterface(ClassHelper.make(GroovyObject.class));
132:
133: // lets add a new field for the metaclass
134: StaticMethodCallExpression initMetaClassCall = new StaticMethodCallExpression(
135: ClassHelper.make(ScriptBytecodeAdapter.class),
136: "initMetaClass", VariableExpression.THIS_EXPRESSION);
137:
138: PropertyNode metaClassProperty = node.addProperty(
139: "metaClass", ACC_PUBLIC, ClassHelper
140: .make(MetaClass.class), initMetaClassCall,
141: null, null);
142: metaClassProperty.setSynthetic(true);
143: FieldNode metaClassField = metaClassProperty.getField();
144: metaClassField.setModifiers(metaClassField.getModifiers()
145: | ACC_TRANSIENT);
146:
147: FieldExpression metaClassVar = new FieldExpression(
148: metaClassField);
149: IfStatement initMetaClassField = new IfStatement(
150: new BooleanExpression(new BinaryExpression(
151: metaClassVar, Token.newSymbol(
152: Types.COMPARE_EQUAL, -1, -1),
153: ConstantExpression.NULL)),
154: new ExpressionStatement(new BinaryExpression(
155: metaClassVar, Token.newSymbol(Types.EQUAL,
156: -1, -1), initMetaClassCall)),
157: EmptyStatement.INSTANCE);
158:
159: node.addSyntheticMethod("getMetaClass", ACC_PUBLIC,
160: ClassHelper.make(MetaClass.class),
161: Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY,
162: new BlockStatement(new Statement[] {
163: initMetaClassField,
164: new ReturnStatement(metaClassVar) },
165: new VariableScope()));
166:
167: // @todo we should check if the base class implements the invokeMethod method
168:
169: // lets add the invokeMethod implementation
170: ClassNode super Class = node.getSuperClass();
171: boolean addDelegateObject = (node instanceof InnerClassNode && super Class
172: .equals(ClassHelper.CLOSURE_TYPE))
173: || super Class.equals(ClassHelper.GSTRING_TYPE);
174:
175: // don't do anything as the base class implements the invokeMethod
176: if (!addDelegateObject) {
177:
178: VariableExpression vMethods = new VariableExpression(
179: "method");
180: VariableExpression vArguments = new VariableExpression(
181: "arguments");
182: VariableScope blockScope = new VariableScope();
183: blockScope.getReferencedLocalVariables().put("method",
184: vMethods);
185: blockScope.getReferencedLocalVariables().put(
186: "arguments", vArguments);
187:
188: node
189: .addSyntheticMethod(
190: "invokeMethod",
191: ACC_PUBLIC,
192: ClassHelper.OBJECT_TYPE,
193: new Parameter[] {
194: new Parameter(
195: ClassHelper.STRING_TYPE,
196: "method"),
197: new Parameter(
198: ClassHelper.OBJECT_TYPE,
199: "arguments") },
200: ClassNode.EMPTY_ARRAY,
201: new BlockStatement(
202: new Statement[] {
203: initMetaClassField,
204: new ReturnStatement(
205: new MethodCallExpression(
206: metaClassVar,
207: "invokeMethod",
208: new ArgumentListExpression(
209: new Expression[] {
210: VariableExpression.THIS_EXPRESSION,
211: vMethods,
212: vArguments }))) },
213: blockScope));
214:
215: if (!node.isScript()) {
216: node
217: .addSyntheticMethod(
218: "getProperty",
219: ACC_PUBLIC,
220: ClassHelper.OBJECT_TYPE,
221: new Parameter[] { new Parameter(
222: ClassHelper.STRING_TYPE,
223: "property") },
224: ClassNode.EMPTY_ARRAY,
225: new BlockStatement(
226: new Statement[] {
227: initMetaClassField,
228: new ReturnStatement(
229: new MethodCallExpression(
230: metaClassVar,
231: "getProperty",
232: new ArgumentListExpression(
233: new Expression[] {
234: VariableExpression.THIS_EXPRESSION,
235: new VariableExpression(
236: "property") }))) },
237: new VariableScope()));
238: VariableExpression vProp = new VariableExpression(
239: "property");
240: VariableExpression vValue = new VariableExpression(
241: "value");
242: blockScope = new VariableScope();
243: blockScope.getReferencedLocalVariables().put(
244: "property", vProp);
245: blockScope.getReferencedLocalVariables().put(
246: "value", vValue);
247:
248: node
249: .addSyntheticMethod(
250: "setProperty",
251: ACC_PUBLIC,
252: ClassHelper.VOID_TYPE,
253: new Parameter[] {
254: new Parameter(
255: ClassHelper.STRING_TYPE,
256: "property"),
257: new Parameter(
258: ClassHelper.OBJECT_TYPE,
259: "value") },
260: ClassNode.EMPTY_ARRAY,
261: new BlockStatement(
262: new Statement[] {
263: initMetaClassField,
264: new ExpressionStatement(
265: new MethodCallExpression(
266: metaClassVar,
267: "setProperty",
268: new ArgumentListExpression(
269: new Expression[] {
270: VariableExpression.THIS_EXPRESSION,
271: vProp,
272: vValue }))) },
273: blockScope));
274: }
275: }
276: }
277:
278: if (node.getDeclaredConstructors().isEmpty()) {
279: ConstructorNode constructor = new ConstructorNode(
280: ACC_PUBLIC, null);
281: constructor.setSynthetic(true);
282: node.addConstructor(constructor);
283: }
284:
285: if (!(node instanceof InnerClassNode)) {// add a static timestamp field to the class
286: FieldNode timeTagField = new FieldNode(
287: Verifier.__TIMESTAMP, Modifier.PUBLIC
288: | Modifier.STATIC, ClassHelper.Long_TYPE,
289: //"",
290: node, new ConstantExpression(new Long(System
291: .currentTimeMillis())));
292: // alternatively , FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
293: timeTagField.setSynthetic(true);
294: node.addField(timeTagField);
295: }
296:
297: addInitialization(node);
298: node.getObjectInitializerStatements().clear();
299: node.visitContents(this );
300: }
301:
302: public void visitConstructor(ConstructorNode node) {
303: CodeVisitorSupport checkSuper = new CodeVisitorSupport() {
304: boolean firstMethodCall = true;
305: String type = null;
306:
307: public void visitMethodCallExpression(
308: MethodCallExpression call) {
309: if (!firstMethodCall)
310: return;
311: firstMethodCall = false;
312: String name = call.getMethodAsString();
313: if (!name.equals("super") && !name.equals("this"))
314: return;
315: type = name;
316: call.getArguments().visit(this );
317: type = null;
318: }
319:
320: public void visitVariableExpression(
321: VariableExpression expression) {
322: if (type == null)
323: return;
324: String name = expression.getName();
325: if (!name.equals("this") && !name.equals("super"))
326: return;
327: throw new RuntimeParserException(
328: "cannot reference "
329: + name
330: + " inside of "
331: + type
332: + "(....) before supertype constructor has been called",
333: expression);
334: }
335: };
336: Statement s = node.getCode();
337: //todo why can a statement can be null?
338: if (s == null)
339: return;
340: s.visit(checkSuper);
341: }
342:
343: public void visitMethod(MethodNode node) {
344: this .methodNode = node;
345: Statement statement = node.getCode();
346: if (!node.isVoidMethod()) {
347: if (statement instanceof ExpressionStatement) {
348: ExpressionStatement expStmt = (ExpressionStatement) statement;
349: node.setCode(new ReturnStatement(expStmt
350: .getExpression()));
351: } else if (statement instanceof BlockStatement) {
352: BlockStatement block = (BlockStatement) statement;
353:
354: // lets copy the list so we create a new block
355: List list = new ArrayList(block.getStatements());
356: if (!list.isEmpty()) {
357: int idx = list.size() - 1;
358: Statement last = (Statement) list.get(idx);
359: if (last instanceof ExpressionStatement) {
360: ExpressionStatement expStmt = (ExpressionStatement) last;
361: list.set(idx, new ReturnStatement(expStmt));
362: } else if (!(last instanceof ReturnStatement)) {
363: list.add(new ReturnStatement(
364: ConstantExpression.NULL));
365: }
366: } else {
367: list.add(new ReturnStatement(
368: ConstantExpression.NULL));
369: }
370:
371: node.setCode(new BlockStatement(filterStatements(list),
372: block.getVariableScope()));
373: }
374: } else if (!node.isAbstract()) {
375: BlockStatement newBlock = new BlockStatement();
376: if (statement instanceof BlockStatement) {
377: newBlock
378: .addStatements(filterStatements(((BlockStatement) statement)
379: .getStatements()));
380: } else {
381: newBlock.addStatement(filterStatement(statement));
382: }
383: newBlock.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
384: node.setCode(newBlock);
385: }
386: if (node.getName().equals("main") && node.isStatic()) {
387: Parameter[] params = node.getParameters();
388: if (params.length == 1) {
389: Parameter param = params[0];
390: if (param.getType() == null
391: || param.getType() == ClassHelper.OBJECT_TYPE) {
392: param.setType(ClassHelper.STRING_TYPE.makeArray());
393: }
394: }
395: }
396: statement = node.getCode();
397: if (statement != null)
398: statement.visit(new VerifierCodeVisitor(this ));
399: }
400:
401: public void visitField(FieldNode node) {
402: }
403:
404: public void visitProperty(PropertyNode node) {
405: String name = node.getName();
406: FieldNode field = node.getField();
407:
408: String getterName = "get" + capitalize(name);
409: String setterName = "set" + capitalize(name);
410:
411: Statement getterBlock = node.getGetterBlock();
412: if (getterBlock == null) {
413: if (!node.isPrivate()
414: && classNode.getGetterMethod(getterName) == null) {
415: getterBlock = createGetterBlock(node, field);
416: }
417: }
418: Statement setterBlock = node.getSetterBlock();
419: if (setterBlock == null) {
420: if (!node.isPrivate()
421: && (node.getModifiers() & ACC_FINAL) == 0
422: && classNode.getSetterMethod(setterName) == null) {
423: setterBlock = createSetterBlock(node, field);
424: }
425: }
426:
427: if (getterBlock != null) {
428: MethodNode getter = new MethodNode(getterName, node
429: .getModifiers(), node.getType(),
430: Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY,
431: getterBlock);
432: getter.setSynthetic(true);
433: classNode.addMethod(getter);
434: visitMethod(getter);
435:
436: if (ClassHelper.boolean_TYPE == node.getType()
437: || ClassHelper.Boolean_TYPE == node.getType()) {
438: String secondGetterName = "is" + capitalize(name);
439: MethodNode secondGetter = new MethodNode(
440: secondGetterName, node.getModifiers(), node
441: .getType(), Parameter.EMPTY_ARRAY,
442: ClassNode.EMPTY_ARRAY, getterBlock);
443: secondGetter.setSynthetic(true);
444: classNode.addMethod(secondGetter);
445: visitMethod(secondGetter);
446: }
447: }
448: if (setterBlock != null) {
449: Parameter[] setterParameterTypes = { new Parameter(node
450: .getType(), "value") };
451: MethodNode setter = new MethodNode(setterName, node
452: .getModifiers(), ClassHelper.VOID_TYPE,
453: setterParameterTypes, ClassNode.EMPTY_ARRAY,
454: setterBlock);
455: setter.setSynthetic(true);
456: classNode.addMethod(setter);
457: visitMethod(setter);
458: }
459: }
460:
461: // Implementation methods
462: //-------------------------------------------------------------------------
463:
464: private interface DefaultArgsAction {
465: public void call(ArgumentListExpression arguments,
466: Parameter[] newParams, MethodNode method);
467: }
468:
469: /**
470: * Creates a new helper method for each combination of default parameter expressions
471: */
472: protected void addDefaultParameterMethods(final ClassNode node) {
473: List methods = new ArrayList(node.getMethods());
474: addDefaultParameters(methods, new DefaultArgsAction() {
475: public void call(ArgumentListExpression arguments,
476: Parameter[] newParams, MethodNode method) {
477: MethodCallExpression expression = new MethodCallExpression(
478: VariableExpression.THIS_EXPRESSION, method
479: .getName(), arguments);
480: expression.setImplicitThis(true);
481: Statement code = null;
482: if (method.isVoidMethod()) {
483: code = new ExpressionStatement(expression);
484: } else {
485: code = new ReturnStatement(expression);
486: }
487: node.addMethod(method.getName(), method.getModifiers(),
488: method.getReturnType(), newParams, method
489: .getExceptions(), code);
490: }
491: });
492: }
493:
494: protected void addDefaultParameterConstructors(final ClassNode node) {
495: List methods = new ArrayList(node.getDeclaredConstructors());
496: addDefaultParameters(methods, new DefaultArgsAction() {
497: public void call(ArgumentListExpression arguments,
498: Parameter[] newParams, MethodNode method) {
499: ConstructorNode ctor = (ConstructorNode) method;
500: ConstructorCallExpression expression = new ConstructorCallExpression(
501: ClassNode.THIS, arguments);
502: Statement code = new ExpressionStatement(expression);
503: node.addConstructor(ctor.getModifiers(), newParams,
504: ctor.getExceptions(), code);
505: }
506: });
507: }
508:
509: /**
510: * Creates a new helper method for each combination of default parameter expressions
511: */
512: protected void addDefaultParameters(List methods,
513: DefaultArgsAction action) {
514: for (Iterator iter = methods.iterator(); iter.hasNext();) {
515: MethodNode method = (MethodNode) iter.next();
516: if (method.hasDefaultValue()) {
517: Parameter[] parameters = method.getParameters();
518: int counter = 0;
519: ArrayList paramValues = new ArrayList();
520: int size = parameters.length;
521: for (int i = size - 1; i >= 0; i--) {
522: Parameter parameter = parameters[i];
523: if (parameter != null
524: && parameter.hasInitialExpression()) {
525: paramValues.add(new Integer(i));
526: paramValues.add(parameter
527: .getInitialExpression());
528: counter++;
529: }
530: }
531:
532: for (int j = 1; j <= counter; j++) {
533: Parameter[] newParams = new Parameter[parameters.length
534: - j];
535: ArgumentListExpression arguments = new ArgumentListExpression();
536: int index = 0;
537: int k = 1;
538: for (int i = 0; i < parameters.length; i++) {
539: if (k > counter - j && parameters[i] != null
540: && parameters[i].hasInitialExpression()) {
541: arguments.addExpression(parameters[i]
542: .getInitialExpression());
543: k++;
544: } else if (parameters[i] != null
545: && parameters[i].hasInitialExpression()) {
546: newParams[index++] = parameters[i];
547: arguments
548: .addExpression(new VariableExpression(
549: parameters[i].getName()));
550: k++;
551: } else {
552: newParams[index++] = parameters[i];
553: arguments
554: .addExpression(new VariableExpression(
555: parameters[i].getName()));
556: }
557: }
558: action.call(arguments, newParams, method);
559: }
560: }
561: }
562: }
563:
564: protected void addClosureCode(InnerClassNode node) {
565: // add a new invoke
566: }
567:
568: protected void addInitialization(ClassNode node) {
569: for (Iterator iter = node.getDeclaredConstructors().iterator(); iter
570: .hasNext();) {
571: addInitialization(node, (ConstructorNode) iter.next());
572: }
573: }
574:
575: protected void addInitialization(ClassNode node,
576: ConstructorNode constructorNode) {
577: Statement firstStatement = constructorNode.getFirstStatement();
578: ConstructorCallExpression first = getFirstIfSpecialConstructorCall(firstStatement);
579:
580: // in case of this(...) let the other constructor do the intit
581: if (first != null && first.isThisCall())
582: return;
583:
584: List statements = new ArrayList();
585: List staticStatements = new ArrayList();
586: for (Iterator iter = node.getFields().iterator(); iter
587: .hasNext();) {
588: addFieldInitialization(statements, staticStatements,
589: (FieldNode) iter.next());
590: }
591: statements.addAll(node.getObjectInitializerStatements());
592: if (!statements.isEmpty()) {
593: Statement code = constructorNode.getCode();
594: BlockStatement block = new BlockStatement();
595: List otherStatements = block.getStatements();
596: if (code instanceof BlockStatement) {
597: block = (BlockStatement) code;
598: otherStatements = block.getStatements();
599: } else if (code != null) {
600: otherStatements.add(code);
601: }
602: if (!otherStatements.isEmpty()) {
603: if (first != null) {
604: // it is super(..) since this(..) is already covered
605: otherStatements.remove(0);
606: statements.add(0, firstStatement);
607: }
608: statements.addAll(otherStatements);
609: }
610: constructorNode.setCode(new BlockStatement(statements,
611: block.getVariableScope()));
612: }
613:
614: if (!staticStatements.isEmpty()) {
615: node.addStaticInitializerStatements(staticStatements, true);
616: }
617: }
618:
619: private ConstructorCallExpression getFirstIfSpecialConstructorCall(
620: Statement code) {
621: if (code == null || !(code instanceof ExpressionStatement))
622: return null;
623:
624: Expression expression = ((ExpressionStatement) code)
625: .getExpression();
626: if (!(expression instanceof ConstructorCallExpression))
627: return null;
628: ConstructorCallExpression cce = (ConstructorCallExpression) expression;
629: if (cce.isSpecialCall())
630: return cce;
631: return null;
632: }
633:
634: protected void addFieldInitialization(List list, List staticList,
635: FieldNode fieldNode) {
636: Expression expression = fieldNode.getInitialExpression();
637: if (expression != null) {
638: ExpressionStatement statement = new ExpressionStatement(
639: new BinaryExpression(
640: new FieldExpression(fieldNode), Token
641: .newSymbol(Types.EQUAL, fieldNode
642: .getLineNumber(), fieldNode
643: .getColumnNumber()),
644: expression));
645: if (fieldNode.isStatic()) {
646: staticList.add(statement);
647: } else {
648: list.add(statement);
649: }
650: }
651: }
652:
653: /**
654: * Capitalizes the start of the given bean property name
655: */
656: public static String capitalize(String name) {
657: return name.substring(0, 1).toUpperCase()
658: + name.substring(1, name.length());
659: }
660:
661: protected Statement createGetterBlock(PropertyNode propertyNode,
662: FieldNode field) {
663: Expression expression = new FieldExpression(field);
664: return new ReturnStatement(expression);
665: }
666:
667: protected Statement createSetterBlock(PropertyNode propertyNode,
668: FieldNode field) {
669: Expression expression = new FieldExpression(field);
670: return new ExpressionStatement(new BinaryExpression(expression,
671: Token.newSymbol(Types.EQUAL, 0, 0),
672: new VariableExpression("value")));
673: }
674:
675: /**
676: * Filters the given statements
677: */
678: protected List filterStatements(List list) {
679: List answer = new ArrayList(list.size());
680: for (Iterator iter = list.iterator(); iter.hasNext();) {
681: answer.add(filterStatement((Statement) iter.next()));
682: }
683: return answer;
684: }
685:
686: protected Statement filterStatement(Statement statement) {
687: if (statement instanceof ExpressionStatement) {
688: ExpressionStatement expStmt = (ExpressionStatement) statement;
689: Expression expression = expStmt.getExpression();
690: if (expression instanceof ClosureExpression) {
691: ClosureExpression closureExp = (ClosureExpression) expression;
692: if (!closureExp.isParameterSpecified()) {
693: return closureExp.getCode();
694: }
695: }
696: }
697: return statement;
698: }
699:
700: }
|