sourcefile.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 239 行

SCALA
239
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author  Martin Odersky */// $Id: SourceFile.scala 13933 2008-02-08 14:46:32Z washburn $package scala.tools.nsc.utilimport scala.tools.nsc.io.{AbstractFile, VirtualFile}object SourceFile {  val LF: Char = 0x0A  val FF: Char = 0x0C  val CR: Char = 0x0D  val SU: Char = 0x1A  def isLineBreak(c: Int) = c match {  case LF|FF|CR|SU => true  case _ => false  }}/** abstract base class of a source file used in the compiler */abstract class SourceFile {  import SourceFile._  def content : RandomAccessSeq[Char] // normalized, must end in SU  def file    : AbstractFile  def isLineBreak(idx : Int) : Boolean  def length : Int  def position(offset: Int) : Position = {    assert(offset < length)    new OffsetPosition(this, offset)  }  def position(line: Int, column: Int) : Position = new OffsetPosition(this, lineToOffset(line) + column)  def offsetToLine(offset: Int): Int   def lineToOffset(index : Int): Int  /** Map a position to a position in the underlying source file.   *  For regular source files, simply return the argument.   */  def positionInUltimateSource(position: Position) = position  override def toString(): String = file.name /* + ":" + content.length */  def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString  def path = file.path  def beginsWith(offset: Int, text: String): Boolean  def skipWhitespace(offset: Int): Int  def lineToString(index: Int): String    def identifier(pos : Position, compiler  : scala.tools.nsc.Global) : Option[String] = None  }/** a file whose contents do not change over time */class BatchSourceFile(val file : AbstractFile, _content : Array[Char]) extends SourceFile {  import SourceFile._  def this(_file: AbstractFile) = this(_file, _file.toCharArray)  def this(sourceName: String, content: Array[Char]) =    this(new VirtualFile(sourceName), content)  override def equals(that : Any) = that match {    case that : BatchSourceFile => file == that.file    case _ => false  }  override def hashCode = file.hashCode      val content = _content // don't sweat it...  override val length = content.length  override def identifier(pos : Position, compiler : scala.tools.nsc.Global) = pos match {  case OffsetPosition(source,offset) if source == this =>     import java.lang.Character    var i = offset + 1    while (i < content.length &&       (compiler.syntaxAnalyzer.isOperatorPart(content(i)) ||       compiler.syntaxAnalyzer.isIdentifierPart(content(i)))) i = i + 1        assert(i > offset)    if (i <= content.length)      Some(new String(content, offset, i - offset))    else None  case _ => super.identifier(pos, compiler)  }        def isLineBreak(idx: Int) =    if (idx >= content.length) false    else if (!SourceFile.isLineBreak(content(idx))) false    else if (content(idx) == CR && content(idx + 1) == LF) false    else true    def beginsWith(offset: Int, text: String): Boolean = {    var idx = 0    while (idx < text.length()) {      if (offset + idx >= content.length) return false      if (content(offset + idx) != text.charAt(idx)) return false      idx += 1    }    return true  }  def skipWhitespace(offset: Int): Int =    if (content(offset).isWhitespace) skipWhitespace(offset + 1)    else offset  def lineToString(index: Int): String = {    var offset = lineToOffset(index)    val buf = new StringBuilder()    while (!isLineBreak(offset) && offset < content.length) {      buf.append(content(offset))      offset += 1    }    buf.toString()  }  object line {    var index  = 0    var offset = 0    def find(toFind: Int, isIndex: Boolean): Int = {      if (toFind == 0) return 0      if (!isIndex && (toFind >= content.length)) {        assert(true)        throw new Error(toFind + " not valid offset in " +                        file.name + ":" + content.length)      }      def get(isIndex : Boolean) = if (isIndex) index else offset      val isBackward = toFind <= get(isIndex)      val increment = if (isBackward) -1 else + 1      val oneIfBackward = if (isBackward) +1 else 0      while (true) {        if (!isIndex && offset == toFind) return index;        if (isBackward && offset <= 0)          throw new Error(offset + " " + index + " " + toFind + " " + isIndex);        offset = offset + increment        if (!isBackward) assert(offset < content.length);        if (isLineBreak(offset + (if (isBackward) 0 else -1))) {          index = index + increment          if (isIndex && index + oneIfBackward == toFind)             return offset + oneIfBackward;        }      }      throw new Error()    }  }  def offsetToLine(offset: Int): Int = line.find(offset, false)  def lineToOffset(index : Int): Int = line.find(index , true)  }/** A source file composed of multiple other source files. * *  @version 1.0 */class CompoundSourceFile(    name: String,    components: List[BatchSourceFile],    contents: Array[Char])extends BatchSourceFile(name, contents){  /** The usual constructor.  Specify a name for the compound file and   *  a list of component sources.   */  def this(name: String, components: BatchSourceFile*) = {    this(      name,      components.toList,      Array.concat(components.toList.map(comp =>         CompoundSourceFile.stripSU(comp.content).toArray):_*))  }  /** Create an instance with the specified components and a generic name. */  def this(components: BatchSourceFile*) =    this("(virtual file)", components.toList:_*)  override def positionInUltimateSource(position: Position) = {    if (position.offset.isEmpty) super.positionInUltimateSource(position)    else {      println("!!!")      var off = position.offset.get      var compsLeft = components      while (compsLeft.head.content.length-1 <= off && !compsLeft.tail.isEmpty) {        println("discarding "+compsLeft.head)        off = off - compsLeft.head.content.length + 1        compsLeft = compsLeft.tail      }      compsLeft.head.positionInUltimateSource(new OffsetPosition(this, off))    }  }}object CompoundSourceFile {  private[util] def stripSU(chars: Array[Char]) =    if (chars.length > 0 && chars.last == SourceFile.SU)      chars.slice(0, chars.length-1)    else      chars}/** One portion of an underlying file.  The fragment includes  * the indeces from the specified start (inclusively) to stop  * (not inclusively).  */class SourceFileFragment(    name: String,    underlyingFile: BatchSourceFile,    start: Int,    stop: Int,    contents: Array[Char])extends BatchSourceFile(name, contents) {  def this(name: String, underlyingFile: BatchSourceFile, start: Int, stop: Int) =    this(      name,      underlyingFile,      start,      stop,      { assert(start >= 0)        assert(start <= stop)        assert(start <= underlyingFile.length)        assert(stop <= underlyingFile.length)        underlyingFile.content.slice(start, stop).toArray })  def this(underlyingFile: BatchSourceFile, start: Int, stop: Int) =    this(      "(fragment of " + underlyingFile.file.name + ")",      underlyingFile,      start,      stop)  override def positionInUltimateSource(position: Position) = {    if (position.offset.isEmpty)      super.positionInUltimateSource(position)    else {      super.positionInUltimateSource(      new OffsetPosition(this, position.offset.get))    }  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?