1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
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 classes = new ArrayList();
82 private List methods = new ArrayList();
83 private List imports = new ArrayList();
84 private List importPackages = new ArrayList();
85 private Map importIndex = new HashMap();
86 private CompileUnit unit;
87 private String packageName/package-summary.html">ong> String packageName;
88 private String 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 getMethods() {
106 return methods;
107 }
108
109 public List 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 getImports() {
121 return imports;
122 }
123
124 public List 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 getImport(String alias) {
132 return (String) importIndex.get(alias);
133 }
134
135 public void addImport(String alias, String className) {
136 imports.add(new ImportNode(className, alias));
137 importIndex.put(alias, className);
138 }
139
140 public String[] addImportPackage(String packageName) {/package-summary.html">ong> String[] addImportPackage(String packageName) {
141 importPackages.add(packageName);
142 return new String[] {
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
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 getPackageName() {
173 return</strong> packageName;
174 }
175
176 public void setPackageName(String packageName) {/package-summary.html">ong> void setPackageName(String 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 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 description) {
199
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 name = getPackageName();
213 if (name == null) {
214 name = "";
215 }
216 else {
217 name = name + ".";
218 }
219
220 if (getDescription() == null) {
221 throw new RuntimeException("Cannot generate main(String[]) class for statements when we have no file description");
222 }
223 name += extractClassFromFileDescription();
224
225 String 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
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.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 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(
273 "Cannot use abstract methods in a script, they are only available inside classes. Method: "
274 + node.getName());
275 }
276
277
278 node.setModifiers(modifiers
279
280 classNode.addMethod(node);
281 }
282 return classNode;
283 }
284
285 protected String extractClassFromFileDescription() {
286
287 String answer = getDescription();
288 int idx = answer.lastIndexOf('.');
289 if (idx > 0) {
290 answer = answer.substring(0, idx);
291 }
292
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 }