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

fastparse.parsers.Terminals.scala Maven / Gradle / Ivy

The newest version!
package scala.meta.internal.fastparse.parsers
// import acyclic.file
import scala.meta.internal.fastparse.utils.{ParserInput, ReprOps}
import scala.meta.internal.fastparse.core.ParseCtx

import scala.annotation.tailrec
import scala.meta.internal.fastparse.core.Parser

import scala.collection.mutable.ArrayBuffer
/**
 * Leaf parsers which do not contain any other
 * parsers, and do simple things
 */
object Terminals {

  /**
   * A parser that always succeeds, consuming no input
   */
  case class Pass[Elem, Repr]()(implicit repr: ReprOps[Elem, Repr]) extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = success(cfg.success, (), index, Set.empty, false)
    override val toString = "Pass"
  }

  /**
    * A parser that always succeeds with given result value `t`, consuming no input
    */
  case class PassWith[T, Elem, Repr](t: T)(implicit repr: ReprOps[Elem, Repr]) extends Parser[T, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = success(cfg.success, t, index, Set.empty, false)
  }

  /**
   * A parser that always fails immediately
   */
  case class Fail[Elem, Repr]()(implicit repr: ReprOps[Elem, Repr]) extends Parser[Nothing, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = fail(cfg.failure, index)
    override val toString = "Fail"
  }
  /**
   * Succeeds, consuming a single element
   */
  case class AnyElem[Elem, Repr](name: String)(implicit repr: ReprOps[Elem, Repr]) extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      val input = cfg.input
      if (!input.isReachable(index)) fail(cfg.failure, index)
      else success(cfg.success, (), index+1, Set.empty, false)
    }
    override val toString = name
  }
  /**
   * Consumes up to `count` elements, if they are available
   */
  case class AnyElems[Elem, Repr](name: String, count: Int)(implicit repr: ReprOps[Elem, Repr]) extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      val input = cfg.input
      if (!input.isReachable(index + count - 1)) fail(cfg.failure, index)
      else success(cfg.success, (), index + count, Set.empty, false)
    }
    override val toString = name + "(" + count + ")"
  }

  /**
   * Succeeds if at the start of the input, consuming no input
   */

  case class Start[Elem, Repr]()(implicit repr: ReprOps[Elem, Repr]) extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      if (index == 0) success(cfg.success, (), index, Set.empty, false)
      else fail(cfg.failure, index)
    }
    override val toString = "Start"
  }

  /**
   * Succeeds if at the end of the input, consuming no input
   */
  case class End[Elem, Repr]()(implicit repr: ReprOps[Elem, Repr]) extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      if (!cfg.input.isReachable(index)) success(cfg.success, (), index, Set.empty, false)
      else fail(cfg.failure, index)
    }
    override val toString = "End"
  }

  /**
   * Workaround https://github.com/scala-js/scala-js/issues/1603
   * by implementing startsWith myself
   */
  def startsWith[Elem, Repr](src: ParserInput[Elem, Repr], prefix: Repr, offset: Int)
                                (implicit repr: ReprOps[Elem, Repr])= {
    @tailrec def rec(i: Int): Boolean = {
      if (i >= repr.length(prefix)) true
      else if (!src.isReachable(i + offset)) false
      else if (src(i + offset) != repr.apply(prefix, i)) false
      else rec(i + 1)
    }
    rec(0)
  }

  def startsWithIgnoreCase(src: ParserInput[Char, String], prefix: IndexedSeq[Char], offset: Int) = {
    val max = prefix.length
    @tailrec def rec(i: Int): Boolean = {
      if (i >= prefix.length) true
      else if (!src.isReachable(i + offset)) false
      else {
        val c1: Char = src(i + offset)
        val c2: Char = prefix(i)
        if (c1 != c2 && c1.toLower != c2.toLower) false
        else rec(i + 1)
      }
    }
    rec(0)
  }

  /**
   * Parses a literal `IndexedSeq[Elem]`
   */
  case class Literal[Elem, Repr](s: Repr)
                                (implicit repr: ReprOps[Elem, Repr])
       extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {

      if (startsWith(cfg.input, s, index)) success(cfg.success, (), index + repr.length(s), Set.empty, false)
      else fail(cfg.failure, index)
    }
    override def toString = repr.literalize(s)
  }

  /**
   * Parses a literal `String` ignoring case
   */
  case class IgnoreCase(s: IndexedSeq[Char])
                       (implicit repr: ReprOps[Char, String])
       extends Parser[Unit, Char, String](){

    def parseRec(cfg: ParseCtx[Char, String], index: Int) = {
      if (startsWithIgnoreCase(cfg.input, s, index)) success(cfg.success, (), index + s.length, Set.empty, false)
      else fail(cfg.failure, index)
    }
    override def toString = repr.literalize(s.mkString)
  }

  /**
   * Parses a single element
   */
  case class ElemLiteral[Elem, Repr](c: Elem)
                                    (implicit repr: ReprOps[Elem, Repr])
       extends Parser[Unit, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      val input = cfg.input
      if (!input.isReachable(index)) fail(cfg.failure, index)
      else if (input(index) == c) success(cfg.success, c.toString, index + 1, Set.empty, false)
      else fail(cfg.failure, index)
    }
    override def toString = repr.literalize(repr.fromSingle(c)).toString
  }

  /**
   * Always succeeds, and provides the current index of the
   * parse into the input. e.g. useful for providing
   * source locations for AST nodes. Consumes no input.
   */
  case class Index[Elem, Repr]()(implicit repr: ReprOps[Elem, Repr]) extends Parser[Int, Elem, Repr]{
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      success(cfg.success, index, index, Set.empty, false)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy