|
|
/* ____ ____ ____ ____ ______ *\
** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
** /_____/\____/\___/\____/____/ **
\* */
// $Id$
package scalac.symtab;
import java.io.IOException;
import scalac.Global;
import scalac.Phase;
import scalac.symtab.Symbol;
import scalac.symtab.Type;
import scalac.util.Debug;
/**
* This class implements common behaviors of lazy types used to load
* symbols from external sources (containing source or compiled code).
*/
public abstract class SymbolLoader extends Type.LazyType {
//########################################################################
// Public Fields
/** The global environment */
public final Global global;
//########################################################################
// Public Constructors
/** Initializes this instance. */
public SymbolLoader(Global global) {
this.global = global;
}
//########################################################################
// Public Methods
/**
* Completes the specified symbol. More precisely, it completes
* all symbols related to the root symbol of the specified
* symbol. It is guaranteed that after this method call all these
* symbols are initialized (or at least that their info does no
* longer contain this lazy type).
*
* The root symbol of a symbol is:
* - the root symbol of the constructed class, if it's a
* constructor,
* - the root symbol of the source module, if it's a module class,
* - the linked class, if it's a module with a linked class,
* - itself if it's a class or a module with no linked class,
* - undefined otherwise.
*
* The symbols related to a symbol include:
* - the symbol itself,
* - its constructor (allConstructors()), if it's a class,
* - the symbols related to its linked module, if there is one.
* - the symbols related to its module class, if it's a module,
*/
public final void complete(Symbol symbol) {
Symbol root = getRootSymbol(symbol);
try {
long start = System.currentTimeMillis();
Phase phase = global.currentPhase;
global.currentPhase = global.PHASE.ANALYZER.phase();
String source = doComplete(root);
global.currentPhase = phase;
long end = System.currentTimeMillis();
global.operation("loaded " + source + " in " + (end-start) + "ms");
checkValidity(root, source);
} catch (IOException exception) {
if (global.debug) exception.printStackTrace();
String error = "error while loading " + symbol;
String message = exception.getMessage();
error = message != null ? error + ", " + message : "i/o " + error;
global.error(error);
}
initializeRoot(root);
}
//########################################################################
// Protected Methods
/**
* Performs the actual loading and returns the name of the
* external source. It is guaranteed that the argument of this
* method is always a root symbol
*
* @see complete(Symbol)
*/
protected abstract String doComplete(Symbol root) throws IOException;
//########################################################################
// Private Methods
/**
* Returns the root symbol of the specified symbol.
*
* @see complete(Symbol)
*/
private Symbol getRootSymbol(Symbol symbol) {
if (symbol.isConstructor())
return getRootSymbol(symbol.constructorClass());
if (symbol.isModuleClass())
return getRootSymbol(symbol.sourceModule());
if (symbol.isModule() && symbol.linkedClass() != null)
return symbol.linkedClass();
assert symbol.isClassType() || symbol.isModule(): Debug.show(symbol);
return symbol;
}
/**
* Checks that at least the specified root symbol or its linked
* module, if any, has been initialized and signals an error
* otherwise.
*
* @see complete(Symbol)
*/
private void checkValidity(Symbol root, String source) {
if (root.rawInfo() != this) return;
String what;
if (!root.isClassType() || root.linkedModule() == null) {
what = "does not define " + root;
} else {
if (root.linkedModule().moduleClass().rawInfo() != this) return;
what = "defines neither " + root + " nor " + root.linkedModule();
}
global.error(source + " " + what);
}
/**
* Initializes all symbols related to the specified root symbol
* and whose info is this instance.
*
* @see complete(Symbol)
*/
private void initializeRoot(Symbol root) {
if (root.isClassType()) {
initializeClass(root);
if (root.linkedModule() != null)
initializeRoot(root.linkedModule());
} else {
initializeSymbol(root);
if (root.isModule()) initializeClass(root.moduleClass());
}
}
/**
* Initializes the specified class and its constructor if their
* info is this instance.
*/
private void initializeClass(Symbol clasz) {
initializeSymbol(clasz);
initializeSymbol(clasz.allConstructors());
}
/** Initializes the symbol if its info is this instance. */
private void initializeSymbol(Symbol symbol) {
if (symbol.rawInfo() != this) return;
symbol.setInfo(symbol.isModule() ? Type.NoType : Type.ErrorType);
if (symbol.isConstructor()) symbol.flags |= Modifiers.PRIVATE;
}
//########################################################################
}
|