KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > ast > ModuleNode


1 /*
2  $Id: ModuleNode.java,v 1.25 2004/07/10 03:31:38 bran 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.ast;
47
48 import groovy.lang.Script;
49 import groovy.lang.Binding;
50
51 import java.io.File JavaDoc;
52 import java.util.ArrayList JavaDoc;
53 import java.util.HashMap JavaDoc;
54 import java.util.Iterator JavaDoc;
55 import java.util.List JavaDoc;
56 import java.util.Map JavaDoc;
57
58 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
59 import org.codehaus.groovy.ast.expr.ClassExpression;
60 import org.codehaus.groovy.ast.expr.Expression;
61 import org.codehaus.groovy.ast.expr.MethodCallExpression;
62 import org.codehaus.groovy.ast.expr.VariableExpression;
63 import org.codehaus.groovy.ast.stmt.BlockStatement;
64 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
65 import org.codehaus.groovy.ast.stmt.Statement;
66 import org.codehaus.groovy.control.SourceUnit;
67 import org.codehaus.groovy.runtime.InvokerHelper;
68 import org.objectweb.asm.Constants;
69
70 /**
71  * Represents a module, which consists typically of a class declaration
72  * but could include some imports, some statements and multiple classes
73  * intermixed with statements like scripts in Python or Ruby
74  *
75  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
76  * @version $Revision: 1.25 $
77  */

