compilationunit.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 1,012 行 · 第 1/3 页
JAVA
1,012 行
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()));
}
/**
* Adds a SourceUnit to the unit.
*/
public SourceUnit addSource(SourceUnit source) {
String name = source.getName();
source.setClassLoader(this.classLoader);
for (Iterator iter = queuedSources.iterator(); iter.hasNext();) {
SourceUnit su = (SourceUnit) iter.next();
if (name.equals(su.getName())) return su;
}
queuedSources.add(source);
return source;
}
/**
* Returns an iterator on the unit's SourceUnits.
*/
public Iterator iterator() {
return new Iterator() {
Iterator nameIterator = names.iterator();
public boolean hasNext() {
return nameIterator.hasNext();
}
public Object next() {
String name = (String) 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 static abstract 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 static abstract 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) {
for (Iterator it = phaseOperations[phase].iterator(); it.hasNext();) {
Object operation = it.next();
if (operation instanceof PrimaryClassNodeOperation) {
applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
} else if (operation instanceof SourceUnitOperation) {
applyToSourceUnits((SourceUnitOperation)operation);
} else {
applyToGeneratedGroovyClasses((GroovyClassOperation)operation);
}
}
if (dequeued()) continue;
if (progressCallback != null) progressCallback.call(this, phase);
completePhase();
applyToSourceUnits(mark);
gotoPhase(phase+1);
if (phase==Phases.CLASS_GENERATION) {
sortClasses();
}
}
errorCollector.failIfErrors();
}
private void sortClasses() throws CompilationFailedException {
Iterator modules = this.ast.getModules().iterator();
while (modules.hasNext()) {
ModuleNode module = (ModuleNode) modules.next();
// before we actually do the sorting we should check
// for cyclic references
List classes = module.getClasses();
for (Iterator iter = classes.iterator(); iter.hasNext();) {
ClassNode start = (ClassNode) iter.next();
ClassNode cn = start;
HashSet parents = new HashSet();
do {
if (parents.contains(cn.getName())) {
getErrorCollector().addErrorAndContinue(
new SimpleMessage("cyclic inheritance involving "+cn.getName()+" in class "+start.getName(),this)
);
cn=null;
} else {
parents.add(cn.getName());
cn = cn.getSuperClass();
}
} while (cn!=null);
}
errorCollector.failIfErrors();
module.sortClasses();
}
}
/**
* Dequeues any source units add through addSource and resets the compiler phase
* to initialization.
*
* Note: this does not mean a file is recompiled. If a SoucreUnit has already passed
* a phase it is skipped until a higher phase is reached.
* @return TODO
*
* @throws CompilationFailedException
*/
protected boolean dequeued() throws CompilationFailedException {
boolean dequeue = !queuedSources.isEmpty();
while (!queuedSources.isEmpty()) {
SourceUnit su = (SourceUnit) queuedSources.removeFirst();
String name = su.getName();
names.add(name);
sources.put(name,su);
}
if (dequeue) {
gotoPhase(Phases.INITIALIZATION);
}
return dequeue;
}
/**
* Adds summary of each class to maps
*/
private SourceUnitOperation summarize = new SourceUnitOperation() {
public void call(SourceUnit source) throws CompilationFailedException {
SourceSummary sourceSummary = source.getSourceSummary();
if (sourceSummary != null) {
summariesBySourceName.put(source.getName(),sourceSummary);
List publicClassSources = sourceSummary.getPublicClassSources();
if (publicClassSources == null || publicClassSources.size() == 0) {
//todo - is this the best way to handle scripts?
summariesByPublicClassName.put("*NoName*",sourceSummary);
// nothing to put into classSourcesByClassName as no ClassSource
} else {
Iterator itr = publicClassSources.iterator();
while (itr.hasNext()) {
ClassSource classSource = (ClassSource)itr.next();
summariesByPublicClassName.put(classSource.getName(),sourceSummary);
classSourcesByPublicClassName.put(classSource.getName(),classSource);
}
}
}
}
};
/**
* Resolves all types
*/
private SourceUnitOperation resolve = new SourceUnitOperation() {
public void call(SourceUnit source) throws CompilationFailedException {
List classes = source.ast.getClasses();
for (Iterator it = classes.iterator(); it.hasNext();) {
ClassNode node = (ClassNode) it.next();
VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
scopeVisitor.visitClass(node);
resolveVisitor.startResolving(node,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 {
boolean failures = false;
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));
failures = true;
} finally {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
}
}
}
}
};
/* checks if all needed classes are compiled before generating the bytecode */
private SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() {
public void call(SourceUnit source) throws CompilationFailedException {
List classes = source.ast.getClasses();
for (Iterator it = classes.iterator(); it.hasNext();) {
ClassNode node = (ClassNode) it.next();
CompileUnit cu = node.getCompileUnit();
for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext();) {
String name = (String) iter.next();
SourceUnit su = ast.getScriptSourceLocation(name);
List 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.size()==0) {
message.append(", but the file seems not to contain any classes");
} else {
message.append(", but the file contains the classes: ");
boolean first = true;
for (Iterator suClassesIter = classesInSourceUnit
.iterator(); suClassesIter.hasNext();) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?