summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-05-26 14:19:52 +0000
committerMartin Odersky <odersky@gmail.com>2009-05-26 14:19:52 +0000
commitd73a2965746b3cc0bdeb3f96fed342143deae210 (patch)
treee654bb6a634acf932cecf5e1f55040a68edaf0cd /src/compiler
parent0b8ece795b13f651c42b5c01936bebb4312efe5f (diff)
downloadscala-d73a2965746b3cc0bdeb3f96fed342143deae210.tar.gz
scala-d73a2965746b3cc0bdeb3f96fed342143deae210.tar.bz2
scala-d73a2965746b3cc0bdeb3f96fed342143deae210.zip
added Synthetic Positions; refactored interacti...
added Synthetic Positions; refactored interactive.Global
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala20
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Parsers.scala24
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala90
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/ContextTrees.scala3
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Global.scala112
-rw-r--r--src/compiler/scala/tools/nsc/interactive/REPL.scala72
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala29
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala13
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala22
10 files changed, 253 insertions, 133 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 0257faae88..0f08598157 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -812,15 +812,14 @@ trait Trees {
* <code>RefCheck</code>, where the arbitrary type trees are all replaced by
* TypeTree's. */
case class TypeTree() extends TypTree {
- var original: Tree = _
-
override def symbol = if (tpe == null) null else tpe.typeSymbol
def setOriginal(tree: Tree): this.type = {
- original = tree
- setPos(tree.pos)
+ setPos(SyntheticPosition(tree))
}
+ def original: Tree = pos.asInstanceOf[SyntheticPosition].original
+
override def isEmpty = (tpe eq null) || tpe == NoType
}
@@ -1773,5 +1772,18 @@ trait Trees {
def isTop : Boolean
}
+ /** A position to be used for synthetic trees that correspond to some original tree
+ * @note Trees with synthetic positions may not contain trees with real positions inside them!
+ */
+ case class SyntheticPosition(original: Tree) extends Position {
+ override def isDefined: Boolean = true
+ override def isSynthetic: Boolean = true
+ override def offset: Option[Int] = original.pos.offset
+ override def source: Option[SourceFile] = original.pos.source
+ override def start: Int = original.pos.start
+ override def point: Int = original.pos.point
+ override def end: Int = original.pos.end
+ override def underlying = original.pos.underlying
+ }
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index abe7c1f951..0aa4907fc6 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -378,10 +378,10 @@ self =>
def atPos[T <: Tree](offset: Int)(t: T): T =
posAssigner.atPos(r2p(offset, offset, in.lastOffset))(t)
- def atPos[T <: Tree](start: Int, mid: Int)(t: T): T =
- posAssigner.atPos(r2p(start, mid, in.lastOffset))(t)
- def atPos[T <: Tree](start: Int, mid: Int, end: Int)(t: T): T =
- posAssigner.atPos(r2p(start, mid, end))(t)
+ def atPos[T <: Tree](start: Int, point: Int)(t: T): T =
+ posAssigner.atPos(r2p(start, point, in.lastOffset))(t)
+ def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T =
+ posAssigner.atPos(r2p(start, point, end))(t)
def atPos[T <: Tree](pos: Position)(t: T): T =
posAssigner.atPos(pos)(t)
@@ -498,8 +498,8 @@ self =>
}
def selector(t: Tree): Tree = {
- val mid = in.offset
- Select(t, ident()) setPos r2p(t.pos.start, mid, in.lastOffset)
+ val point = in.offset
+ Select(t, ident()) setPos r2p(t.pos.start, point, in.lastOffset)
}
/** Path ::= StableId
@@ -1281,16 +1281,16 @@ self =>
val start = in.offset
if (in.token == VAL) in.nextToken()
val pat = pattern1(false)
- val mid = in.offset
+ val point = in.offset
val tok = in.token
if (tok == EQUALS && eqOK) in.nextToken()
else accept(LARROW)
val rhs = expr()
- enums += makeGenerator(r2p(start, mid, in.lastOffset), pat, tok == EQUALS, rhs)
+ enums += makeGenerator(r2p(start, point, in.lastOffset), pat, tok == EQUALS, rhs)
if (in.token == IF) enums += makeFilter(in.offset, guard())
}
- def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.mid, tree.pos.end), tree)
+ def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.end), tree)
/* -------- PATTERNS ------------------------------------------- */
@@ -1715,7 +1715,7 @@ self =>
val t = typ()
if (isIdent && in.name == STAR) {
in.nextToken()
- atPos(t.pos.start, t.pos.mid) {
+ atPos(t.pos.start, t.pos.point) {
AppliedTypeTree(
rootScalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t))
}
@@ -1947,7 +1947,7 @@ self =>
//Console.println("DEBUG: p = "+p.toString()); // DEBUG
val trees =
makePatDef(newmods, if (tp.isEmpty) p else Typed(p, tp), rhs) map
- atPos(p.pos.start, p.pos.mid)
+ atPos(p.pos.start, p.pos.point)
rhs = rhs.duplicate
if (newmods hasFlag Flags.DEFERRED) {
trees match {
@@ -2283,7 +2283,7 @@ self =>
/** Create a tree representing a packaging */
def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef =
- atPos(start, pkg.pos.mid) {
+ atPos(start, pkg.pos.point) {
pkg match {
case Ident(name) =>
PackageDef(name, stats)
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
new file mode 100644
index 0000000000..f55195973e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
@@ -0,0 +1,90 @@
+package scala.tools.nsc.interactive
+
+import scala.concurrent.SyncVar
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.util.{SourceFile, Position, WorkScheduler}
+import scala.tools.nsc.symtab._
+import scala.tools.nsc.ast._
+
+/** Interface of interactive compiler to a client such as an IDE
+ */
+trait CompilerControl { self: Global =>
+
+ /* Must be initialized before starting compilerRunner */
+ protected val scheduler = new WorkScheduler
+
+ /** The compilation unit corresponding to a source file */
+ def unitOf(s: SourceFile): RichCompilationUnit = unitOfFile get s.file match {
+ case Some(unit) =>
+ unit
+ case None =>
+ val unit = new RichCompilationUnit(s)
+ unitOfFile(s.file) = unit
+ unit
+ }
+
+ /** The compilation unit corresponding to a position */
+ def unitOf(pos: Position): RichCompilationUnit = unitOf(pos.source.get)
+
+ /** Locate smallest tree that encloses position */
+ def locateTree(pos: Position): Tree =
+ new Locator(pos) locateIn unitOf(pos).body
+
+ /** Locate smallest context that encloses position */
+ def locateContext(pos: Position): Option[Context] =
+ locateContext(unitOf(pos).contexts, pos)
+
+ /** Make sure a set of compilation units is loaded and parsed */
+ def askReload(sources: List[SourceFile], result: SyncVar[Either[Unit, Throwable]]) =
+ scheduler.postWorkItem(() => reload(sources, result))
+
+ /** Set sync var `result` to a fully attributed tree located at position `pos` */
+ def askTypeAt(pos: Position, result: SyncVar[Either[Tree, Throwable]]) =
+ scheduler.postWorkItem(() => self.typedTreeAt(pos, result))
+
+ /** Ask to do unit first on present and subsequent type checking passes */
+ def askToDoFirst(f: SourceFile) = {
+ scheduler.postWorkItem { () => moveToFront(List(f)) }
+ }
+
+ /** Cancel currently pending high-priority jobs */
+ def askCancel() =
+ scheduler.raise(new CancelActionReq)
+
+ /** Cancel current compiler run and start a fresh one where everything will be re-typechecked
+ * (but not re-loaded).
+ */
+ def askReset() =
+ scheduler.raise(new FreshRunReq)
+
+ /** Tell the compile server to shutdown, and do not restart again */
+ def askShutdown() =
+ scheduler.raise(new ShutdownReq)
+
+ // ---------------- Interpreted exeptions -------------------
+
+ class CancelActionReq extends Exception
+ class FreshRunReq extends Exception
+ class ShutdownReq extends Exception
+
+ // ---------------- Helper class -----------------------------
+
+ /** A locator for trees with given positions.
+ * Given a position `pos`, locator.apply returns
+ * the smallest tree that encloses `pos`.
+ */
+ private class Locator(pos: Position) extends Traverser {
+ var last: Tree = _
+ def locateIn(root: Tree): Tree = {
+ this.last = EmptyTree
+ traverse(root)
+ this.last
+ }
+ override def traverse(t: Tree) {
+ if (!t.pos.isSynthetic && (t.pos includes pos)) {
+ last = t
+ super.traverse(t)
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala
index ade9d7e792..8f8470ae2d 100755
--- a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala
+++ b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala
@@ -39,7 +39,8 @@ trait ContextTrees { self: Global =>
def addContext(contexts: Contexts, context: Context) {
val cpos = context.tree.pos
- if (contexts.isEmpty) contexts += new ContextTree(context)
+ if (!cpos.isDefined || cpos.isSynthetic) {}
+ else if (contexts.isEmpty) contexts += new ContextTree(context)
else {
val hi = contexts.length - 1
if (contexts(hi).pos precedes cpos)
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index ad141175ff..16af234d48 100755
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -1,6 +1,6 @@
package scala.tools.nsc.interactive
-import scala.collection.mutable.{LinkedHashSet, LinkedHashMap, SynchronizedMap}
+import scala.collection.mutable.{LinkedHashMap, SynchronizedMap}
import scala.concurrent.SyncVar
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.util.{SourceFile, Position, RangePosition, OffsetPosition, NoPosition, WorkScheduler}
@@ -11,7 +11,7 @@ import scala.tools.nsc.ast._
/** The main class of the presentation compiler in an interactive environment such as an IDE
*/
class Global(settings: Settings, reporter: Reporter)
- extends nsc.Global(settings, reporter) with ContextTrees {
+ extends nsc.Global(settings, reporter) with CompilerControl with ContextTrees with RichCompilationUnits {
self =>
/** A list indicating in which order some units should be typechecked.
@@ -43,8 +43,8 @@ self =>
// ----------- Overriding hooks in nsc.Global -----------------------
/** Create a RangePosition */
- override def rangePos(source: SourceFile, start: Int, mid: Int, end: Int) =
- new RangePosition(source, start, mid, end)
+ override def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
+ new RangePosition(source, start, point, end)
/** Called from typechecker: signal that a node has been completely typechecked
* @param context The context that typechecked the node
@@ -85,7 +85,7 @@ self =>
scheduler.pollException() match {
case Some(ex: CancelActionReq) => if (acting) throw ex
case Some(ex: FreshRunReq) => if (compiling) throw ex
- case Some(ex) => throw ex
+ case Some(ex: Throwable) => throw ex
case _ =>
}
scheduler.nextWorkItem() match {
@@ -104,9 +104,6 @@ self =>
// ----------------- The Background Runner Thread -----------------------
- /* Must be initialized before starting compilerRunner */
- private val scheduler = new WorkScheduler
-
/** The current presentation compiler runner */
private var compileRunner = newRunnerThread
@@ -220,25 +217,6 @@ self =>
// ---------------- Helper classes ---------------------------
- /** A locator for trees with given positions.
- * Given a position `pos`, locator.apply returns
- * the smallest tree that encloses `pos`.
- */
- class Locator(pos: Position) extends Traverser {
- var last: Tree = _
- def locateIn(root: Tree): Tree = {
- this.last = EmptyTree
- traverse(root)
- this.last
- }
- override def traverse(t: Tree) {
- if (t.pos includes pos) {
- last = t
- super.traverse(t)
- }
- }
- }
-
/** A transformer that replaces tree `from` with tree `to` in a given tree */
class TreeReplacer(from: Tree, to: Tree) extends Transformer {
override def transform(t: Tree): Tree = {
@@ -254,6 +232,10 @@ self =>
object ResetAttrs extends Traverser {
override def traverse(t: Tree) {
if (t.hasSymbol) t.symbol = NoSymbol
+ t match {
+ case EmptyTree => ;
+ }
+
t.tpe = null
super.traverse(t)
}
@@ -306,83 +288,7 @@ self =>
class TyperResult(val tree: Tree) extends Exception
- class RichCompilationUnit(source: SourceFile) extends CompilationUnit(source) {
-
- /** The runid of the latest compiler run that typechecked this unit,
- * or else @see NotLoaded, JustParsed
- */
- var status: Int = NotLoaded
-
- /** the current edit point offset */
- var editPoint: Int = -1
-
- /** The position of a targeted type check
- * If this is different from NoPosition, the type checking
- * will stop once a tree that contains this position range
- * is fully attributed.
- */
- var _targetPos: Position = NoPosition
- override def targetPos: Position = _targetPos
- def targetPos_=(p: Position) { _targetPos = p }
-
- var contexts: Contexts = new Contexts
-
- }
-
assert(globalPhase.id == 0)
- // ----------------- interface to IDE ------------------------------------
-
- /** The compilation unit corresponding to a source file */
- def unitOf(s: SourceFile): RichCompilationUnit = unitOfFile get s.file match {
- case Some(unit) =>
- unit
- case None =>
- val unit = new RichCompilationUnit(s)
- unitOfFile(s.file) = unit
- unit
- }
-
- /** The compilation unit corresponding to a position */
- def unitOf(pos: Position): RichCompilationUnit = unitOf(pos.source.get)
-
- /** Locate smallest tree that encloses position */
- def locateTree(pos: Position): Tree =
- new Locator(pos) locateIn unitOf(pos).body
-
- /** Locate smallest context that encloses position */
- def locateContext(pos: Position): Option[Context] =
- locateContext(unitOf(pos).contexts, pos)
-
- /** Make sure a set of compilation units is loaded and parsed */
- def askReload(sources: List[SourceFile], result: SyncVar[Either[Unit, Throwable]]) =
- scheduler.postWorkItem(() => reload(sources, result))
-
- /** Set sync var `result` to a fully attributed tree located at position `pos` */
- def askTypeAt(pos: Position, result: SyncVar[Either[Tree, Throwable]]) =
- scheduler.postWorkItem(() => self.typedTreeAt(pos, result))
-
- /** Ask to do unit first on present and subsequent type checking passes */
- def askToDoFirst(f: SourceFile) = {
- scheduler.postWorkItem { () => moveToFront(List(f)) }
- }
-
- /** Cancel currently pending high-priority jobs */
- def askCancel() =
- scheduler.raise(new CancelActionReq)
-
- /** Cancel current compiler run and start a fresh one where everything will be re-typechecked
- * (but not re-loaded).
- */
- def askReset() =
- scheduler.raise(new FreshRunReq)
-
- /** Tell the compile server to shutdown, and do not restart again */
- def askShutdown() =
- scheduler.raise(new ShutdownReq)
-
- class CancelActionReq extends Exception
- class FreshRunReq extends Exception
- class ShutdownReq extends Exception
}
diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala
new file mode 100644
index 0000000000..cd83ddf082
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala
@@ -0,0 +1,72 @@
+package scala.tools.nsc.interactive
+
+import scala.concurrent.SyncVar
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.util.{SourceFile, Position, WorkScheduler}
+import scala.tools.nsc.symtab._
+import scala.tools.nsc.ast._
+
+/** Interface of interactive compiler to a client such as an IDE
+ */
+object REPL /* extends EvalLoop */ {
+}
+
+ /** Commands:
+ *
+ * reload file1 ... fileN
+ * typeat file line col
+ *
+ *
+ def run() {
+ loop { line =>
+
+
+ }
+
+ def process(args: Array[String]) {
+ val settings = new Settings(error)
+ reporter = new ConsoleReporter(settings)
+ val command = new CompilerCommand(List.fromArray(args), settings, error, false)
+ if (command.settings.version.value)
+ reporter.info(null, versionMsg, true)
+ else {
+ if (command.settings.target.value == "msil") {
+ val libpath = System.getProperty("msil.libpath")
+ if (libpath != null)
+ command.settings.assemrefs.value =
+ command.settings.assemrefs.value + File.pathSeparator + libpath
+ }
+ try {
+ object compiler extends Global(command.settings, reporter)
+ if (reporter.hasErrors) {
+ reporter.flush()
+ return
+ }
+
+ if (command.shouldStopWithInfo) {
+ reporter.info(null, command.getInfoMessage(compiler), true)
+ } else {
+ if (command.settings.resident.value)
+ resident(compiler)
+ else if (command.files.isEmpty) {
+ reporter.info(null, command.usageMsg, true)
+ reporter.info(null, compiler.pluginOptionsHelp, true)
+ } else {
+ val run = new compiler.Run()
+ run compile command.files
+ reporter.printSummary()
+ }
+ }
+ } catch {
+ case ex @ FatalError(msg) =>
+ if (true || command.settings.debug.value) // !!!
+ ex.printStackTrace();
+ reporter.error(null, "fatal error: " + msg)
+ }
+ }
+ }
+ val comp = new Global
+
+
+ def
+ */
diff --git a/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala b/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala
new file mode 100644
index 0000000000..b8b59b67ae
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/RichCompilationUnits.scala
@@ -0,0 +1,29 @@
+package scala.tools.nsc.interactive
+
+import scala.tools.nsc.util.{SourceFile, Position, NoPosition}
+
+trait RichCompilationUnits { self: Global =>
+
+ class RichCompilationUnit(source: SourceFile) extends CompilationUnit(source) {
+
+ /** The runid of the latest compiler run that typechecked this unit,
+ * or else @see NotLoaded, JustParsed
+ */
+ var status: Int = NotLoaded
+
+ /** the current edit point offset */
+ var editPoint: Int = -1
+
+ /** The position of a targeted type check
+ * If this is different from NoPosition, the type checking
+ * will stop once a tree that contains this position range
+ * is fully attributed.
+ */
+ var _targetPos: Position = NoPosition
+ override def targetPos: Position = _targetPos
+ def targetPos_=(p: Position) { _targetPos = p }
+
+ var contexts: Contexts = new Contexts
+
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 6bba3e74bf..6411ddf532 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -820,6 +820,7 @@ trait Types {
trait UniqueType {
override lazy val hashCode: Int = super.hashCode()
}
+
/** A base class for types that defer some operations
* to their immediate supertype.
*/
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7dc60b91dc..89e2028ded 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3412,10 +3412,15 @@ trait Typers { self: Analyzer =>
newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt, mode)
case TypeTree() =>
- // we should get here only when something before failed
- // and we try again (@see tryTypedApply). In that case we can assign
- // whatever type to tree; we just have to survive until a real error message is issued.
- tree setType AnyClass.tpe
+ tree.pos match {
+ case SyntheticPosition(original) =>
+ tree setType typedType(original, mode).tpe
+ case _ =>
+ // we should get here only when something before failed
+ // and we try again (@see tryTypedApply). In that case we can assign
+ // whatever type to tree; we just have to survive until a real error message is issued.
+ tree setType AnyClass.tpe
+ }
case _ =>
throw new Error("unexpected tree: " + tree.getClass + "\n" + tree)//debug
}
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index 6d494d5c3f..a62974c426 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -16,14 +16,17 @@ trait Position {
def offset: Option[Int] = None
def source: Option[SourceFile] = None
def isDefined: Boolean = false
+ def isSynthetic: Boolean = false
- def start: Int = mid
- def mid: Int = offset.get
- def end: Int = mid
+ def start: Int = point
+ def point: Int = offset.get
+ def end: Int = point
- def startOrElse(d: Int) = offset.get//OrElse(d)
- def midOrElse(d: Int) = offset.get//OrElse(d)
- def endOrElse(d: Int) = offset.get//OrElse(d)
+ def startOrElse(d: Int) = offset.getOrElse(d)
+ def pointOrElse(d: Int) = offset.getOrElse(d)
+ def endOrElse(d: Int) = offset.getOrElse(d)
+
+ def underlying = this
def includes(pos: Position) =
isDefined && pos.isDefined && start <= pos.start && pos.end <= end
@@ -105,12 +108,13 @@ case class OffsetPosition(source0: SourceFile, offset0: Int) extends Position {
}
/** new for position ranges */
-class RangePosition(source0: SourceFile, override val start: Int, override val mid: Int, override val end: Int)
-extends OffsetPosition(source0, mid) {
+class RangePosition(source0: SourceFile, override val start: Int, override val point: Int, override val end: Int)
+extends OffsetPosition(source0, point) {
override def isDefined = true
override def startOrElse(d: Int) = start
- override def midOrElse(d: Int) = mid
+ override def pointOrElse(d: Int) = point
override def endOrElse(d: Int) = end
}
+