summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-03-04 14:47:01 -0800
committerPaul Phillips <paulp@improving.org>2013-03-04 14:48:07 -0800
commitdc1cd96ffd44ddd47ea1d5be88b4b9e438bd9c3b (patch)
treef364545f8be08dba80fc8a9ce570ea48ca8270d1
parent8dc1bc78ca57876085bb3b384b002dd29bc0e5fe (diff)
downloadscala-dc1cd96ffd44ddd47ea1d5be88b4b9e438bd9c3b.tar.gz
scala-dc1cd96ffd44ddd47ea1d5be88b4b9e438bd9c3b.tar.bz2
scala-dc1cd96ffd44ddd47ea1d5be88b4b9e438bd9c3b.zip
Disentangled RangePositions from interactive.
This is a stepping stone to having range positions all the time, as well as to modularizing the presentation compiler. It does not enable range positions by default, only places them smoewhere where they can be.
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala6
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala7
-rw-r--r--src/compiler/scala/tools/nsc/Main.scala52
-rw-r--r--src/compiler/scala/tools/nsc/ast/Positions.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala18
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala9
-rw-r--r--src/compiler/scala/tools/nsc/doc/DocParser.scala7
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RangePositions.scala279
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala5
-rw-r--r--src/partest/scala/tools/partest/nest/CompileManager.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Positions.scala9
-rw-r--r--src/reflect/scala/reflect/internal/RangePositions.scala285
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala17
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala2
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala43
-rw-r--r--src/reflect/scala/reflect/internal/util/RangePosition.scala49
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala2
-rw-r--r--test/files/run/t5603.scala3
20 files changed, 401 insertions, 409 deletions
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index 2a9567b567..b2cedf6338 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -19,7 +19,6 @@ import org.apache.tools.ant.util.facade.{FacadeTaskHelper,
ImplementationSpecificArgument}
import scala.tools.nsc.{Global, Settings, CompilerCommand}
-import scala.tools.nsc.interactive.RangePositions
import scala.tools.nsc.io.{Path => SPath}
import scala.tools.nsc.reporters.{Reporter, ConsoleReporter}
@@ -509,10 +508,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
new Settings(error)
protected def newGlobal(settings: Settings, reporter: Reporter) =
- if (settings.Yrangepos.value)
- new Global(settings, reporter) with RangePositions
- else
- new Global(settings, reporter)
+ Global(settings, reporter)
/*============================================================================*\
** The big execute method **
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index fea9e72512..e438ac4bfb 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -12,6 +12,7 @@ import scala.collection.{ mutable, immutable }
import io.{ SourceReader, AbstractFile, Path }
import reporters.{ Reporter, ConsoleReporter }
import util.{ ClassPath, MergedClassPath, StatisticsInfo, returning, stackTraceString, stackTraceHeadString }
+import scala.reflect.internal.RangePositions
import scala.reflect.internal.util.{ OffsetPosition, SourceFile, NoSourceFile, BatchSourceFile, ScriptSourceFile }
import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat }
import symtab.{ Flags, SymbolTable, SymbolLoaders, SymbolTrackers }
@@ -1694,6 +1695,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def createJavadoc = false
}
+class RangePositionGlobal(settings0: Settings, reporter0: Reporter) extends Global(settings0, reporter0) with RangePositions
+
object Global {
- def apply(settings: Settings, reporter: Reporter): Global = new Global(settings, reporter)
+ def apply(settings: Settings, reporter: Reporter): Global =
+ if (settings.Yrangepos.value) new RangePositionGlobal(settings, reporter)
+ else new Global(settings, reporter)
}
diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala
index 27132f3c51..00c6c37dfd 100644
--- a/src/compiler/scala/tools/nsc/Main.scala
+++ b/src/compiler/scala/tools/nsc/Main.scala
@@ -2,54 +2,24 @@
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
-
-package scala.tools.nsc
-
-import java.io.File
-import File.pathSeparator
-import scala.tools.nsc.io.AbstractFile
+package scala.tools
+package nsc
/** The main class for NSC, a compiler for the programming
* language Scala.
*/
-object Main extends Driver with EvalLoop {
-
- def resident(compiler: Global) {
- loop { line =>
- val args = line.split(' ').toList
- val command = new CompilerCommand(args, new Settings(scalacError))
- compiler.reporter.reset()
- new compiler.Run() compile command.files
- }
+class MainClass extends Driver with EvalLoop {
+ def resident(compiler: Global): Unit = loop { line =>
+ val command = new CompilerCommand(line split "\\s+" toList, new Settings(scalacError))
+ compiler.reporter.reset()
+ new compiler.Run() compile command.files
}
- override def processSettingsHook(): Boolean =
- if (settings.Yidedebug.value) {
- settings.Xprintpos.value = true
- settings.Yrangepos.value = true
- val compiler = new interactive.Global(settings, reporter)
- import compiler.{ reporter => _, _ }
-
- val sfs = command.files map getSourceFile
- val reloaded = new interactive.Response[Unit]
- askReload(sfs, reloaded)
-
- reloaded.get.right.toOption match {
- case Some(ex) => reporter.cancelled = true // Causes exit code to be non-0
- case None => reporter.reset() // Causes other compiler errors to be ignored
- }
- askShutdown()
- false
- }
- else true
-
- override def newCompiler(): Global =
- if (settings.Yrangepos.value) new Global(settings, reporter) with interactive.RangePositions
- else Global(settings, reporter)
-
+ override def newCompiler(): Global = Global(settings, reporter)
override def doCompile(compiler: Global) {
- if (settings.resident.value)
- resident(compiler)
+ if (settings.resident.value) resident(compiler)
else super.doCompile(compiler)
}
}
+
+object Main extends MainClass { }
diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala
index e7bd5da9dd..63a2dd0ee7 100644
--- a/src/compiler/scala/tools/nsc/ast/Positions.scala
+++ b/src/compiler/scala/tools/nsc/ast/Positions.scala
@@ -6,11 +6,6 @@ import scala.reflect.internal.util.{ SourceFile, OffsetPosition }
trait Positions extends scala.reflect.internal.Positions {
self: Global =>
- def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
- new OffsetPosition(source, point)
-
- def validatePositions(tree: Tree) {}
-
class ValidatingPosAssigner extends PosAssigner {
var pos: Position = _
override def traverse(t: Tree) {
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index ab6a400c63..6c5c087d55 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -16,24 +16,6 @@ import scala.reflect.internal.Flags.TRAIT
import scala.compat.Platform.EOL
trait Trees extends scala.reflect.internal.Trees { self: Global =>
-
- def treeLine(t: Tree): String =
- if (t.pos.isDefined && t.pos.isRange) t.pos.lineContent.drop(t.pos.column - 1).take(t.pos.end - t.pos.start + 1)
- else t.summaryString
-
- def treeStatus(t: Tree, enclosingTree: Tree = null) = {
- val parent = if (enclosingTree eq null) " " else " P#%5s".format(enclosingTree.id)
-
- "[L%4s%8s] #%-6s %-15s %-10s // %s".format(t.pos.safeLine, parent, t.id, t.pos.show, t.shortClass, treeLine(t))
- }
- def treeSymStatus(t: Tree) = {
- val line = if (t.pos.isDefined) "line %-4s".format(t.pos.safeLine) else " "
- "#%-5s %s %-10s // %s".format(t.id, line, t.shortClass,
- if (t.symbol ne NoSymbol) "(" + t.symbol.fullLocationString + ")"
- else treeLine(t)
- )
- }
-
// --- additional cases --------------------------------------------------------
/** Only used during parsing */
case class Parens(args: List[Tree]) extends Tree
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index b28d4cd08d..181bba6896 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -1297,7 +1297,16 @@ trait Scanners extends ScannersCommon {
class ParensAnalyzer(unit: CompilationUnit, patches: List[BracePatch]) extends UnitScanner(unit, patches) {
val balance = mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0)
+ /** The source code with braces and line starts annotated with [NN] showing the index */
+ private def markedSource = {
+ val code = unit.source.content
+ val braces = code.indices filter (idx => "{}\n" contains code(idx)) toSet;
+ val mapped = code.indices map (idx => if (braces(idx)) s"${code(idx)}[$idx]" else "" + code(idx))
+ mapped.mkString("")
+ }
+
init()
+ log(s"ParensAnalyzer for ${unit.source} of length ${unit.source.content.length}\n```\n$markedSource\n```")
/** The offset of the first token on this line, or next following line if blank
*/
diff --git a/src/compiler/scala/tools/nsc/doc/DocParser.scala b/src/compiler/scala/tools/nsc/doc/DocParser.scala
index 27c995e1c3..104178a832 100644
--- a/src/compiler/scala/tools/nsc/doc/DocParser.scala
+++ b/src/compiler/scala/tools/nsc/doc/DocParser.scala
@@ -9,24 +9,19 @@ package doc
import reporters._
import scala.reflect.internal.util._
-import interactive.RangePositions
import DocParser.Parsed
/** A very minimal global customized for extracting `DocDefs`. It stops
* right after parsing so it can read `DocDefs` from source code which would
* otherwise cause the compiler to go haywire.
*/
-class DocParser(settings: nsc.Settings, reporter: Reporter)
- extends Global(settings, reporter)
- with RangePositions {
-
+class DocParser(settings: nsc.Settings, reporter: Reporter) extends RangePositionGlobal(settings, reporter) {
def this(settings: Settings) = this(settings, new ConsoleReporter(settings))
def this() = this(new Settings(Console println _))
// the usual global initialization
locally { new Run() }
- override def forScaladoc = true
override protected def computeInternalPhases() {
phasesSet += syntaxAnalyzer
}
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index fa1d4a38b9..82eafb4b09 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -21,12 +21,12 @@ import scala.language.implicitConversions
/** The main class of the presentation compiler in an interactive environment such as an IDE
*/
-class Global(settings: Settings, _reporter: Reporter, projectName: String = "") extends {
+class Global(settings: Settings, _reporter: Reporter, projectName: String = "") extends {
/* Is the compiler initializing? Early def, so that the field is true during the
* execution of the super constructor.
*/
private var initializing = true
-} with scala.tools.nsc.Global(settings, _reporter)
+} with RangePositionGlobal(settings, _reporter)
with CompilerControl
with RangePositions
with ContextTrees
diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
index 5a1a4cbdeb..0af62ad729 100644
--- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -2,283 +2,12 @@
* Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL
* @author Martin Odersky
*/
+
package scala.tools.nsc
package interactive
-import ast.Trees
-import ast.Positions
-import scala.reflect.internal.util.{SourceFile, Position, RangePosition, NoPosition}
-import scala.collection.mutable.ListBuffer
-
-/** Handling range positions
- * atPos, the main method in this trait, will add positions to a tree,
- * and will ensure the following properties:
- *
- * 1. All nodes between the root of the tree and nodes that already have positions
- * will be assigned positions.
- * 2. No node which already has a position will be assigned a different range; however
- * a RangePosition might become a TransparentPosition.
- * 3. The position of each assigned node includes the positions of each of its children.
- * 4. The positions of all solid descendants of children of an assigned node
- * are mutually non-overlapping.
- *
- * Here, the solid descendant of a node are:
- *
- * If the node has a TransparentPosition, the solid descendants of all its children
- * Otherwise, the singleton consisting of the node itself.
- */
-trait RangePositions extends Trees with Positions {
-self: scala.tools.nsc.Global =>
-
- case class Range(pos: Position, tree: Tree) {
- def isFree = tree == EmptyTree
- }
-
- override def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
- new RangePosition(source, start, point, end)
-
- /** A position that wraps a set of trees.
- * The point of the wrapping position is the point of the default position.
- * If some of the trees are ranges, returns a range position enclosing all ranges
- * Otherwise returns default position that is either focused or not.
- */
- override def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = {
- val ranged = trees filter (_.pos.isRange)
- if (ranged.isEmpty) if (focus) default.focus else default
- else new RangePosition(default.source, (ranged map (_.pos.start)).min, default.point, (ranged map (_.pos.end)).max)
- }
-
- /** A position that wraps a non-empty set of trees.
- * The point of the wrapping position is the point of the first trees' position.
- * If some of the trees are ranges, returns a range position enclosing all ranges
- * Otherwise returns first tree's position.
- */
- override def wrappingPos(trees: List[Tree]): Position = {
- val headpos = trees.head.pos
- if (headpos.isDefined) wrappingPos(headpos, trees) else headpos
- }
-
- // -------------- ensuring no overlaps -------------------------------
-
- /** Ensure that given tree has no positions that overlap with
- * any of the positions of `others`. This is done by
- * shortening the range, assigning TransparentPositions
- * to some of the nodes in `tree` or focusing on the position.
- */
- override def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean) {
- def isOverlapping(pos: Position) =
- pos.isRange && (others exists (pos overlaps _.pos))
- if (isOverlapping(tree.pos)) {
- val children = tree.children
- children foreach (ensureNonOverlapping(_, others, focus))
- if (tree.pos.isOpaqueRange) {
- val wpos = wrappingPos(tree.pos, children, focus)
- tree setPos (if (isOverlapping(wpos)) tree.pos.makeTransparent else wpos)
- }
- }
- }
-
- def solidDescendants(tree: Tree): List[Tree] =
- if (tree.pos.isTransparent) tree.children flatMap solidDescendants
- else List(tree)
-
- /** A free range from `lo` to `hi` */
- private def free(lo: Int, hi: Int): Range =
- Range(new RangePosition(null, lo, lo, hi), EmptyTree)
-
- /** The maximal free range */
- private lazy val maxFree: Range = free(0, Int.MaxValue)
-
- /** A singleton list of a non-empty range from `lo` to `hi`, or else the empty List */
- private def maybeFree(lo: Int, hi: Int) =
- if (lo < hi) List(free(lo, hi))
- else List()
-
- /** Insert `pos` into ranges `rs` if possible;
- * otherwise add conflicting trees to `conflicting`.
- */
- private def insert(rs: List[Range], t: Tree, conflicting: ListBuffer[Tree]): List[Range] = rs match {
- case List() =>
- assert(conflicting.nonEmpty)
- rs
- case r :: rs1 =>
- assert(!t.pos.isTransparent)
- if (r.isFree && (r.pos includes t.pos)) {
-// println("subdividing "+r+"/"+t.pos)
- maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1
- } else {
- if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree
- r :: insert(rs1, t, conflicting)
- }
- }
-
- /** Replace elem `t` of `ts` by `replacement` list. */
- private def replace(ts: List[Tree], t: Tree, replacement: List[Tree]): List[Tree] =
- if (ts.head == t) replacement ::: ts.tail
- else ts.head :: replace(ts.tail, t, replacement)
-
- /** Does given list of trees have mutually non-overlapping positions?
- * pre: None of the trees is transparent
- */
- def findOverlapping(cts: List[Tree]): List[(Tree, Tree)] = {
- var ranges = List(maxFree)
- for (ct <- cts) {
- if (ct.pos.isOpaqueRange) {
- val conflicting = new ListBuffer[Tree]
- ranges = insert(ranges, ct, conflicting)
- if (conflicting.nonEmpty) return conflicting.toList map (t => (t, ct))
- }
- }
- List()
- }
-
- // -------------- setting positions -------------------------------
-
- /** Set position of all children of a node
- * @param pos A target position.
- * Uses the point of the position as the point of all positions it assigns.
- * Uses the start of this position as an Offset position for unpositioed trees
- * without children.
- * @param trees The children to position. All children must be positionable.
- */
- private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try {
- for (tree <- trees) {
- if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
- val children = tree.children
- if (children.isEmpty) {
- tree setPos pos.focus
- } else {
- setChildrenPos(pos, children)
- tree setPos wrappingPos(pos, children)
- }
- }
- }
- } catch {
- case ex: Exception =>
- println("error while set children pos "+pos+" of "+trees)
- throw ex
- }
-
- /** Position a tree.
- * This means: Set position of a node and position all its unpositioned children.
- */
- override def atPos[T <: Tree](pos: Position)(tree: T): T = {
- if (pos.isOpaqueRange) {
- if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
- tree.setPos(pos)
- val children = tree.children
- if (children.nonEmpty) {
- if (children.tail.isEmpty) atPos(pos)(children.head)
- else setChildrenPos(pos, children)
- }
- }
- tree
- } else {
- super.atPos(pos)(tree)
- }
- }
-
- // ---------------- Validating positions ----------------------------------
-
- override def validatePositions(tree: Tree) {
- def reportTree(prefix : String, tree : Tree) {
- val source = if (tree.pos.isDefined) tree.pos.source else ""
- inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.productPrefix+" at "+tree.pos.show+source)
- inform("")
- inform(treeStatus(tree))
- inform("")
- }
-
- def positionError(msg: String)(body : => Unit) {
- inform("======= Position error\n" + msg)
- body
- inform("\nWhile validating #" + tree.id)
- inform(treeStatus(tree))
- inform("\nChildren:")
- tree.children map (t => " " + treeStatus(t, tree)) foreach inform
- inform("=======")
- throw new ValidateException(msg)
- }
-
- def validate(tree: Tree, encltree: Tree): Unit = {
-
- if (!tree.isEmpty && tree.canHaveAttrs) {
- if (settings.Yposdebug.value && (settings.verbose.value || settings.Yrangepos.value))
- println("[%10s] %s".format("validate", treeStatus(tree, encltree)))
-
- if (!tree.pos.isDefined)
- positionError("Unpositioned tree #"+tree.id) {
- inform("%15s %s".format("unpositioned", treeStatus(tree, encltree)))
- inform("%15s %s".format("enclosing", treeStatus(encltree)))
- encltree.children foreach (t => inform("%15s %s".format("sibling", treeStatus(t, encltree))))
- }
- if (tree.pos.isRange) {
- if (!encltree.pos.isRange)
- positionError("Synthetic tree ["+encltree.id+"] contains nonsynthetic tree ["+tree.id+"]") {
- reportTree("Enclosing", encltree)
- reportTree("Enclosed", tree)
- }
- if (!(encltree.pos includes tree.pos))
- positionError("Enclosing tree ["+encltree.id+"] does not include tree ["+tree.id+"]") {
- reportTree("Enclosing", encltree)
- reportTree("Enclosed", tree)
- }
-
- findOverlapping(tree.children flatMap solidDescendants) match {
- case List() => ;
- case xs => {
- positionError("Overlapping trees "+xs.map { case (x, y) => (x.id, y.id) }.mkString("", ", ", "")) {
- reportTree("Ancestor", tree)
- for((x, y) <- xs) {
- reportTree("First overlapping", x)
- reportTree("Second overlapping", y)
- }
- }
- }
- }
- }
- for (ct <- tree.children flatMap solidDescendants) validate(ct, tree)
- }
- }
-
- if (phase.id <= currentRun.typerPhase.id)
- validate(tree, tree)
- }
-
- class ValidateException(msg : String) extends Exception(msg)
-
- // ---------------- Locating trees ----------------------------------
-
- /** 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
- }
- protected def isEligible(t: Tree) = !t.pos.isTransparent
- override def traverse(t: Tree) {
- t match {
- case tt : TypeTree if tt.original != null && (tt.pos includes tt.original.pos) =>
- traverse(tt.original)
- case _ =>
- if (t.pos includes pos) {
- if (isEligible(t)) last = t
- super.traverse(t)
- } else t match {
- case mdef: MemberDef =>
- traverseTrees(mdef.mods.annotations)
- case _ =>
- }
- }
- }
- }
+@deprecated("Use scala.reflect.internal.RangePositions", "2.11.0")
+trait RangePositions extends scala.reflect.internal.RangePositions with ast.Trees with ast.Positions {
+ self: scala.tools.nsc.Global =>
- class TypedLocator(pos: Position) extends Locator(pos) {
- override protected def isEligible(t: Tree) = super.isEligible(t) && t.tpe != null
- }
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index db54b5a2b1..4d1ceb2818 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -243,7 +243,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
settings.outputDirs setSingleOutput replOutput.dir
settings.exposeEmptyPackage.value = true
if (settings.Yrangepos.value)
- new Global(settings, reporter) with ReplGlobal with interactive.RangePositions { override def toString: String = "<global>" }
+ new RangePositionGlobal(settings, reporter) with ReplGlobal { override def toString: String = "<global>" }
else
new Global(settings, reporter) with ReplGlobal { override def toString: String = "<global>" }
}
diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index 483cb491a1..3f61062073 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -42,10 +42,7 @@ abstract class DirectTest extends App {
newCompiler(settings)
}
- def newCompiler(settings: Settings): Global = {
- if (settings.Yrangepos.value) new Global(settings, reporter(settings)) with interactive.RangePositions
- else new Global(settings, reporter(settings))
- }
+ def newCompiler(settings: Settings): Global = Global(settings, reporter(settings))
def reporter(settings: Settings): Reporter = new ConsoleReporter(settings)
diff --git a/src/partest/scala/tools/partest/nest/CompileManager.scala b/src/partest/scala/tools/partest/nest/CompileManager.scala
index 0e62f9a022..a8694cc0d6 100644
--- a/src/partest/scala/tools/partest/nest/CompileManager.scala
+++ b/src/partest/scala/tools/partest/nest/CompileManager.scala
@@ -10,7 +10,6 @@ package nest
import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
import scala.reflect.io.{ Directory, File => SFile, FileOperationException }
-import scala.tools.nsc.interactive.RangePositions
import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
import scala.tools.nsc.util.{ ClassPath, FakePos }
import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
@@ -52,10 +51,7 @@ abstract class SimpleCompiler {
class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
def newGlobal(settings: Settings, reporter: Reporter): Global =
- if (settings.Yrangepos.value)
- new Global(settings, reporter) with RangePositions
- else
- new Global(settings, reporter)
+ Global(settings, reporter)
def newGlobal(settings: Settings, logWriter: FileWriter): Global =
newGlobal(settings, new ExtConsoleReporter(settings, new PrintWriter(logWriter)))
diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala
index f8c670827a..69f6d22538 100644
--- a/src/reflect/scala/reflect/internal/Positions.scala
+++ b/src/reflect/scala/reflect/internal/Positions.scala
@@ -1,6 +1,8 @@
package scala.reflect
package internal
+import util._
+
trait Positions extends api.Positions { self: SymbolTable =>
type Position = scala.reflect.internal.util.Position
@@ -12,7 +14,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
* If some of the trees are ranges, returns a range position enclosing all ranges
* Otherwise returns default position that is either focused or not.
*/
- def wrappingPos(default: Position, trees: List[Tree]) = wrappingPos(default, trees, true)
+ def wrappingPos(default: Position, trees: List[Tree]): Position = wrappingPos(default, trees, true)
def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = default
/** A position that wraps the non-empty set of trees.
@@ -30,6 +32,9 @@ trait Positions extends api.Positions { self: SymbolTable =>
def ensureNonOverlapping(tree: Tree, others: List[Tree]){ ensureNonOverlapping(tree, others, true) }
def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean) {}
+ def rangePos(source: SourceFile, start: Int, point: Int, end: Int): Position = new OffsetPosition(source, point)
+ def validatePositions(tree: Tree) {}
+
trait PosAssigner extends Traverser {
var pos: Position
}
@@ -62,4 +67,4 @@ trait Positions extends api.Positions { self: SymbolTable =>
posAssigner.traverse(tree)
tree
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/internal/RangePositions.scala b/src/reflect/scala/reflect/internal/RangePositions.scala
new file mode 100644
index 0000000000..85bbaf3364
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/RangePositions.scala
@@ -0,0 +1,285 @@
+/* NSC -- new Scala compiler
+ * Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import util._
+import scala.collection.mutable.ListBuffer
+
+/** Handling range positions
+ * atPos, the main method in this trait, will add positions to a tree,
+ * and will ensure the following properties:
+ *
+ * 1. All nodes between the root of the tree and nodes that already have positions
+ * will be assigned positions.
+ * 2. No node which already has a position will be assigned a different range; however
+ * a RangePosition might become a TransparentPosition.
+ * 3. The position of each assigned node includes the positions of each of its children.
+ * 4. The positions of all solid descendants of children of an assigned node
+ * are mutually non-overlapping.
+ *
+ * Here, the solid descendant of a node are:
+ *
+ * If the node has a TransparentPosition, the solid descendants of all its children
+ * Otherwise, the singleton consisting of the node itself.
+ */
+trait RangePositions extends Trees with Positions {
+ self: SymbolTable =>
+
+ def inform(msg: String): Unit
+
+ case class Range(pos: Position, tree: Tree) {
+ def isFree = tree == EmptyTree
+ }
+
+ override def rangePos(source: SourceFile, start: Int, point: Int, end: Int): RangePosition =
+ new RangePosition(source, start, point, end)
+
+ /** A position that wraps a set of trees.
+ * The point of the wrapping position is the point of the default position.
+ * If some of the trees are ranges, returns a range position enclosing all ranges
+ * Otherwise returns default position that is either focused or not.
+ */
+ override def wrappingPos(default: Position, trees: List[Tree], focus: Boolean): Position = {
+ val ranged = trees filter (_.pos.isRange)
+ if (ranged.isEmpty) if (focus) default.focus else default
+ else new RangePosition(default.source, (ranged map (_.pos.start)).min, default.point, (ranged map (_.pos.end)).max)
+ }
+
+ /** A position that wraps a non-empty set of trees.
+ * The point of the wrapping position is the point of the first trees' position.
+ * If some of the trees are ranges, returns a range position enclosing all ranges
+ * Otherwise returns first tree's position.
+ */
+ override def wrappingPos(trees: List[Tree]): Position = {
+ val headpos = trees.head.pos
+ if (headpos.isDefined) wrappingPos(headpos, trees) else headpos
+ }
+
+ // -------------- ensuring no overlaps -------------------------------
+
+ /** Ensure that given tree has no positions that overlap with
+ * any of the positions of `others`. This is done by
+ * shortening the range, assigning TransparentPositions
+ * to some of the nodes in `tree` or focusing on the position.
+ */
+ override def ensureNonOverlapping(tree: Tree, others: List[Tree], focus: Boolean) {
+ def isOverlapping(pos: Position) =
+ pos.isRange && (others exists (pos overlaps _.pos))
+ if (isOverlapping(tree.pos)) {
+ val children = tree.children
+ children foreach (ensureNonOverlapping(_, others, focus))
+ if (tree.pos.isOpaqueRange) {
+ val wpos = wrappingPos(tree.pos, children, focus)
+ tree setPos (if (isOverlapping(wpos)) tree.pos.makeTransparent else wpos)
+ }
+ }
+ }
+
+ def solidDescendants(tree: Tree): List[Tree] =
+ if (tree.pos.isTransparent) tree.children flatMap solidDescendants
+ else List(tree)
+
+ /** A free range from `lo` to `hi` */
+ private def free(lo: Int, hi: Int): Range =
+ Range(new RangePosition(null, lo, lo, hi), EmptyTree)
+
+ /** The maximal free range */
+ private lazy val maxFree: Range = free(0, Int.MaxValue)
+
+ /** A singleton list of a non-empty range from `lo` to `hi`, or else the empty List */
+ private def maybeFree(lo: Int, hi: Int) =
+ if (lo < hi) List(free(lo, hi))
+ else List()
+
+ /** Insert `pos` into ranges `rs` if possible;
+ * otherwise add conflicting trees to `conflicting`.
+ */
+ private def insert(rs: List[Range], t: Tree, conflicting: ListBuffer[Tree]): List[Range] = rs match {
+ case List() =>
+ assert(conflicting.nonEmpty)
+ rs
+ case r :: rs1 =>
+ assert(!t.pos.isTransparent)
+ if (r.isFree && (r.pos includes t.pos)) {
+// println("subdividing "+r+"/"+t.pos)
+ maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1
+ } else {
+ if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree
+ r :: insert(rs1, t, conflicting)
+ }
+ }
+
+ /** Replace elem `t` of `ts` by `replacement` list. */
+ private def replace(ts: List[Tree], t: Tree, replacement: List[Tree]): List[Tree] =
+ if (ts.head == t) replacement ::: ts.tail
+ else ts.head :: replace(ts.tail, t, replacement)
+
+ /** Does given list of trees have mutually non-overlapping positions?
+ * pre: None of the trees is transparent
+ */
+ def findOverlapping(cts: List[Tree]): List[(Tree, Tree)] = {
+ var ranges = List(maxFree)
+ for (ct <- cts) {
+ if (ct.pos.isOpaqueRange) {
+ val conflicting = new ListBuffer[Tree]
+ ranges = insert(ranges, ct, conflicting)
+ if (conflicting.nonEmpty) return conflicting.toList map (t => (t, ct))
+ }
+ }
+ List()
+ }
+
+ // -------------- setting positions -------------------------------
+
+ /** Set position of all children of a node
+ * @param pos A target position.
+ * Uses the point of the position as the point of all positions it assigns.
+ * Uses the start of this position as an Offset position for unpositioed trees
+ * without children.
+ * @param trees The children to position. All children must be positionable.
+ */
+ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try {
+ for (tree <- trees) {
+ if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
+ val children = tree.children
+ if (children.isEmpty) {
+ tree setPos pos.focus
+ } else {
+ setChildrenPos(pos, children)
+ tree setPos wrappingPos(pos, children)
+ }
+ }
+ }
+ } catch {
+ case ex: Exception =>
+ println("error while set children pos "+pos+" of "+trees)
+ throw ex
+ }
+
+ /** Position a tree.
+ * This means: Set position of a node and position all its unpositioned children.
+ */
+ override def atPos[T <: Tree](pos: Position)(tree: T): T = {
+ if (pos.isOpaqueRange) {
+ if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) {
+ tree.setPos(pos)
+ val children = tree.children
+ if (children.nonEmpty) {
+ if (children.tail.isEmpty) atPos(pos)(children.head)
+ else setChildrenPos(pos, children)
+ }
+ }
+ tree
+ } else {
+ super.atPos(pos)(tree)
+ }
+ }
+
+ // ---------------- Validating positions ----------------------------------
+
+ override def validatePositions(tree: Tree) {
+ def reportTree(prefix : String, tree : Tree) {
+ val source = if (tree.pos.isDefined) tree.pos.source else ""
+ inform("== "+prefix+" tree ["+tree.id+"] of type "+tree.productPrefix+" at "+tree.pos.show+source)
+ inform("")
+ inform(treeStatus(tree))
+ inform("")
+ }
+
+ def positionError(msg: String)(body : => Unit) {
+ inform("======= Position error\n" + msg)
+ body
+ inform("\nWhile validating #" + tree.id)
+ inform(treeStatus(tree))
+ inform("\nChildren:")
+ tree.children map (t => " " + treeStatus(t, tree)) foreach inform
+ inform("=======")
+ throw new ValidateException(msg)
+ }
+
+ def validate(tree: Tree, encltree: Tree): Unit = {
+
+ if (!tree.isEmpty && tree.canHaveAttrs) {
+ if (settings.Yposdebug.value && (settings.verbose.value || settings.Yrangepos.value))
+ println("[%10s] %s".format("validate", treeStatus(tree, encltree)))
+
+ if (!tree.pos.isDefined)
+ positionError("Unpositioned tree #"+tree.id) {
+ inform("%15s %s".format("unpositioned", treeStatus(tree, encltree)))
+ inform("%15s %s".format("enclosing", treeStatus(encltree)))
+ encltree.children foreach (t => inform("%15s %s".format("sibling", treeStatus(t, encltree))))
+ }
+ if (tree.pos.isRange) {
+ if (!encltree.pos.isRange)
+ positionError("Synthetic tree ["+encltree.id+"] contains nonsynthetic tree ["+tree.id+"]") {
+ reportTree("Enclosing", encltree)
+ reportTree("Enclosed", tree)
+ }
+ if (!(encltree.pos includes tree.pos))
+ positionError("Enclosing tree ["+encltree.id+"] does not include tree ["+tree.id+"]") {
+ reportTree("Enclosing", encltree)
+ reportTree("Enclosed", tree)
+ }
+
+ findOverlapping(tree.children flatMap solidDescendants) match {
+ case List() => ;
+ case xs => {
+ positionError("Overlapping trees "+xs.map { case (x, y) => (x.id, y.id) }.mkString("", ", ", "")) {
+ reportTree("Ancestor", tree)
+ for((x, y) <- xs) {
+ reportTree("First overlapping", x)
+ reportTree("Second overlapping", y)
+ }
+ }
+ }
+ }
+ }
+ for (ct <- tree.children flatMap solidDescendants) validate(ct, tree)
+ }
+ }
+
+ if (!isPastTyper)
+ validate(tree, tree)
+ }
+
+ class ValidateException(msg : String) extends Exception(msg)
+
+ // ---------------- Locating trees ----------------------------------
+
+ /** 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
+ }
+ protected def isEligible(t: Tree) = !t.pos.isTransparent
+ override def traverse(t: Tree) {
+ t match {
+ case tt : TypeTree if tt.original != null && (tt.pos includes tt.original.pos) =>
+ traverse(tt.original)
+ case _ =>
+ if (t.pos includes pos) {
+ if (isEligible(t)) last = t
+ super.traverse(t)
+ } else t match {
+ case mdef: MemberDef =>
+ traverseTrees(mdef.mods.annotations)
+ case _ =>
+ }
+ }
+ }
+ }
+
+ class TypedLocator(pos: Position) extends Locator(pos) {
+ override protected def isEligible(t: Tree) = super.isEligible(t) && t.tpe != null
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index ce33fd8408..c00337e578 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -14,6 +14,23 @@ trait Trees extends api.Trees { self: SymbolTable =>
private[scala] var nodeCount = 0
+ protected def treeLine(t: Tree): String =
+ if (t.pos.isDefined && t.pos.isRange) t.pos.lineContent.drop(t.pos.column - 1).take(t.pos.end - t.pos.start + 1)
+ else t.summaryString
+
+ protected def treeStatus(t: Tree, enclosingTree: Tree = null) = {
+ val parent = if (enclosingTree eq null) " " else " P#%5s".format(enclosingTree.id)
+
+ "[L%4s%8s] #%-6s %-15s %-10s // %s".format(t.pos.safeLine, parent, t.id, t.pos.show, t.shortClass, treeLine(t))
+ }
+ protected def treeSymStatus(t: Tree) = {
+ val line = if (t.pos.isDefined) "line %-4s".format(t.pos.safeLine) else " "
+ "#%-5s %s %-10s // %s".format(t.id, line, t.shortClass,
+ if (t.symbol ne NoSymbol) "(" + t.symbol.fullLocationString + ")"
+ else treeLine(t)
+ )
+ }
+
abstract class Tree extends TreeContextApiImpl with Attachable with Product {
val id = nodeCount // TODO: add to attachment?
nodeCount += 1
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index d5ed9dab5b..506edb861e 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -40,6 +40,8 @@ abstract class MutableSettings extends AbsSettings {
def verbose: BooleanSetting
def uniqid: BooleanSetting
def Yshowsymkinds: BooleanSetting
+ def Yposdebug: BooleanSetting
+ def Yrangepos: BooleanSetting
def Xprintpos: BooleanSetting
def Yrecursion: IntSetting
def maxClassfileName: IntSetting
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
index f0185372c5..bb8c9e9b26 100644
--- a/src/reflect/scala/reflect/internal/util/Position.scala
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -266,46 +266,3 @@ class OffsetPosition(override val source: SourceFile, override val point: Int) e
}
override def show = "["+point+"]"
}
-
-/** new for position ranges */
-class RangePosition(source: SourceFile, override val start: Int, point: Int, override val end: Int)
-extends OffsetPosition(source, point) {
- if (start > end) sys.error("bad position: "+show)
- override def isRange: Boolean = true
- override def isOpaqueRange: Boolean = true
- override def startOrPoint: Int = start
- override def endOrPoint: Int = end
- override def withStart(off: Int) = new RangePosition(source, off, point, end)
- override def withEnd(off: Int) = new RangePosition(source, start, point, off)
- override def withPoint(off: Int) = new RangePosition(source, start, off, end)
- override def withSource(source: SourceFile, shift: Int) = new RangePosition(source, start + shift, point + shift, end + shift)
- override def focusStart = new OffsetPosition(source, start)
- override def focus = {
- if (focusCache eq NoPosition) focusCache = new OffsetPosition(source, point)
- focusCache
- }
- override def focusEnd = new OffsetPosition(source, end)
- override def makeTransparent = new TransparentPosition(source, start, point, end)
- override def includes(pos: Position) = pos.isDefined && start <= pos.startOrPoint && pos.endOrPoint <= end
- override def union(pos: Position): Position =
- if (pos.isRange) new RangePosition(source, start min pos.start, point, end max pos.end) else this
-
- override def toSingleLine: Position = source match {
- case bs: BatchSourceFile
- if end > 0 && bs.offsetToLine(start) < bs.offsetToLine(end - 1) =>
- val pointLine = bs.offsetToLine(point)
- new RangePosition(source, bs.lineToOffset(pointLine), point, bs.lineToOffset(pointLine + 1))
- case _ => this
- }
-
- override def toString = "RangePosition("+source.file.canonicalPath+", "+start+", "+point+", "+end+")"
- override def show = "["+start+":"+end+"]"
- private var focusCache: Position = NoPosition
-}
-
-class TransparentPosition(source: SourceFile, start: Int, point: Int, end: Int) extends RangePosition(source, start, point, end) {
- override def isOpaqueRange: Boolean = false
- override def isTransparent = true
- override def makeTransparent = this
- override def show = "<"+start+":"+end+">"
-}
diff --git a/src/reflect/scala/reflect/internal/util/RangePosition.scala b/src/reflect/scala/reflect/internal/util/RangePosition.scala
new file mode 100644
index 0000000000..3712aa0a52
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/RangePosition.scala
@@ -0,0 +1,49 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.internal.util
+
+/** new for position ranges */
+class RangePosition(source: SourceFile, override val start: Int, point: Int, override val end: Int)
+extends OffsetPosition(source, point) {
+ if (start > end) sys.error("bad position: "+show)
+ override def isRange: Boolean = true
+ override def isOpaqueRange: Boolean = true
+ override def startOrPoint: Int = start
+ override def endOrPoint: Int = end
+ override def withStart(off: Int) = new RangePosition(source, off, point, end)
+ override def withEnd(off: Int) = new RangePosition(source, start, point, off)
+ override def withPoint(off: Int) = new RangePosition(source, start, off, end)
+ override def withSource(source: SourceFile, shift: Int) = new RangePosition(source, start + shift, point + shift, end + shift)
+ override def focusStart = new OffsetPosition(source, start)
+ override def focus = {
+ if (focusCache eq NoPosition) focusCache = new OffsetPosition(source, point)
+ focusCache
+ }
+ override def focusEnd = new OffsetPosition(source, end)
+ override def makeTransparent = new TransparentPosition(source, start, point, end)
+ override def includes(pos: Position) = pos.isDefined && start <= pos.startOrPoint && pos.endOrPoint <= end
+ override def union(pos: Position): Position =
+ if (pos.isRange) new RangePosition(source, start min pos.start, point, end max pos.end) else this
+
+ override def toSingleLine: Position = source match {
+ case bs: BatchSourceFile
+ if end > 0 && bs.offsetToLine(start) < bs.offsetToLine(end - 1) =>
+ val pointLine = bs.offsetToLine(point)
+ new RangePosition(source, bs.lineToOffset(pointLine), point, bs.lineToOffset(pointLine + 1))
+ case _ => this
+ }
+
+ override def toString = "RangePosition("+source.file.canonicalPath+", "+start+", "+point+", "+end+")"
+ override def show = "["+start+":"+end+"]"
+ private var focusCache: Position = NoPosition
+}
+
+class TransparentPosition(source: SourceFile, start: Int, point: Int, end: Int) extends RangePosition(source, start, point, end) {
+ override def isOpaqueRange: Boolean = false
+ override def isTransparent = true
+ override def makeTransparent = this
+ override def show = "<"+start+":"+end+">"
+}
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
index ba524f4df2..5d58fa96d6 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -35,6 +35,8 @@ private[reflect] class Settings extends MutableSettings {
val Xprintpos = new BooleanSetting(false)
val Ynotnull = new BooleanSetting(false)
val Yshowsymkinds = new BooleanSetting(false)
+ val Yposdebug = new BooleanSetting(false)
+ val Yrangepos = new BooleanSetting(false)
val debug = new BooleanSetting(false)
val deepCloning = new BooleanSetting(false)
val explaintypes = new BooleanSetting(false)
diff --git a/test/files/run/t5603.scala b/test/files/run/t5603.scala
index 60dfd01fee..8c8038a602 100644
--- a/test/files/run/t5603.scala
+++ b/test/files/run/t5603.scala
@@ -36,7 +36,8 @@ object Test extends DirectTest {
val settings = new Settings()
settings.Xprintpos.value = true
+ settings.Yrangepos.value = true
val command = new CompilerCommand((CommandLineParser tokenize extraSettings) ++ args.toList, settings)
- new Global(command.settings, new ConsoleReporter(settings)) with interactive.RangePositions
+ Global(command.settings, new ConsoleReporter(settings))
}
}