View Javadoc

1   /*
2    * $Id: CompileUnit.java,v 1.19 2006/06/15 15:29:07 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 that the
8    * following conditions are met:
9    *  1. Redistributions of source code must retain copyright statements and
10   * notices. Redistributions must also contain a copy of this document.
11   *  2. Redistributions in binary form must reproduce the above copyright
12   * notice, this list of conditions and the following disclaimer in the
13   * documentation and/or other materials provided with the distribution.
14   *  3. The name "groovy" must not be used to endorse or promote products
15   * derived from this Software without prior written permission of The Codehaus.
16   * For written permission, please contact info@codehaus.org.
17   *  4. Products derived from this Software may not be called "groovy" nor may
18   * "groovy" appear in their names without prior written permission of The
19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
21   * 
22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32   * DAMAGE.
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          // node==null means a compilation error prevented
84          // groovy from building an ast
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             // we have a duplicate class!
145             // One possibility for this is, that we delcared a script and a 
146             // class in the same file and named the class like the file
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                 // same class in same source
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            /* throw new RuntimeException(
166                 "Error: duplicate class declaration for name: " + name + " and class: " + node);*/
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 }