All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xerial.core.io.text.Scanner.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012 Taro L. Saito
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package xerial.core.io.text

import xerial.core.collection.CyclicArray
import xerial.core.log.Logger

//--------------------------------------
//
// Reader.scala
// Since: 2012/08/12 12:56
//
//--------------------------------------

/**
 * An interface for reading tokens
 * 
 * @author Taro L. Saito
 */
trait Scanner extends PositionMark {

  /**
   * End of the character. Usually -1
   */
  val EOF : Int = -1

  /**
   * Look-ahead the first character
   * @return
   */
  def first : Int

  /**
   * Proceeds a cursor by one
   */
  def consume : this.type

  /**
   * Returns true iff the reader reached the end of the stream
   * @return
   */
  def atEnd : Boolean

  /**
   * Close the stream
   */
  def close : Unit


  protected def cursor : Int
  protected def setCursor(c:Int) : Unit
}

trait TextScanner extends Scanner {
  /**
   * Returns the column position in the current line
   */
  def column : Int

  /**
   * Returns the current line number
   */
  def line : Int

}


trait PositionMark { this: Scanner =>

  def withMark[U](f: => U) : U = {
    mark
    try
      f
    finally
       removeLast
  }

  def mark : Unit
  def lastMark : Int
  def removeLast : Int

  /**
   * Return the character sequence from the last mark to the current cursor position
   */
  def selected : CharSequence

  /**
   * Return the character sequence from the first mark to the current cursor position
   * @return
   */
  def selectedFromFirstMark : CharSequence

  /**
   * Rewind the scanner cursor to the last marked position
   */
  def rewind : Unit
  def clearMarks : Unit
}

trait PositionMarkImpl extends PositionMark with Logger { this: Scanner =>

  private val markQueue = new CyclicArray[Int]

  def mark : Unit = {
    markQueue.append(cursor)
  }

  private def ensureNotEmpty = require(!markQueue.isEmpty, "no mark is set")


  def firstMark : Int = {
    ensureNotEmpty
    markQueue.peekFirst
  }

  def lastMark : Int = {
    ensureNotEmpty
    markQueue.peekLast
  }

  def removeLast : Int = {
    ensureNotEmpty
    markQueue.removeLast
  }

  /**
   * Rewind the scanner cursor to the last marked position. The last mark is preserved.
   */
  def rewind : Unit = {
    ensureNotEmpty
    trace(s"rewind to $lastMark")
    setCursor(markQueue.peekLast)
  }
  def clearMarks : Unit = markQueue.clear


  protected def shiftMarks(offset:Int) : Unit = {
    for(i <- 0 until markQueue.length)
      markQueue.update(i, markQueue(i) + offset)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy