hamzaremmal/amy

View on GitHub
compiler/src/main/scala/amyc/utils/Position.scala

Summary

Maintainability
A
0 mins
Test Coverage
C
72%
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)
    }
}