diff options
author | paltherr <paltherr@epfl.ch> | 2005-01-03 12:40:31 +0000 |
---|---|---|
committer | paltherr <paltherr@epfl.ch> | 2005-01-03 12:40:31 +0000 |
commit | bd170a6e74e5f4965442a17dab98b46c938491ca (patch) | |
tree | e6983cb391671df0651b88b90b05de32a242ffb2 /sources/scalac | |
parent | 89d9f33d8fd4adea0d643c129b6600e31ca8c0e2 (diff) | |
download | scala-bd170a6e74e5f4965442a17dab98b46c938491ca.tar.gz scala-bd170a6e74e5f4965442a17dab98b46c938491ca.tar.bz2 scala-bd170a6e74e5f4965442a17dab98b46c938491ca.zip |
- Introduced new compilation loop
Diffstat (limited to 'sources/scalac')
-rw-r--r-- | sources/scalac/CompilationLoop.java | 143 | ||||
-rw-r--r-- | sources/scalac/Global.java | 46 | ||||
-rw-r--r-- | sources/scalac/typechecker/AnalyzerPhase.java | 2 |
3 files changed, 159 insertions, 32 deletions
diff --git a/sources/scalac/CompilationLoop.java b/sources/scalac/CompilationLoop.java new file mode 100644 index 0000000000..00cf6a576a --- /dev/null +++ b/sources/scalac/CompilationLoop.java @@ -0,0 +1,143 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac; + +import java.util.ArrayList; + +import scalac.util.Debug; + +/** This class implements the scalac compilation loop. */ +public class CompilationLoop { + + //######################################################################## + // Private Fields + + /** The global environment */ + private final Global global; + /** The list of active phases */ + private final Phase[] phases; + /** The units currently associated to each active phase. */ + private final ArrayList/*<CompilationUnit>*/[] unitss; + /** The indexes of the first units that are not yet processed. */ + private final int[] indexes; + + //######################################################################## + // Private Constructors + + /** Initializes this instance. */ + public CompilationLoop(Global global) { + this.global = global; + int count = 0; + for (Phase p = global.PHASE.INITIAL.phase(); p != null; p = p.next) + count++; + this.phases = new Phase[count]; + this.unitss = new ArrayList[count]; + this.indexes = new int[count]; + Phase phase = global.PHASE.INITIAL.phase(); + for (int i = 0; i < count; i++) { + phases[i] = phase; + unitss[i] = new ArrayList(); + phase = phase.next; + } + } + + //######################################################################## + // Public Methods + + /** + * Compiles the given units and returns list of all compiled units + * including those loaded automatically. + */ + public CompilationUnit[] compile(CompilationUnit[] units) { + for (int i = 0; i < units.length; i++) unitss[0].add(units[i]); + int limit = phases.length - 1; + loop(limit, true); + return global.reporter.errors() != 0 + ? new CompilationUnit[0] + : (CompilationUnit[])unitss[limit].toArray( + new CompilationUnit[unitss[limit].size()]); + } + + /** + * Inserts the given unit and compiles it up to the current phase + * excluded. + */ + public void insert(CompilationUnit unit) { + Phase backup = global.currentPhase; + unitss[0].add(unit); + // !!! This "false" may be dangerous; it may lead to crashes + // because phases might work on trees/symbol-tables that + // contain errors (however this occurs only if the newly + // loaded code may contain errors). On the other hand "true", + // might starve some phases; if a phase requests a compilation + // unit, it may never receive it. + loop(getPhaseIndex(backup), false); + global.currentPhase = backup; + } + + //######################################################################## + // Private Methods + + /** Compiles all units up to phase "phases[limit]" excluded. */ + private void loop(int limit, boolean main) { + assert limit < phases.length: Debug.show(""+limit, phases); + for (int current = getFirstNonEmptyIndex(); current < limit; ) { + // !!! remove NAMER test ? + if (main && global.reporter.errors() != 0 + && global.currentPhase != global.PHASE.NAMER.phase()) break; + // Update the current phase pointer. + Phase phase = global.currentPhase = phases[current]; + // If the phase is not yet started, start it. + if (indexes[current] == 0) global.start(); + // Apply the phase to all available units. It's important + // to not cache the result of "size()" as new units may be + // added during the loop. + for (int i = indexes[current]; i < unitss[current].size(); i++) + phase.apply((CompilationUnit)unitss[current].get(i)); + int next = getFirstNonEmptyIndex(); + // If no new units were introduced, stop the phase. + if (next == current) { + PhaseDescriptor descriptor = phase.descriptor; + global.stop(descriptor.taskDescription()); + CompilationUnit[] units = + (CompilationUnit[])unitss[current].toArray( + new CompilationUnit[unitss[current].size()]); + if (descriptor.hasPrintFlag()) global.print(units); + // if (descriptor.hasGraphFlag()); // !!! + // if (descriptor.hasCheckFlag()); // !!! + if (phase == global.PHASE.PARSER.phase()) global.fix1(units); + if (phase == global.PHASE.ANALYZER.phase()) global.fix2(units); + unitss[current + 1].addAll(unitss[current]); + unitss[current].clear(); + next++; + } + indexes[current] = unitss[current].size(); + current = next; + } + } + + /** + * Returns the first index with a non-empty unit list. If there is + * no such index, returns "phases.length". + */ + private int getFirstNonEmptyIndex() { + int index = 0; + while (index < phases.length && unitss[index].isEmpty()) index++; + return index; + } + + /** Returns the index of the given phase. */ + private int getPhaseIndex(Phase phase) { + for (int index = 0; index < phases.length; index++) + if (phases[index] == phase) return index; + throw Debug.abort("phase not found", Debug.show(phase, phases)); + } + + //######################################################################## +} diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index 426f59af59..b6c039c495 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -157,6 +157,9 @@ public abstract class Global { */ public final CompilerPhases PHASE; + /** The current compilation loop or null */ + private CompilationLoop loop; + /** compilation targets */ public static final String TARGET_INT; @@ -381,26 +384,12 @@ public abstract class Global { /** compile all compilation units */ private CompilationUnit[] compile(CompilationUnit[] units) { + this.currentPhase = PHASE.INITIAL.phase(); treePrinter.begin(); - - currentPhase = PHASE.INITIAL.phase(); - // apply successive phases and pray that it works - // !!! remove NAMER test ? - while (currentPhase.next != null && ((currentPhase == PHASE.NAMER.phase()) || (reporter.errors() == 0))) { - currentPhase = currentPhase.next; - start(); - // System.out.println("*** " + currentPhase.descriptor.description() + " ***"); - for (int i = 0; i < units.length; i++) - currentPhase.apply(units[i]); - if (currentPhase == PHASE.ANALYZER.phase()) - units = ((AnalyzerPhase)currentPhase).getUnits(); - stop(currentPhase.descriptor.taskDescription()); - if (currentPhase.descriptor.hasPrintFlag()) print(units); - // if (currentPhase.descriptor.hasGraphFlag()) // !!! - // if (currentPhase.descriptor.hasCheckFlag()) // !!! - if (currentPhase == PHASE.PARSER.phase()) fix1(units); - if (currentPhase == PHASE.ANALYZER.phase()) fix2(units); - } + this.loop = new CompilationLoop(this); + loadFunctions(); + units = loop.compile(units); + this.loop = null; if (reporter.errors() != 0) { imports.clear(); for (Iterator i = compiledNow.entrySet().iterator(); i.hasNext();) { @@ -412,28 +401,25 @@ public abstract class Global { } compiledNow.clear(); treePrinter.end(); + this.currentPhase = PHASE.TERMINAL.phase(); return units; } + protected abstract void loadFunctions(); + /** Compiles an additional source file. */ public void compileLate(SourceFile source, boolean mixinOnly) { + assert loop != null: source; if (!compiledUnits.contains(source)) { compiledUnits.add(source); CompilationUnit unit = new CompilationUnit(this, source, false, mixinOnly); - Phase backup = currentPhase; - // !!! add code to print/skip/graph as in compile - currentPhase = PHASE.PARSER.phase(); - PHASE.PARSER.phase().apply(unit); - currentPhase = PHASE.NAMER.phase(); - PHASE.NAMER.phase().apply(unit); - // !!! add code for later phases? - currentPhase = backup; + loop.insert(unit); } } public abstract void dump(CompilationUnit[] units); - private void print(CompilationUnit[] units) { + void print(CompilationUnit[] units) { if (currentPhase.id == PHASE.MAKEBOXINGEXPLICIT.id()) { boolean html = args.printer.value.equals(PRINTER_HTML); if (html) writer.println("<pre>"); @@ -503,7 +489,7 @@ public abstract class Global { private List imports = new ArrayList(); public Symbol console; - private void fix1(CompilationUnit[] units) { + void fix1(CompilationUnit[] units) { for (int i = 0; i < units.length; i++) { if (units[i].console) fix1(units[i]); } @@ -529,7 +515,7 @@ public abstract class Global { module++; } - private void fix2(CompilationUnit[] units) { + void fix2(CompilationUnit[] units) { for (int i = 0; i < units.length; i++) { if (units[i].console) fix2(units[i]); } diff --git a/sources/scalac/typechecker/AnalyzerPhase.java b/sources/scalac/typechecker/AnalyzerPhase.java index 0939806844..de47aae6c2 100644 --- a/sources/scalac/typechecker/AnalyzerPhase.java +++ b/sources/scalac/typechecker/AnalyzerPhase.java @@ -29,6 +29,4 @@ public abstract class AnalyzerPhase extends Phase { public abstract void addConsoleImport(Symbol module); - public abstract CompilationUnit[] getUnits(); - } |