alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (Position.scala)

This example Scala source code file (Position.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Scala source code examples by using tags.

All credit for the original source code belongs to scala-lang.org; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Scala tags/keywords

boolean, int, noposition, nosourcefile, pos, position, rangeposition, sourcefile, string, undefinedposition

The Position.scala Scala example source code

/* NSC -- new Scala compiler
 * Copyright 2005-2013 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala
package reflect
package internal
package util

/** @inheritdoc */
class Position extends scala.reflect.api.Position with InternalPositionImpl with DeprecatedPosition {
  type Pos = Position
  def pos: Position = this
  def withPos(newPos: Position): macros.Attachments { type Pos = Position.this.Pos } = newPos

  protected def fail(what: String) = throw new UnsupportedOperationException(s"Position.$what on $this")

  // If scala-refactoring extends Position directly it seems I have no
  // choice but to offer all the concrete methods.
  def isDefined          = false
  def isRange            = false
  def source: SourceFile = NoSourceFile
  def start: Int         = fail("start")
  def point: Int         = fail("point")
  def end: Int           = fail("end")
}

object Position {
  val tabInc = 8

  private def validate[T <: Position](pos: T): T = {
    if (pos.isRange)
      assert(pos.start <= pos.end, s"bad position: ${pos.show}")

    pos
  }

  /** 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 posIn
    val prefix = pos.source match {
      case NoSourceFile     => ""
      case s if shortenFile => s.file.name + ":"
      case s                => s.file.path + ":"
    }
    prefix + (pos showError msg)
  }

  def offset(source: SourceFile, point: Int): Position                            = validate(new OffsetPosition(source, point))
  def range(source: SourceFile, start: Int, point: Int, end: Int): Position       = validate(new RangePosition(source, start, point, end))
  def transparent(source: SourceFile, start: Int, point: Int, end: Int): Position = validate(new TransparentPosition(source, start, point, end))
}

class OffsetPosition(sourceIn: SourceFile, pointIn: Int) extends DefinedPosition {
  override def isRange = false
  override def source  = sourceIn
  override def point   = pointIn
  override def start   = point
  override def end     = point
}
class RangePosition(sourceIn: SourceFile, startIn: Int, pointIn: Int, endIn: Int) extends OffsetPosition(sourceIn, pointIn) {
  override def isRange = true
  override def start   = startIn
  override def end     = endIn
}
class TransparentPosition(sourceIn: SourceFile, startIn: Int, pointIn: Int, endIn: Int) extends RangePosition(sourceIn, startIn, pointIn, endIn) {
  override def isTransparent = true
}
case object NoPosition extends UndefinedPosition
case class FakePos(msg: String) extends UndefinedPosition {
  override def toString = msg
}

sealed abstract class DefinedPosition extends Position {
  final override def isDefined = true
  override def equals(that: Any) = that match {
    case that: DefinedPosition => source.file == that.source.file && start == that.start && point == that.point && end == that.end
    case _                     => false
  }
  override def hashCode = Seq[Any](source.file, start, point, end).##
  override def toString = (
    if (isRange) s"RangePosition($canonicalPath, $start, $point, $end)"
    else s"source-$canonicalPath,line-$line,$pointMessage$point"
  )
  private def pointMessage  = if (point > source.length) "out-of-bounds-" else "offset="
  private def canonicalPath = source.file.canonicalPath
}

sealed abstract class UndefinedPosition extends Position {
  final override def isDefined = false
  override def isRange         = false
  override def source          = NoSourceFile
  override def start           = fail("start")
  override def point           = fail("point")
  override def end             = fail("end")
}

private[util] trait InternalPositionImpl {
  self: Position =>

  // The methods which would be abstract in Position if it were
  // possible to change Position.
  def isDefined: Boolean
  def isRange: Boolean
  def source: SourceFile
  def start: Int
  def point: Int
  def end: Int

  /** Map this position to its position in the original source file
   *  (which may be this position unchanged.)
   */
  def finalPosition: Pos = source positionInUltimateSource this

  def isTransparent              = false
  def isOffset                   = isDefined && !isRange
  def isOpaqueRange              = isRange && !isTransparent
  def pointOrElse(alt: Int): Int = if (isDefined) point else alt
  def makeTransparent: Position  = if (isOpaqueRange) Position.transparent(source, start, point, end) else this

  /** Copy a range position with a changed value.
   */
  def withStart(start: Int): Position          = copyRange(start = start)
  def withPoint(point: Int): Position          = if (isRange) copyRange(point = point) else Position.offset(source, point)
  def withEnd(end: Int): Position              = copyRange(end = end)
  def withSource(source: SourceFile): Position = copyRange(source = source)
  def withShift(shift: Int): Position          = Position.range(source, start + shift, point + shift, end + shift)

  /** Convert a range position to a simple offset.
   */
  def focusStart: Position = if (this.isRange) asOffset(start) else this
  def focus: Position      = if (this.isRange) asOffset(point) else this
  def focusEnd: Position   = if (this.isRange) asOffset(end) else this

  /** If you have it in for punctuation you might not like these methods.
   *  However I think they're aptly named.
   *
   *    |   means union
   *    ^   means "the point" (look, it's a caret)
   *    |^  means union, taking the point of the rhs
   *    ^|  means union, taking the point of the lhs
   */
  def |(that: Position, poses: Position*): Position = poses.foldLeft(this | that)(_ | _)
  def |(that: Position): Position                   = this union that
  def ^(point: Int): Position                       = this withPoint point
  def |^(that: Position): Position                  = (this | that) ^ that.point
  def ^|(that: Position): Position                  = (this | that) ^ this.point

  def union(pos: Position): Position = (
    if (!pos.isRange) this
    else if (this.isRange) copyRange(start = start min pos.start, end = end max pos.end)
    else pos
  )

  def includes(pos: Position): Boolean         = isRange && pos.isDefined && start <= pos.start && pos.end <= end
  def properlyIncludes(pos: Position): Boolean = includes(pos) && (start < pos.start || pos.end < end)
  def precedes(pos: Position): Boolean         = bothDefined(pos) && end <= pos.start
  def properlyPrecedes(pos: Position): Boolean = bothDefined(pos) && end < pos.start
  def sameRange(pos: Position): Boolean        = bothRanges(pos) && start == pos.start && end == pos.end
  // This works because it's a range position invariant that S1 < E1 and S2 < E2.
  // So if S1 < E2 and S2 < E1, then both starts precede both ends, which is the
  // necessary condition to establish that there is overlap.
  def overlaps(pos: Position): Boolean         = bothRanges(pos) && start < pos.end && pos.start < end

  def line: Int           = if (hasSource) source.offsetToLine(point) + 1 else 0
  def column: Int         = if (hasSource) calculateColumn() else 0
  def lineContent: String = if (hasSource) source.lineToString(line - 1) else ""
  def lineCaret: String   = if (hasSource) " " * (column - 1) + "^" else ""
  @deprecated("use `lineCaret`", since="2.11.0")
  def lineCarat: String   = lineCaret

  def showError(msg: String): String = {
    def escaped(s: String) = {
      def u(c: Int) = f"\\u$c%04x"
      def uable(c: Int) = (c < 0x20 && c != '\t') || c == 0x7F
      if (s exists (c => uable(c))) {
        val sb = new StringBuilder
        s foreach (c => sb append (if (uable(c)) u(c) else c))
        sb.toString
      } else s
    }
    def errorAt(p: Pos) = {
      def where     = p.line
      def content   = escaped(p.lineContent)
      def indicator = p.lineCaret
      f"$where: $msg%n$content%n$indicator"
    }
    finalPosition match {
      case FakePos(fmsg) => s"$fmsg $msg"
      case NoPosition    => msg
      case pos           => errorAt(pos)
    }
  }
  def showDebug: String = toString
  def show = (
    if (isOpaqueRange) s"[$start:$end]"
    else if (isTransparent) s"<$start:$end>"
    else if (isDefined) s"[$point]"
    else "[NoPosition]"
  )

  private def asOffset(point: Int): Position = Position.offset(source, point)
  private def copyRange(source: SourceFile = source, start: Int = start, point: Int = point, end: Int = end): Position =
    Position.range(source, start, point, end)

  private def calculateColumn(): 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
  }
  private def hasSource                      = source ne NoSourceFile
  private def bothRanges(that: Position)     = isRange && that.isRange
  private def bothDefined(that: Position)    = isDefined && that.isDefined
}

/** Holding cell for methods unused and/or unnecessary. */
private[util] trait DeprecatedPosition {
  self: Position =>

  @deprecated("use `point`", "2.9.0") // Used in SBT 0.12.4
  def offset: Option[Int] = if (isDefined) Some(point) else None

  @deprecated("use `focus`", "2.11.0")
  def toSingleLine: Position = this

  @deprecated("use `line`", "2.11.0")
  def safeLine: Int = line

  @deprecated("use `showDebug`", "2.11.0")
  def dbgString: String = showDebug

  @deprecated("use `finalPosition`", "2.11.0")
  def inUltimateSource(source: SourceFile): Position = source positionInUltimateSource this

  @deprecated("use `lineCaret`", since="2.11.0")
  def lineWithCarat(maxWidth: Int): (String, String) = ("", "")

  @deprecated("Use `withSource(source)` and `withShift`", "2.11.0")
  def withSource(source: SourceFile, shift: Int): Position = this withSource source withShift shift

  @deprecated("Use `start` instead", "2.11.0")
  def startOrPoint: Int = if (isRange) start else point

  @deprecated("Use `end` instead", "2.11.0")
  def endOrPoint: Int = if (isRange) end else point
}

Other Scala source code examples

Here is a short list of links related to this Scala Position.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.