Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

286 lines (230 sloc) 11.178 kb
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Martin Odersky
*
*/
package scala.tools.nsc
package util
object Position {
val tabInc = 8
/** Prints the message with the given position indication. */
def formatMessage(posIn: Position, msg: String, shortenFile: Boolean): String = {
val pos = (
if (posIn eq null) NoPosition
else if (posIn.isDefined) posIn.inUltimateSource(posIn.source)
else posIn
)
def file = pos.source.file
def prefix = if (shortenFile) file.name else file.path
pos match {
case FakePos(fmsg) => fmsg+" "+msg
case NoPosition => msg
case _ =>
List(
"%s:%s: %s".format(prefix, pos.line, msg),
pos.lineContent.stripLineEnd,
" " * (pos.column - 1) + "^"
) mkString "\n"
}
}
}
trait Position extends scala.reflect.api.Position with scala.reflect.api.Attachment {
/** Exposes itself as payload of Attachment */
// necessary for conformance with Attachment
def pos: Position = this
/** A bit weird method that is necessary to safely update positions without destroying custom attachments */
// necessary for conformance with Attachment
def withPos(newPos: scala.reflect.api.Position): scala.reflect.api.Attachment = newPos
/** Exposes itself as payload of Attachment */
// necessary for conformance with Attachment
def payload: Position = this
/** A bit weird method that is necessary to safely update positions without destroying custom attachments */
// necessary for conformance with Attachment
def withPayload(newPos: Any): scala.reflect.api.Attachment = newPos.asInstanceOf[Position]
/** Java file corresponding to the source file of this position.
*/
// necessary for conformance with scala.reflect.api.Position
def fileInfo: java.io.File = source.file.file
/** Contents of the source file that contains this position.
*/
// necessary for conformance with scala.reflect.api.Position
def fileContent: Array[Char] = source.content
/** An optional value containing the source file referred to by this position, or
* None if not defined.
*/
def source: SourceFile = throw new UnsupportedOperationException("Position.source")
/** Is this position neither a NoPosition nor a FakePosition?
* If isDefined is true, offset and source are both defined.
*/
def isDefined: Boolean = false
/** Is this position a transparent position? */
def isTransparent: Boolean = false
/** Is this position a range position? */
def isRange: Boolean = false
/** Is this position a non-transparent range position? */
def isOpaqueRange: Boolean = false
/** if opaque range, make this position transparent */
def makeTransparent: Position = this
/** The start of the position's range, error if not a range position */
def start: Int = throw new UnsupportedOperationException("Position.start")
/** The start of the position's range, or point if not a range position */
def startOrPoint: Int = point
/** The point (where the ^ is) of the position */
def point: Int = throw new UnsupportedOperationException("Position.point")
/** The point (where the ^ is) of the position, or else `default` if undefined */
def pointOrElse(default: Int): Int = default
/** The end of the position's range, error if not a range position */
def end: Int = throw new UnsupportedOperationException("Position.end")
/** The end of the position's range, or point if not a range position */
def endOrPoint: Int = point
@deprecated("use point instead", "2.9.0")
def offset: Option[Int] = if (isDefined) Some(point) else None
/** The same position with a different start value (if a range) */
def withStart(off: Int): Position = this
/** The same position with a different end value (if a range) */
def withEnd(off: Int): Position = this
/** The same position with a different point value (if a range or offset) */
def withPoint(off: Int): Position = this
/** The same position with a different source value, and its values shifted by given offset */
def withSource(source: SourceFile, shift: Int): Position = this
/** If this is a range, the union with the other range, with the point of this position.
* Otherwise, this position
*/
def union(pos: scala.reflect.api.Position): Position = this
/** If this is a range position, the offset position of its start.
* Otherwise the position itself
*/
def focusStart: Position = this
/** If this is a range position, the offset position of its point.
* Otherwise the position itself
*/
def focus: Position = this
/** If this is a range position, the offset position of its end.
* Otherwise the position itself
*/
def focusEnd: Position = this
/** Does this position include the given position `pos`.
* This holds if `this` is a range position and its range [start..end]
* is the same or covers the range of the given position, which may or may not be a range position.
*/
def includes(pos: scala.reflect.api.Position): Boolean = false
/** Does this position properly include the given position `pos` ("properly" meaning their
* ranges are not the same)?
*/
def properlyIncludes(pos: scala.reflect.api.Position): Boolean =
includes(pos) && (start < pos.startOrPoint || pos.endOrPoint < end)
/** Does this position precede that position?
* This holds if both positions are defined and the end point of this position
* is not larger than the start point of the given position.
*/
def precedes(pos: scala.reflect.api.Position): Boolean =
isDefined && pos.isDefined && endOrPoint <= pos.startOrPoint
/** Does this position properly precede the given position `pos` ("properly" meaning their ranges
* do not share a common point).
*/
def properlyPrecedes(pos: scala.reflect.api.Position): Boolean =
isDefined && pos.isDefined && endOrPoint < pos.startOrPoint
/** Does this position overlap with that position?
* This holds if both positions are ranges and there is an interval of
* non-zero length that is shared by both position ranges.
*/
def overlaps(pos: scala.reflect.api.Position): Boolean =
isRange && pos.isRange &&
((pos.start < end && start < pos.end) || (start < pos.end && pos.start < end))
/** Does this position cover the same range as that position?
* Holds only if both position are ranges
*/
def sameRange(pos: scala.reflect.api.Position): Boolean =
isRange && pos.isRange && start == pos.start && end == pos.end
def line: Int = throw new UnsupportedOperationException("Position.line")
def column: Int = throw new UnsupportedOperationException("Position.column")
/** Convert this to a position around `point` that spans a single source line */
def toSingleLine: Position = this
def lineContent: String =
if (isDefined) source.lineToString(line - 1)
else "NO_LINE"
/** Map this position to a position in an original source
* file. If the SourceFile is a normal SourceFile, simply
* return this.
*/
def inUltimateSource(source : SourceFile): Position =
if (source == null) this else source.positionInUltimateSource(this)
def dbgString: String = toString
def safeLine: Int = try line catch { case _: UnsupportedOperationException => -1 }
def show: String = "["+toString+"]"
}
case object NoPosition extends Position {
override def dbgString = toString
}
case class FakePos(msg: String) extends Position {
override def toString = msg
}
class OffsetPosition(override val source: SourceFile, override val point: Int) extends Position {
override def isDefined = true
override def pointOrElse(default: Int): Int = point
override def withPoint(off: Int) = new OffsetPosition(source, off)
override def withSource(source: SourceFile, shift: Int) = new OffsetPosition(source, point + shift)
override def line: Int = source.offsetToLine(point) + 1
override def column: Int = {
var idx = source.lineToOffset(source.offsetToLine(point))
var col = 0
while (idx != point) {
col += (if (source.content(idx) == '\t') Position.tabInc - col % Position.tabInc else 1)
idx += 1
}
col + 1
}
override def union(pos: scala.reflect.api.Position) =
// [Eugene] how do I get rid of this cast?
// I could introduce a "type PositionType <: scala.reflect.api.Position", but that's also ugly
if (pos.isRange) pos.asInstanceOf[Position] else this
override def equals(that : Any) = that match {
case that : OffsetPosition => point == that.point && source.file == that.source.file
case that => false
}
override def hashCode = point * 37 + source.file.hashCode
override def toString = {
val pointmsg = if (point > source.length) "out-of-bounds-" else "offset="
"source-%s,line-%s,%s%s".format(source.file.canonicalPath, line, pointmsg, point)
}
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) assert(false, "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: scala.reflect.api.Position) = pos.isDefined && start <= pos.startOrPoint && pos.endOrPoint <= end
override def union(pos: scala.reflect.api.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+">"
}
Jump to Line
Something went wrong with that request. Please try again.