home | career | drupal | java | mac | mysql | perl | scala | uml | unix

Groovy example source code file (CompilationUnit.java)

This example Groovy source code file (CompilationUnit.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

classnode, classnode, compilationfailedexception, compilationfailedexception, compilationunit, groovyclassloader, io, linkedlist, list, list, net, network, primaryclassnodeoperation, security, sourceunit, sourceunit, sourceunitoperation, string, util

The Groovy CompilationUnit.java source code

/*
 * Copyright 2003-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.codehaus.groovy.control;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyRuntimeException;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.CompileUnit;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.classgen.*;
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
import org.codehaus.groovy.control.io.InputStreamReaderSource;
import org.codehaus.groovy.control.io.ReaderSource;
import org.codehaus.groovy.control.messages.ExceptionMessage;
import org.codehaus.groovy.control.messages.Message;
import org.codehaus.groovy.control.messages.SimpleMessage;
import org.codehaus.groovy.syntax.SyntaxException;
import org.codehaus.groovy.tools.GroovyClass;
import org.codehaus.groovy.transform.ASTTransformationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.CodeSource;
import java.util.*;

/**
 * The CompilationUnit collects all compilation data as it is generated by the compiler system.
 * You can use this object to add additional source units to the compilation, or force the
 * compilation to be run again (to affect only the deltas). <br/>
* * You can also add PhaseOperations to this compilation using the addPhaseOperation method. * This is commonly used when you want to wire a new AST Transformation into the compilation. * * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou * @author <a href="mailto:roshandawrani@codehaus.org">Roshan Dawrani * @version $Id: CompilationUnit.java 21958 2011-04-08 16:07:34Z blackdrag $ */ public class CompilationUnit extends ProcessingUnit { //--------------------------------------------------------------------------- // CONSTRUCTION AND SUCH private GroovyClassLoader transformLoader; // Classloader for global and local transforms protected Map<String, SourceUnit> sources; // The SourceUnits from which this unit is built protected Map summariesBySourceName; // Summary of each SourceUnit protected Map summariesByPublicClassName; // Summary of each SourceUnit protected Map classSourcesByPublicClassName; // Summary of each Class protected List<String> names; // Names for each SourceUnit in sources. protected LinkedList<SourceUnit> queuedSources; protected CompileUnit ast; // The overall AST for this CompilationUnit. protected List<GroovyClass> generatedClasses; // The classes generated during classgen. protected Verifier verifier; // For use by verify(). protected boolean debug; // Controls behavior of classgen() and other routines. protected boolean configured; // Set true after the first configure() operation protected ClassgenCallback classgenCallback; // A callback for use during classgen() protected ProgressCallback progressCallback; // A callback for use during compile() protected ResolveVisitor resolveVisitor; protected StaticImportVisitor staticImportVisitor; protected OptimizerVisitor optimizer; LinkedList[] phaseOperations; LinkedList[] newPhaseOperations; /** * Initializes the CompilationUnit with defaults. */ public CompilationUnit() { this(null, null, null); } /** * Initializes the CompilationUnit with defaults except for class loader. */ public CompilationUnit(GroovyClassLoader loader) { this(null, null, loader); } /** * Initializes the CompilationUnit with no security considerations. */ public CompilationUnit(CompilerConfiguration configuration) { this(configuration, null, null); } /** * Initializes the CompilationUnit with a CodeSource for controlling * security stuff and a class loader for loading classes. */ public CompilationUnit(CompilerConfiguration configuration, CodeSource security, GroovyClassLoader loader) { this(configuration, security, loader, null); } /** * Initializes the CompilationUnit with a CodeSource for controlling * security stuff, a class loader for loading classes, and a class * loader for loading AST transformations. * <b>Note The transform loader must be * able to load compiler classes. That means CompilationUnit.class.classLoader * must be at last a parent to transformLoader. The other loader has no such constraint. * * @param transformLoader - the loader for transforms * @param loader - loader used to resolve classes against during compilation * @param security - security setting for the compilation * @param configuration - compilation configuration */ public CompilationUnit(CompilerConfiguration configuration, CodeSource security, GroovyClassLoader loader, GroovyClassLoader transformLoader) { super(configuration, loader, null); this.transformLoader = transformLoader; this.names = new ArrayList<String>(); this.queuedSources = new LinkedList<SourceUnit>(); this.sources = new HashMap<String, SourceUnit>(); this.summariesBySourceName = new HashMap(); this.summariesByPublicClassName = new HashMap(); this.classSourcesByPublicClassName = new HashMap(); this.ast = new CompileUnit(this.classLoader, security, this.configuration); this.generatedClasses = new ArrayList<GroovyClass>(); this.verifier = new Verifier(); this.resolveVisitor = new ResolveVisitor(this); this.staticImportVisitor = new StaticImportVisitor(); this.optimizer = new OptimizerVisitor(this); phaseOperations = new LinkedList[Phases.ALL + 1]; newPhaseOperations = new LinkedList[Phases.ALL + 1]; for (int i = 0; i < phaseOperations.length; i++) { phaseOperations[i] = new LinkedList(); newPhaseOperations[i] = new LinkedList(); } addPhaseOperation(new SourceUnitOperation() { public void call(SourceUnit source) throws CompilationFailedException { source.parse(); } }, Phases.PARSING); addPhaseOperation(convert, Phases.CONVERSION); addPhaseOperation(new PrimaryClassNodeOperation() { public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { EnumVisitor ev = new EnumVisitor(CompilationUnit.this, source); ev.visitClass(classNode); } }, Phases.CONVERSION); addPhaseOperation(resolve, Phases.SEMANTIC_ANALYSIS); addPhaseOperation(staticImport, Phases.SEMANTIC_ANALYSIS); addPhaseOperation(new PrimaryClassNodeOperation() { @Override public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { InnerClassVisitor iv = new InnerClassVisitor(CompilationUnit.this, source); iv.visitClass(classNode); } }, Phases.SEMANTIC_ANALYSIS); addPhaseOperation(compileCompleteCheck, Phases.CANONICALIZATION); addPhaseOperation(classgen, Phases.CLASS_GENERATION); addPhaseOperation(output); ASTTransformationVisitor.addPhaseOperations(this); addPhaseOperation(new PrimaryClassNodeOperation() { @Override public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { StaticVerifier sv = new StaticVerifier(); sv.visitClass(classNode, source); } }, Phases.SEMANTIC_ANALYSIS); addPhaseOperation(new PrimaryClassNodeOperation() { @Override public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { InnerClassCompletionVisitor iv = new InnerClassCompletionVisitor(); iv.visitClass(classNode); } }, Phases.CANONICALIZATION); // apply configuration customizers if any if (configuration != null) { final List<CompilationCustomizer> customizers = configuration.getCompilationCustomizers(); for (CompilationCustomizer customizer : customizers) { addPhaseOperation(customizer, customizer.getPhase().getPhaseNumber()); } } this.classgenCallback = null; } /** * Returns the class loader for loading AST transformations. * @return - the transform class loader */ public GroovyClassLoader getTransformLoader() { return transformLoader == null ? getClassLoader() : transformLoader; } public void addPhaseOperation(SourceUnitOperation op, int phase) { if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown"); phaseOperations[phase].add(op); } public void addPhaseOperation(PrimaryClassNodeOperation op, int phase) { if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown"); phaseOperations[phase].add(op); } public void addPhaseOperation(GroovyClassOperation op) { phaseOperations[Phases.OUTPUT].addFirst(op); } public void addNewPhaseOperation(SourceUnitOperation op, int phase) { if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown"); newPhaseOperations[phase].add(op); } /** * Configures its debugging mode and classloader classpath from a given compiler configuration. * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}. */ public void configure(CompilerConfiguration configuration) { super.configure(configuration); this.debug = configuration.getDebug(); if (!this.configured && this.classLoader instanceof GroovyClassLoader) { appendCompilerConfigurationClasspathToClassLoader(configuration, (GroovyClassLoader) this.classLoader); } this.configured = true; } private void appendCompilerConfigurationClasspathToClassLoader(CompilerConfiguration configuration, GroovyClassLoader classLoader) { /*for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext(); ) { classLoader.addClasspath((String) iterator.next()); }*/ } /** * Returns the CompileUnit that roots our AST. */ public CompileUnit getAST() { return this.ast; } /** * Get the source summaries */ public Map getSummariesBySourceName() { return summariesBySourceName; } public Map getSummariesByPublicClassName() { return summariesByPublicClassName; } public Map getClassSourcesByPublicClassName() { return classSourcesByPublicClassName; } public boolean isPublicClass(String className) { return summariesByPublicClassName.containsKey(className); } /** * Get the GroovyClasses generated by compile(). */ public List getClasses() { return generatedClasses; } /** * Convenience routine to get the first ClassNode, for * when you are sure there is only one. */ public ClassNode getFirstClassNode() { return this.ast.getModules().get(0).getClasses().get(0); } /** * Convenience routine to get the named ClassNode. */ public ClassNode getClassNode(final String name) { final ClassNode[] result = new ClassNode[]{null}; PrimaryClassNodeOperation handler = new PrimaryClassNodeOperation() { public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) { if (classNode.getName().equals(name)) { result[0] = classNode; } } }; try { applyToPrimaryClassNodes(handler); } catch (CompilationFailedException e) { if (debug) e.printStackTrace(); } return result[0]; } //--------------------------------------------------------------------------- // SOURCE CREATION /** * Adds a set of file paths to the unit. */ public void addSources(String[] paths) { for (String path : paths) { addSource(new File(path)); } } /** * Adds a set of source files to the unit. */ public void addSources(File[] files) { for (File file : files) { addSource(file); } } /** * Adds a source file to the unit. */ public SourceUnit addSource(File file) { return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector())); } /** * Adds a source file to the unit. */ public SourceUnit addSource(URL url) { return addSource(new SourceUnit(url, configuration, classLoader, getErrorCollector())); } /** * Adds a InputStream source to the unit. */ public SourceUnit addSource(String name, InputStream stream) { ReaderSource source = new InputStreamReaderSource(stream, configuration); return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector())); } public SourceUnit addSource(String name, String scriptText) { return addSource(new SourceUnit(name, scriptText, configuration, classLoader, getErrorCollector())); } /** * Adds a SourceUnit to the unit. */ public SourceUnit addSource(SourceUnit source) { String name = source.getName(); source.setClassLoader(this.classLoader); for (SourceUnit su : queuedSources) { if (name.equals(su.getName())) return su; } queuedSources.add(source); return source; } /** * Returns an iterator on the unit's SourceUnits. */ public Iterator<SourceUnit> iterator() { return new Iterator<SourceUnit>() { Iterator<String> nameIterator = names.iterator(); public boolean hasNext() { return nameIterator.hasNext(); } public SourceUnit next() { String name = nameIterator.next(); return sources.get(name); } public void remove() { throw new UnsupportedOperationException(); } }; } /** * Adds a ClassNode directly to the unit (ie. without source). * WARNING: the source is needed for error reporting, using * this method without setting a SourceUnit will cause * NullPinterExceptions */ public void addClassNode(ClassNode node) { ModuleNode module = new ModuleNode(this.ast); this.ast.addModule(module); module.addClass(node); } //--------------------------------------------------------------------------- // EXTERNAL CALLBACKS /** * A callback interface you can use to "accompany" the classgen() * code as it traverses the ClassNode tree. You will be called-back * for each primary and inner class. Use setClassgenCallback() before * running compile() to set your callback. */ public abstract static class ClassgenCallback { public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException; } /** * Sets a ClassgenCallback. You can have only one, and setting * it to null removes any existing setting. */ public void setClassgenCallback(ClassgenCallback visitor) { this.classgenCallback = visitor; } /** * A callback interface you can use to get a callback after every * unit of the compile process. You will be called-back with a * ProcessingUnit and a phase indicator. Use setProgressCallback() * before running compile() to set your callback. */ public abstract static class ProgressCallback { public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException; } /** * Sets a ProgressCallback. You can have only one, and setting * it to null removes any existing setting. */ public void setProgressCallback(ProgressCallback callback) { this.progressCallback = callback; } //--------------------------------------------------------------------------- // ACTIONS /** * Synonym for compile(Phases.ALL). */ public void compile() throws CompilationFailedException { compile(Phases.ALL); } /** * Compiles the compilation unit from sources. */ public void compile(int throughPhase) throws CompilationFailedException { // // To support delta compilations, we always restart // the compiler. The individual passes are responsible // for not reprocessing old code. gotoPhase(Phases.INITIALIZATION); throughPhase = Math.min(throughPhase, Phases.ALL); while (throughPhase >= phase && phase <= Phases.ALL) { if (phase == Phases.SEMANTIC_ANALYSIS) { doPhaseOperation(resolve); if (dequeued()) continue; } processPhaseOperations(phase); // Grab processing may have brought in new AST transforms into various phases, process them as well processNewPhaseOperations(phase); if (progressCallback != null) progressCallback.call(this, phase); completePhase(); applyToSourceUnits(mark); if (dequeued()) continue; gotoPhase(phase + 1); if (phase == Phases.CLASS_GENERATION) { sortClasses(); } } errorCollector.failIfErrors(); } private void processPhaseOperations(int ph) { LinkedList ops = phaseOperations[ph]; for (Object next : ops) { doPhaseOperation(next); } } private void processNewPhaseOperations(int currPhase) { recordPhaseOpsInAllOtherPhases(currPhase); LinkedList currentPhaseNewOps = newPhaseOperations[currPhase]; while (!currentPhaseNewOps.isEmpty()) { Object operation = currentPhaseNewOps.removeFirst(); // push this operation to master list and then process it. phaseOperations[currPhase].add(operation); doPhaseOperation(operation); // if this operation has brought in more phase ops for ast transforms, keep recording them // in master list of other phases and keep processing them for this phase. recordPhaseOpsInAllOtherPhases(currPhase); currentPhaseNewOps = newPhaseOperations[currPhase]; } } private void doPhaseOperation(Object operation) { if (operation instanceof PrimaryClassNodeOperation) { applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation); } else if (operation instanceof SourceUnitOperation) { applyToSourceUnits((SourceUnitOperation) operation); } else { applyToGeneratedGroovyClasses((GroovyClassOperation) operation); } } private void recordPhaseOpsInAllOtherPhases(int currPhase) { // apart from current phase, push new operations for every other phase in the master phase ops list for (int ph = Phases.INITIALIZATION; ph <= Phases.ALL; ph++) { if (ph != currPhase && !newPhaseOperations[ph].isEmpty()) { phaseOperations[ph].addAll(newPhaseOperations[ph]); newPhaseOperations[ph].clear(); } } } private void sortClasses() throws CompilationFailedException { for (ModuleNode module : this.ast.getModules()) { module.sortClasses(); } } /** * Dequeues any source units add through addSource and resets the compiler phase * to initialization. * <p/> * Note: this does not mean a file is recompiled. If a SourceUnit has already passed * a phase it is skipped until a higher phase is reached. * * @return true if there was a queued source * @throws CompilationFailedException */ protected boolean dequeued() throws CompilationFailedException { boolean dequeue = !queuedSources.isEmpty(); while (!queuedSources.isEmpty()) { SourceUnit su = queuedSources.removeFirst(); String name = su.getName(); names.add(name); sources.put(name, su); } if (dequeue) { gotoPhase(Phases.INITIALIZATION); } return dequeue; } /** * Resolves all types */ private final SourceUnitOperation resolve = new SourceUnitOperation() { public void call(SourceUnit source) throws CompilationFailedException { List<ClassNode> classes = source.ast.getClasses(); for (ClassNode node : classes) { VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source); scopeVisitor.visitClass(node); resolveVisitor.startResolving(node, source); } } }; private PrimaryClassNodeOperation staticImport = new PrimaryClassNodeOperation() { public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { staticImportVisitor.visitClass(classNode, source); } }; /** * Runs convert() on a single SourceUnit. */ private SourceUnitOperation convert = new SourceUnitOperation() { public void call(SourceUnit source) throws CompilationFailedException { source.convert(); CompilationUnit.this.ast.addModule(source.getAST()); if (CompilationUnit.this.progressCallback != null) { CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase); } } }; private GroovyClassOperation output = new GroovyClassOperation() { public void call(GroovyClass gclass) throws CompilationFailedException { String name = gclass.getName().replace('.', File.separatorChar) + ".class"; File path = new File(configuration.getTargetDirectory(), name); // // Ensure the path is ready for the file // File directory = path.getParentFile(); if (directory != null && !directory.exists()) { directory.mkdirs(); } // // Create the file and write out the data // byte[] bytes = gclass.getBytes(); FileOutputStream stream = null; try { stream = new FileOutputStream(path); stream.write(bytes, 0, bytes.length); } catch (IOException e) { getErrorCollector().addError(Message.create(e.getMessage(), CompilationUnit.this)); } finally { if (stream != null) { try { stream.close(); } catch (Exception e) { // Ignore } } } } }; /* checks if all needed classes are compiled before generating the bytecode */ private SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() { public void call(SourceUnit source) throws CompilationFailedException { List<ClassNode> classes = source.ast.getClasses(); for (ClassNode node : classes) { CompileUnit cu = node.getCompileUnit(); for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext();) { String name = (String) iter.next(); SourceUnit su = ast.getScriptSourceLocation(name); List<ClassNode> classesInSourceUnit = su.ast.getClasses(); StringBuffer message = new StringBuffer(); message .append("Compilation incomplete: expected to find the class ") .append(name) .append(" in ") .append(su.getName()); if (classesInSourceUnit.isEmpty()) { message.append(", but the file seems not to contain any classes"); } else { message.append(", but the file contains the classes: "); boolean first = true; for (ClassNode cn : classesInSourceUnit) { if (!first) { message.append(", "); } else { first = false; } message.append(cn.getName()); } } getErrorCollector().addErrorAndContinue( new SimpleMessage(message.toString(), CompilationUnit.this) ); iter.remove(); } } } }; /** * Runs classgen() on a single ClassNode. */ private PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() { public boolean needSortedInput() { return true; } public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException { optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from staticImport if(!classNode.isSynthetic()) { GenericsVisitor genericsVisitor = new GenericsVisitor(source); genericsVisitor.visitClass(classNode); } // // Run the Verifier on the outer class // try { verifier.visitClass(classNode); } catch (GroovyRuntimeException rpe) { ASTNode node = rpe.getNode(); getErrorCollector().addError( new SyntaxException(rpe.getMessage(), null, node.getLineNumber(), node.getColumnNumber()), source ); } LabelVerifier lv = new LabelVerifier(source); lv.visitClass(classNode); ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source); completionVerifier.visitClass(classNode); ExtendedVerifier xverifier = new ExtendedVerifier(source); xverifier.visitClass(classNode); // because the class may be generated even if a error was found // and that class may have an invalid format we fail here if needed getErrorCollector().failIfErrors(); // // Prep the generator machinery // ClassVisitor visitor = createClassVisitor(); String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName()); // only show the file name and its extension like javac does in its stacktraces rather than the full path // also takes care of both \ and / depending on the host compiling environment if (sourceName != null) sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1); ClassGenerator generator = new AsmClassGenerator(source, context, visitor, sourceName); // // Run the generation and create the class (if required) // generator.visitClass(classNode); byte[] bytes = ((ClassWriter) visitor).toByteArray(); generatedClasses.add(new GroovyClass(classNode.getName(), bytes)); // // Handle any callback that's been set // if (CompilationUnit.this.classgenCallback != null) { classgenCallback.call(visitor, classNode); } // // Recurse for inner classes // LinkedList innerClasses = generator.getInnerClasses(); while (!innerClasses.isEmpty()) { classgen.call(source, context, (ClassNode) innerClasses.removeFirst()); } } }; protected ClassVisitor createClassVisitor() { return new ClassWriter(ClassWriter.COMPUTE_MAXS); } //--------------------------------------------------------------------------- // PHASE HANDLING /** * Updates the phase marker on all sources. */ protected void mark() throws CompilationFailedException { applyToSourceUnits(mark); } /** * Marks a single SourceUnit with the current phase, * if it isn't already there yet. */ private SourceUnitOperation mark = new SourceUnitOperation() { public void call(SourceUnit source) throws CompilationFailedException { if (source.phase < phase) { source.gotoPhase(phase); } if (source.phase == phase && phaseComplete && !source.phaseComplete) { source.completePhase(); } } }; //--------------------------------------------------------------------------- // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS /** * An callback interface for use in the applyToSourceUnits loop driver. */ public abstract static class SourceUnitOperation { public abstract void call(SourceUnit source) throws CompilationFailedException; } /** * A loop driver for applying operations to all SourceUnits. * Automatically skips units that have already been processed * through the current phase. */ public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException { for (String name : names) { SourceUnit source = sources.get(name); if ((source.phase < phase) || (source.phase == phase && !source.phaseComplete)) { try { body.call(source); } catch (CompilationFailedException e) { throw e; } catch (Exception e) { GroovyBugError gbe = new GroovyBugError(e); changeBugText(gbe, source); throw gbe; } catch (GroovyBugError e) { changeBugText(e, source); throw e; } } } getErrorCollector().failIfErrors(); } //--------------------------------------------------------------------------- // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS /** * An callback interface for use in the applyToSourceUnits loop driver. */ public abstract static class PrimaryClassNodeOperation { public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException; public boolean needSortedInput() { return false; } } public abstract static class GroovyClassOperation { public abstract void call(GroovyClass gclass) throws CompilationFailedException; } private int getSuperClassCount(ClassNode element) { int count = 0; while (element != null) { count++; element = element.getSuperClass(); } return count; } private int getSuperInterfaceCount(ClassNode element) { int count = 1; ClassNode[] interfaces = element.getInterfaces(); for (ClassNode anInterface : interfaces) { count = Math.max(count, getSuperInterfaceCount(anInterface) + 1); } return count; } private List getPrimaryClassNodes(boolean sort) { List<ClassNode> unsorted = new ArrayList(); for (ModuleNode module : this.ast.getModules()) { for (ClassNode classNode : module.getClasses()) { unsorted.add(classNode); } } if (!sort) return unsorted; int[] indexClass = new int[unsorted.size()]; int[] indexInterface = new int[unsorted.size()]; { int i = 0; for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) { ClassNode element = iter.next(); if (element.isInterface()) { indexInterface[i] = getSuperInterfaceCount(element); indexClass[i] = -1; } else { indexClass[i] = getSuperClassCount(element); indexInterface[i] = -1; } } } List<ClassNode> sorted = getSorted(indexInterface, unsorted); sorted.addAll(getSorted(indexClass, unsorted)); return sorted; } private List<ClassNode> getSorted(int[] index, List unsorted) { List<ClassNode> sorted = new ArrayList(unsorted.size()); for (int i = 0; i < unsorted.size(); i++) { int min = -1; for (int j = 0; j < unsorted.size(); j++) { if (index[j] == -1) continue; if (min == -1) { min = j; } else if (index[j] < index[min]) { min = j; } } if (min == -1) break; sorted.add(unsorted.get(min)); index[min] = -1; } return sorted; } /** * A loop driver for applying operations to all primary ClassNodes in * our AST. Automatically skips units that have already been processed * through the current phase. */ public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException { Iterator classNodes = getPrimaryClassNodes(body.needSortedInput()).iterator(); while (classNodes.hasNext()) { SourceUnit context = null; try { ClassNode classNode = (ClassNode) classNodes.next(); context = classNode.getModule().getContext(); if (context == null || context.phase < phase || (context.phase == phase && !context.phaseComplete)) { body.call(context, new GeneratorContext(this.ast), classNode); } } catch (CompilationFailedException e) { // fall through, getErrorReporter().failIfErrors() will trigger } catch (NullPointerException npe) { throw npe; } catch (GroovyBugError e) { changeBugText(e, context); throw e; } catch (Exception e) { // check the exception for a nested compilation exception ErrorCollector nestedCollector = null; for (Throwable next = e.getCause(); next != e && next != null; next = next.getCause()) { if (!(next instanceof MultipleCompilationErrorsException)) continue; MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next; nestedCollector = mcee.collector; break; } if (nestedCollector != null) { getErrorCollector().addCollectorContents(nestedCollector); } else { getErrorCollector().addError(new ExceptionMessage(e, configuration.getDebug(), this)); } } } getErrorCollector().failIfErrors(); } public void applyToGeneratedGroovyClasses(GroovyClassOperation body) throws CompilationFailedException { if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) { throw new GroovyBugError("CompilationUnit not ready for output(). Current phase=" + getPhaseDescription()); } for (GroovyClass gclass : this.generatedClasses) { // // Get the class and calculate its filesystem name // try { body.call(gclass); } catch (CompilationFailedException e) { // fall through, getErrorReporter().failIfErrors() will trigger } catch (NullPointerException npe) { throw npe; } catch (GroovyBugError e) { changeBugText(e, null); throw e; } catch (Exception e) { throw new GroovyBugError(e); } } getErrorCollector().failIfErrors(); } private void changeBugText(GroovyBugError e, SourceUnit context) { e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + ((context != null) ? context.getName() : "?") + "' " + e.getBugText()); } }

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy CompilationUnit.java source code file:

new blog posts

 

Copyright 1998-2014 Alvin Alexander, alvinalexander.com
All Rights Reserved.