78 public class ModuleNode extends ASTNode implements Constants {
79
80     private BlockStatement statementBlock = new BlockStatement();
81     List JavaDoc classes = new ArrayList JavaDoc();
82     private List JavaDoc methods = new ArrayList JavaDoc();
83     private List JavaDoc imports = new ArrayList JavaDoc();
84     private List JavaDoc importPackages = new ArrayList JavaDoc();
85     private Map JavaDoc importIndex = new HashMap JavaDoc();
86     private CompileUnit unit;
87     private String JavaDoc packageName;
88     private String JavaDoc description;
89     private boolean createClassForStatements = true;
90     private SourceUnit context;
91
92
93     public ModuleNode( SourceUnit context ) {
94         this.context = context;
95     }
96
97     public ModuleNode(CompileUnit unit) {
98         this.unit = unit;
99     }
100
101     public BlockStatement getStatementBlock() {
102         return statementBlock;
103     }
104
105     public List JavaDoc getMethods() {
106         return methods;
107     }
108
109     public List JavaDoc getClasses() {
110         if (createClassForStatements && (!statementBlock.isEmpty() || !methods.isEmpty())) {
111             ClassNode mainClass = createStatementsClass();
112             createClassForStatements = false;
113             classes.add(0, mainClass);
114             mainClass.setModule(this);
115             addToCompileUnit(mainClass);
116         }
117         return classes;
118     }
119
120     public List JavaDoc getImports() {
121         return imports;
122     }
123
124     public List JavaDoc getImportPackages() {
125         return importPackages;
126     }
127
128     /**
129      * @return the class name for the given alias or null if none is available
130      */

131     public String JavaDoc getImport(String JavaDoc alias) {
132         return (String JavaDoc) importIndex.get(alias);
133     }
134
135     public void addImport(String JavaDoc alias, String JavaDoc className) {
136         imports.add(new ImportNode(className, alias));
137         importIndex.put(alias, className);
138     }
139
140     public String JavaDoc[] addImportPackage(String JavaDoc packageName) {
141         importPackages.add(packageName);
142         return new String JavaDoc[] { /* class names, not qualified */ };
143     }
144
145     public void addStatement(Statement node) {
146         statementBlock.addStatement(node);
147     }
148
149     public void addClass(ClassNode node) {
150         classes.add(node);
151         node.setModule(this);
152         addToCompileUnit(node);
153     }
154
155     /**
156      * @param node
157      */

158     private void addToCompileUnit(ClassNode node) {
159         // register the new class with the compile unit
160
if (unit != null) {
161             unit.addClass(node);
162         }
163     }
164
165     public void addMethod(MethodNode node) {
166         methods.add(node);
167     }
168
169     public void visit(GroovyCodeVisitor visitor) {
170     }
171
172     public String JavaDoc getPackageName() {
173         return packageName;
174     }
175
176     public void setPackageName(String JavaDoc packageName) {
177         this.packageName = packageName;
178     }
179
180     public SourceUnit getContext() {
181         return context;
182     }
183
184     /**
185      * @return the underlying character stream description
186      */

187     public String JavaDoc getDescription() {
188         if( context != null )
189         {
190             return context.getName();
191         }
192         else
193         {
194             return this.description;
195         }
196     }
197
198     public void setDescription(String JavaDoc description) {
199         // DEPRECATED -- context.getName() is now sufficient
200
this.description = description;
201     }
202
203     public CompileUnit getUnit() {
204         return unit;
205     }
206
207     void setUnit(CompileUnit unit) {
208         this.unit = unit;
209     }
210
211     protected ClassNode createStatementsClass() {
212         String JavaDoc name = getPackageName();
213         if (name == null) {
214             name = "";
215         }
216         else {
217             name = name + ".";
218         }
219         // now lets use the file name to determine the class name
220
if (getDescription() == null) {
221             throw new RuntimeException JavaDoc("Cannot generate main(String[]) class for statements when we have no file description");
222         }
223         name += extractClassFromFileDescription();
224
225         String JavaDoc baseClass = null;
226         if (unit != null) {
227             baseClass = unit.getConfig().getScriptBaseClass();
228         }
229         if (baseClass == null) {
230             baseClass = Script.class.getName();
231         }
232         ClassNode classNode = new ClassNode(name, ACC_PUBLIC, baseClass);
233         classNode.setScript(true);
234
235         // return new Foo(new ShellContext(args)).run()
236
classNode.addMethod(
237             new MethodNode(
238                 "main",
239                 ACC_PUBLIC | ACC_STATIC,
240                 "void",
241                 new Parameter[] { new Parameter("java.lang.String[]", "args")},
242                 new ExpressionStatement(
243                     new MethodCallExpression(
244                         new ClassExpression(InvokerHelper.class.getName()),
245                         "runScript",
246                         new ArgumentListExpression(
247                             new Expression[] {
248                                 new ClassExpression(classNode.getName()),
249                                 new VariableExpression("args")})))));
250
251         classNode.addMethod(
252             new MethodNode("run", ACC_PUBLIC, Object JavaDoc.class.getName(), Parameter.EMPTY_ARRAY, statementBlock));
253
254         classNode.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, new BlockStatement());
255         Statement stmt = new ExpressionStatement(
256                         new MethodCallExpression(
257                             new VariableExpression("super"),
258                             "setBinding",
259                             new ArgumentListExpression(
260                                     new Expression[] {
261                                         new VariableExpression("context")})));
262
263         classNode.addConstructor(
264             ACC_PUBLIC,
265             new Parameter[] { new Parameter(Binding.class.getName(), "context")},
266             stmt);
267
268         for (Iterator JavaDoc iter = methods.iterator(); iter.hasNext();) {
269             MethodNode node = (MethodNode) iter.next();
270             int modifiers = node.getModifiers();
271             if ((modifiers & ACC_ABSTRACT) != 0) {
272                 throw new RuntimeException JavaDoc(
273                     "Cannot use abstract methods in a script, they are only available inside classes. Method: "
274                         + node.getName());
275             }
276             // br: the old logic seems to add static to all def f().... in a script, which makes enclosing
277
// inner classes (including closures) in a def function difficult. Comment it out.
278
node.setModifiers(modifiers /*| ACC_STATIC*/);
279
280             classNode.addMethod(node);
281         }
282         return classNode;
283     }
284
285     protected String JavaDoc extractClassFromFileDescription() {
286         // lets strip off everything after the last .
287
String JavaDoc answer = getDescription();
288         int idx = answer.lastIndexOf('.');
289         if (idx > 0) {
290             answer = answer.substring(0, idx);
291         }
292         // new lets trip the path separators
293
idx = answer.lastIndexOf('/');
294         if (idx >= 0) {
295             answer = answer.substring(idx + 1);
296         }
297         idx = answer.lastIndexOf(File.separatorChar);
298         if (idx >= 0) {
299             answer = answer.substring(idx + 1);
300         }
301         return answer;
302     }
303
304     public boolean isEmpty() {
305         return classes.isEmpty() && statementBlock.getStatements().isEmpty();
306     }
307
308 }
309
Popular Tags