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

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

package fastparse.parsers
import acyclic.file
import fastparse.utils.Utils._
import fastparse.core.{ParseCtx, Parsed, Parser, Precedence}
import fastparse.utils.{ElemSetHelper, ReprOps, Utils}

/**
 * High-performance intrinsics for parsing common patterns. All
 * of these have equivalent to constructs that can be put together
 * using a combination of "string"s, p1 | p2, and p.rep, but much
 * faster or more convenient.
 */
object Intrinsics {

  abstract class ElemSet[Elem, Repr](elems: Seq[Elem])
                                    (implicit helper: ElemSetHelper[Elem],
                                     repr: ReprOps[Elem, Repr])
      extends Parser[Unit, Elem, Repr]{
    private[this] val uberSet = BitSet(elems)
    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      val input = cfg.input
      if (!input.isReachable(index)) fail(cfg.failure, index)
      else if (uberSet(input(index))) success(cfg.success, (), index + 1, Set.empty, false)
      else fail(cfg.failure, index)
    }
  }
  /**
   * Parses a single character if it passes the predicate
   */
  case class ElemPred[Elem, Repr](name: String,
                                  predicate: Elem => Boolean)
                                 (implicit helper: ElemSetHelper[Elem],
                                  repr: ReprOps[Elem, Repr])
    extends ElemSet[Elem, Repr](helper.allValues.filter(predicate)){

    override def toString = s"$name($predicate)"
  }

  /**
   * Parses a single character if its contained in the lists of allowed characters
   */
  case class ElemIn[Elem, Repr](name: String,
                                strings: Seq[Elem]*)
                               (implicit repr: ReprOps[Elem, Repr],
                                ehelper: ElemSetHelper[Elem])
      extends ElemSet[Elem, Repr](repr.toArray(repr.flatten(strings.map(repr.fromSeq)))){
    override def toString = s"$name(${repr.literalize(repr.flatten(strings.map(repr.fromSeq)))})"
  }

  /**
   * Keeps consuming characters until the predicate [[pred]] becomes false.
   * Functionally equivalent to using `.rep` and [[ElemPred]], but much faster.
   */
  case class ElemsWhile[Elem, Repr](name: String,
                                        pred: Elem => Boolean, min: Int = 1)
                                       (implicit helper: ElemSetHelper[Elem],
                                        repr: ReprOps[Elem, Repr])
      extends Parser[Unit, Elem, Repr]{
    private[this] val uberSet = BitSet(helper.allValues.filter(pred))

    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      var curr = index
      val input = cfg.input
      while(input.isReachable(curr) && uberSet(input(curr))) curr += 1
      if (curr - index < min) fail(cfg.failure, curr)
      else success(cfg.success, (), curr, Set.empty, false)
    }
    override def toString = s"$name($pred)"
  }
  /**
   * Very efficiently attempts to parse a set of strings, by
   * first converting it into an array-backed Trie and then walking it once.
   * If multiple strings match the input, longest match wins.
   */
  class StringInBase[Elem, Repr](ignoreCase: Boolean, strings: Repr*)
                                (implicit repr: ReprOps[Elem, Repr],
                                 helper: ElemSetHelper[Elem],
                                 ordering: Ordering[Elem])
      extends Parser[Unit, Elem, Repr] {

    private[this] val trie = new TrieNode[Elem](strings.map(repr.toArray(_): IndexedSeq[Elem]), ignoreCase)

    def parseRec(cfg: ParseCtx[Elem, Repr], index: Int) = {
      val length = trie.query(cfg.input, index)
      if (length != -1) success(cfg.success, (), index + length + 1, Set.empty, false)
      else fail(cfg.failure, index)
    }
    override def toString = {
      s"StringIn(${strings.map(repr.literalize).mkString(", ")})"
    }
  }

  case class StringIn[Elem, Repr](strings: Repr*)
                                 (implicit repr: ReprOps[Elem, Repr],
                                  helper: ElemSetHelper[Elem],
                                  ordering: Ordering[Elem]) extends StringInBase(false, strings:_*)

  case class StringInIgnoreCase[Elem, Repr](strings: Repr*)
                                           (implicit repr: ReprOps[Elem, Repr],
                                            helper: ElemSetHelper[Elem],
                                            ordering: Ordering[Elem]) extends StringInBase(true, strings:_*)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy