compiler/src/main/scala/amyc/utils/Position.scala
package amyc.utils
import java.io.File
import silex._
object Position {
/** Number of bits used to encode the line number */
private final val LINE_BITS = 20
/** Number of bits used to encode the column number */
private final val COLUMN_BITS = 31 - LINE_BITS // no negatives => 31
/** Mask to decode the line number */
private final val LINE_MASK = (1 << LINE_BITS) - 1
/** Mask to decode the column number */
private final val COLUMN_MASK = (1 << COLUMN_BITS) - 1
private def lineOf(pos: Int): Int = (pos >> COLUMN_BITS) & LINE_MASK
private def columnOf(pos: Int): Int = pos & COLUMN_MASK
def fromFile(f: File, i: Int) = {
SourcePosition(f, lineOf(i), columnOf(i))
}
def withPosition[A <: Positioned](position: Position)(body : => A) : A =
body.setPos(position)
}
abstract class Position {
val file: File
val line: Int
val col: Int
def isDefined: Boolean
def withoutFile: String
}
case class SourcePosition(file: File, line: Int, col: Int) extends Position {
override def toString: String = s"${file.getPath}:$line:$col"
def withoutFile = s"$line:$col"
val isDefined = true
}
case object NoPosition extends Position {
val file = null
val line = 0
val col = 0
override def toString: String = "?:?"
def withoutFile = toString
val isDefined = false
}
// A trait for entities which have a position in a file
trait Positioned {
protected var pos_ : Position = NoPosition
def hasPosition = pos_ != NoPosition
def position = pos_
def setPos(pos: Position): this.type = {
pos_ = pos
this
}
def setPos(other: Positioned): this.type = {
setPos(other.position)
}
}
case class SourcePositioner(file: File) extends Positioner[Char, SourcePosition] {
override val start: SourcePosition = SourcePosition(file, 1, 1)
override def increment(position: SourcePosition, character: Char): SourcePosition =
if (character == '\n') {
position.copy(line = position.line + 1, col = 1)
}
else {
position.copy(col = position.col + 1)
}
}