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 package org.codehaus.groovy.ast;
36
37 import groovy.lang.GroovyClassLoader;
38
39 import java.security.CodeSource;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.Map;
45
46 import org.codehaus.groovy.control.CompilerConfiguration;
47 import org.codehaus.groovy.control.SourceUnit;
48 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
49 import org.codehaus.groovy.syntax.SyntaxException;
50
51 /***
52 * Represents the entire contents of a compilation step which consists of one
53 * or more {@link ModuleNode}instances
54 *
55 * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
56 * @version $Revision: 1.19 $
57 */
58 public class CompileUnit {
59
60 private List modules = new ArrayList();
61 private Map classes = new HashMap();
62 private CompilerConfiguration config;
63 private GroovyClassLoader classLoader;
64 private CodeSource codeSource;
65 private Map classesToCompile = new HashMap();
66 private Map classNameToSource = new HashMap();
67
68 public CompileUnit(GroovyClassLoader classLoader, CompilerConfiguration config) {
69 this(classLoader, null, config);
70 }
71
72 public CompileUnit(GroovyClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
73 this.classLoader = classLoader;
74 this.config = config;
75 this.codeSource = codeSource;
76 }
77
78 public List getModules() {
79 return modules;
80 }
81
82 public void addModule(ModuleNode node) {
83
84
85 if (node==null) return;
86 modules.add(node);
87 node.setUnit(this);
88 addClasses(node.getClasses());
89 }
90
91 /***
92 * @return the ClassNode for the given qualified name or returns null if
93 * the name does not exist in the current compilation unit
94 * (ignoring the .class files on the classpath)
95 */
96 public ClassNode getClass(String name) {
97 ClassNode cn = (ClassNode) classes.get(name);
98 if (cn!=null) return cn;
99 return (ClassNode) classesToCompile.get(name);
100 }
101
102 /***
103 * @return a list of all the classes in each module in the compilation unit
104 */
105 public List getClasses() {
106 List answer = new ArrayList();
107 for (Iterator iter = modules.iterator(); iter.hasNext();) {
108 ModuleNode module = (ModuleNode) iter.next();
109 answer.addAll(module.getClasses());
110 }
111 return answer;
112 }
113
114 public CompilerConfiguration getConfig() {
115 return config;
116 }
117
118 public GroovyClassLoader getClassLoader() {
119 return classLoader;
120 }
121
122 public CodeSource getCodeSource() {
123 return codeSource;
124 }
125
126 /***
127 * Appends all of the fully qualified class names in this
128 * module into the given map
129 */
130 void addClasses(List classList) {
131 for (Iterator iter = classList.iterator(); iter.hasNext();) {
132 addClass((ClassNode) iter.next());
133 }
134 }
135
136 /***
137 * Adds a class to the unit.
138 */
139 public void addClass(ClassNode node) {
140 node = node.redirect();
141 String name = node.getName();
142 ClassNode stored = (ClassNode) classes.get(name);
143 if (stored != null && stored != node) {
144
145
146
147 SourceUnit nodeSource = node.getModule().getContext();
148 SourceUnit storedSource = stored.getModule().getContext();
149 String txt = "Invalid duplicate class definition of class "+node.getName()+" : ";
150 if (nodeSource==storedSource) {
151
152 txt += "The source "+nodeSource.getName()+" contains at last two defintions of the class "+node.getName()+".\n";
153 if (node.isScriptBody() || stored.isScriptBody()) {
154 txt += "One of the classes is a explicit generated class using the class statement, the other is a class generated from"+
155 " the script body based on the file name. Solutions are to change the file name or to change the class name.\n";
156 }
157 } else {
158 txt += "The sources "+nodeSource.getName()+" and "+storedSource.getName()+" are containing both a class of the name "+node.getName()+".\n";
159 }
160 nodeSource.getErrorCollector().addErrorAndContinue(
161 new SyntaxErrorMessage(new SyntaxException(txt, node.getLineNumber(), node.getColumnNumber()), nodeSource)
162 );
163
164
165
166
167 }
168 classes.put(name, node);
169
170 if (classesToCompile.containsKey(name)) {
171 ClassNode cn = (ClassNode) classesToCompile.get(name);
172 cn.setRedirect(node);
173 classesToCompile.remove(name);
174 }
175 }
176
177 /***
178 * this emthod actually does not compile a class. It's only
179 * a marker that this type has to be compiled by the CompilationUnit
180 * at the end of a parse step no node should be be left.
181 */
182 public void addClassNodeToCompile(ClassNode node, String location) {
183 classesToCompile.put(node.getName(),node);
184 classNameToSource.put(node.getName(),location);
185 }
186
187 public String getScriptSourceLocation(String className) {
188 return (String) classNameToSource.get(className);
189 }
190
191 public boolean hasClassNodeToCompile(){
192 return classesToCompile.size()!=0;
193 }
194
195 public Iterator iterateClassNodeToCompile(){
196 return classesToCompile.keySet().iterator();
197 }
198 }