001: /*
002: * $Id: CompileUnit.java 4295 2006-12-02 21:15:54Z 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 that the
008: * following conditions are met:
009: * 1. Redistributions of source code must retain copyright statements and
010: * notices. Redistributions must also contain a copy of this document.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. The name "groovy" must not be used to endorse or promote products
015: * derived from this Software without prior written permission of The Codehaus.
016: * For written permission, please contact info@codehaus.org.
017: * 4. Products derived from this Software may not be called "groovy" nor may
018: * "groovy" appear in their names without prior written permission of The
019: * Codehaus. "groovy" is a registered trademark of The Codehaus.
020: * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
021: *
022: * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
023: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
024: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
025: * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
026: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
027: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
028: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
029: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
030: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
031: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
032: * DAMAGE.
033: *
034: */
035: package org.codehaus.groovy.ast;
036:
037: import groovy.lang.GroovyClassLoader;
038:
039: import java.security.CodeSource;
040: import java.util.ArrayList;
041: import java.util.HashMap;
042: import java.util.Iterator;
043: import java.util.List;
044: import java.util.Map;
045:
046: import org.codehaus.groovy.control.CompilerConfiguration;
047: import org.codehaus.groovy.control.SourceUnit;
048: import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
049: import org.codehaus.groovy.syntax.SyntaxException;
050:
051: /**
052: * Represents the entire contents of a compilation step which consists of one
053: * or more {@link ModuleNode}instances
054: *
055: * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
056: * @version $Revision: 4295 $
057: */
058: public class CompileUnit {
059:
060: private List modules = new ArrayList();
061: private Map classes = new HashMap();
062: private CompilerConfiguration config;
063: private GroovyClassLoader classLoader;
064: private CodeSource codeSource;
065: private Map classesToCompile = new HashMap();
066: private Map classNameToSource = new HashMap();
067:
068: public CompileUnit(GroovyClassLoader classLoader,
069: CompilerConfiguration config) {
070: this (classLoader, null, config);
071: }
072:
073: public CompileUnit(GroovyClassLoader classLoader,
074: CodeSource codeSource, CompilerConfiguration config) {
075: this .classLoader = classLoader;
076: this .config = config;
077: this .codeSource = codeSource;
078: }
079:
080: public List getModules() {
081: return modules;
082: }
083:
084: public void addModule(ModuleNode node) {
085: // node==null means a compilation error prevented
086: // groovy from building an ast
087: if (node == null)
088: return;
089: modules.add(node);
090: node.setUnit(this );
091: addClasses(node.getClasses());
092: }
093:
094: /**
095: * @return the ClassNode for the given qualified name or returns null if
096: * the name does not exist in the current compilation unit
097: * (ignoring the .class files on the classpath)
098: */
099: public ClassNode getClass(String name) {
100: ClassNode cn = (ClassNode) classes.get(name);
101: if (cn != null)
102: return cn;
103: return (ClassNode) classesToCompile.get(name);
104: }
105:
106: /**
107: * @return a list of all the classes in each module in the compilation unit
108: */
109: public List getClasses() {
110: List answer = new ArrayList();
111: for (Iterator iter = modules.iterator(); iter.hasNext();) {
112: ModuleNode module = (ModuleNode) iter.next();
113: answer.addAll(module.getClasses());
114: }
115: return answer;
116: }
117:
118: public CompilerConfiguration getConfig() {
119: return config;
120: }
121:
122: public GroovyClassLoader getClassLoader() {
123: return classLoader;
124: }
125:
126: public CodeSource getCodeSource() {
127: return codeSource;
128: }
129:
130: /**
131: * Appends all of the fully qualified class names in this
132: * module into the given map
133: */
134: void addClasses(List classList) {
135: for (Iterator iter = classList.iterator(); iter.hasNext();) {
136: addClass((ClassNode) iter.next());
137: }
138: }
139:
140: /**
141: * Adds a class to the unit.
142: */
143: public void addClass(ClassNode node) {
144: node = node.redirect();
145: String name = node.getName();
146: ClassNode stored = (ClassNode) classes.get(name);
147: if (stored != null && stored != node) {
148: // we have a duplicate class!
149: // One possibility for this is, that we delcared a script and a
150: // class in the same file and named the class like the file
151: SourceUnit nodeSource = node.getModule().getContext();
152: SourceUnit storedSource = stored.getModule().getContext();
153: String txt = "Invalid duplicate class definition of class "
154: + node.getName() + " : ";
155: if (nodeSource == storedSource) {
156: // same class in same source
157: txt += "The source "
158: + nodeSource.getName()
159: + " contains at last two defintions of the class "
160: + node.getName() + ".\n";
161: if (node.isScriptBody() || stored.isScriptBody()) {
162: txt += "One of the classes is a explicit generated class using the class statement, the other is a class generated from"
163: + " the script body based on the file name. Solutions are to change the file name or to change the class name.\n";
164: }
165: } else {
166: txt += "The sources " + nodeSource.getName() + " and "
167: + storedSource.getName()
168: + " are containing both a class of the name "
169: + node.getName() + ".\n";
170: }
171: nodeSource.getErrorCollector().addErrorAndContinue(
172: new SyntaxErrorMessage(new SyntaxException(txt,
173: node.getLineNumber(), node
174: .getColumnNumber()), nodeSource));
175: }
176: classes.put(name, node);
177:
178: if (classesToCompile.containsKey(name)) {
179: ClassNode cn = (ClassNode) classesToCompile.get(name);
180: cn.setRedirect(node);
181: classesToCompile.remove(name);
182: }
183: }
184:
185: /**
186: * this emthod actually does not compile a class. It's only
187: * a marker that this type has to be compiled by the CompilationUnit
188: * at the end of a parse step no node should be be left.
189: */
190: public void addClassNodeToCompile(ClassNode node,
191: SourceUnit location) {
192: classesToCompile.put(node.getName(), node);
193: classNameToSource.put(node.getName(), location);
194: }
195:
196: public SourceUnit getScriptSourceLocation(String className) {
197: return (SourceUnit) classNameToSource.get(className);
198: }
199:
200: public boolean hasClassNodeToCompile() {
201: return classesToCompile.size() != 0;
202: }
203:
204: public Iterator iterateClassNodeToCompile() {
205: return classesToCompile.keySet().iterator();
206: }
207: }
|