parsers.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 741 行 · 第 1/3 页

SCALA
741
字号
/*                     __                                               *\**     ________ ___   / /  ___     Scala API                            ****    / __/ __// _ | / /  / _ |    (c) 2006-2007, LAMP/EPFL             ****  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **** /____/\___/_/ |_/____/_/ | |                                         ****                          |/                                          **\*                                                                      */// $Id: Parsers.scala 14415 2008-03-19 00:53:09Z mihaylov $package scala.util.parsing.combinatorimport scala.util.parsing.input._import scala.collection.mutable.{Map=>MutableMap}// TODO: better error handling (labelling like parsec's <?>)// TODO: memoisation (like packrat parsers?) /** <p> *    <code>Parsers</code> is a component that <i>provides</i> generic *    parser combinators. *  </p> *  <p> *    It <i>requires</i> the type of the elements these parsers should parse  *    (each parser is polymorphic in the type of result it produces). *  </p> *  <p> *    There are two aspects to the result of a parser: (1) success or failure, *    and (2) the result. A <code>Parser[T]</code> provides both kinds of *    information. *  </p> *  <p> *    The term ``parser combinator'' refers to the fact that these parsers *    are constructed from primitive parsers and composition operators, such *    as sequencing, alternation, optionality, repetition, lifting, and so on. *  </p> *  <p> *    A ``primitive parser'' is a parser that accepts or rejects a single *    piece of input, based on a certain criterion, such as whether the *    input... *  </p><ul> *    <li> is equal to some given object, </li> *    <li> satisfies a certain predicate, </li> *    <li> is in the domain of a given partial function,.... </li> *  </ul> *  <p> *    Even more primitive parsers always produce the same result, irrespective *    of the input. *  </p> * * @requires Elem the type of elements the provided parsers consume  *              (When consuming invidual characters, a parser is typically called a ``scanner'',  *               which produces ``tokens'' that are consumed by what is normally called a ``parser''. *               Nonetheless, the same principles apply, regardless of the input type.)</p> *<p> * @provides Input = Reader[Elem]  *              The type of input the parsers in this component expect.</p> *<p> * @provides Parser[+T] extends (Input => ParseResult[T])  *              Essentially, a `Parser[T]' is a function from `Input' to `ParseResult[T]'.</p> *<p> * @provides ParseResult[+T] is like an `Option[T]', in the sense that it is either *              `Success[T]', which consists of some result (:T) (and the rest of the input) or *              `Failure[T]', which provides an error message (and the rest of the input).</p> * * @author Martin Odersky, Iulian Dragos, Adriaan Moors  */trait Parsers {  /** the type of input elements */  type Elem  /** The parser input is an abstract reader of input elements */  type Input = Reader[Elem]  /** A base class for parser results.    *  A result is either successful or not (failure may be fatal, i.e.,   *  an Error, or not, i.e., a Failure)   *  On success, provides a result of type <code>T</code>.    */  sealed abstract class ParseResult[+T] {    /** Functional composition of ParseResults     *      * @param `f' the function to be lifted over this result     * @return `f' applied to the result of this `ParseResult', packaged up as a new `ParseResult'     */    def map[U](f: T => U): ParseResult[U]        /** Partial functional composition of ParseResults     *      * @param `f' the partial function to be lifted over this result     * @param error a function that takes the same argument as `f' and produces an error message      *        to explain why `f' wasn't applicable (it is called when this is the case)     * @return <i>if `f' f is defined at the result in this `ParseResult',</i>     *         `f' applied to the result of this `ParseResult', packaged up as a new `ParseResult'.     *         If `f' is not defined, `Failure'.     */    def mapPartial[U](f: PartialFunction[T, U], error: T => String): ParseResult[U]           def flatMapWithNext[U](f: T => Input => ParseResult[U]): ParseResult[U]         def append[U >: T](a: => ParseResult[U]): ParseResult[U]        def isEmpty = !successful        /** Returns the embedded result */    def get: T        def getOrElse[B >: T](default: => B): B =         if (isEmpty) default else this.get        val next: Input        val successful: Boolean  }  /** The success case of ParseResult: contains the result and the remaining input.   *   *  @param result The parser's output    *  @param next   The parser's remaining input   */  case class Success[+T](result: T, override val next: Input) extends ParseResult[T] {    def map[U](f: T => U) = Success(f(result), next)    def mapPartial[U](f: PartialFunction[T, U], error: T => String): ParseResult[U]        = if(f.isDefinedAt(result)) Success(f(result), next)          else Failure(error(result), next)    def flatMapWithNext[U](f: T => Input => ParseResult[U]): ParseResult[U]       = f(result)(next)     def append[U >: T](a: => ParseResult[U]): ParseResult[U] = this    def get: T = result        /** The toString method of a Success */    override def toString = "["+next.pos+"] parsed: "+result        val successful = true  }  var lastNoSuccess: NoSuccess = null  /** A common super-class for unsuccessful parse results   */  sealed abstract class NoSuccess(val msg: String, override val next: Input) extends ParseResult[Nothing] { // when we don't care about the difference between Failure and Error    val successful = false    if (!(lastNoSuccess != null && next.pos < lastNoSuccess.next.pos))      lastNoSuccess = this    def map[U](f: Nothing => U) = this    def mapPartial[U](f: PartialFunction[Nothing, U], error: Nothing => String): ParseResult[U] = this    def flatMapWithNext[U](f: Nothing => Input => ParseResult[U]): ParseResult[U]       = this    def get: Nothing = error("No result when parsing failed")  }    /** The failure case of ParseResult: contains an error-message and the remaining input.   * Parsing will back-track when a failure occurs.   *   *  @param msg    An error message string describing the failure.   *  @param next   The parser's unconsumed input at the point where the failure occurred.   */  case class Failure(override val msg: String, override val next: Input) extends NoSuccess(msg, next) {    /** The toString method of a Failure yields an error message */    override def toString = "["+next.pos+"] failure: "+msg+"\n\n"+next.pos.longString        def append[U >: Nothing](a: => ParseResult[U]): ParseResult[U] = { val alt = a; alt match {      case Success(_, _) => alt      case ns: NoSuccess => if (alt.next.pos < next.pos) this else alt    }}  }    /** The fatal failure case of ParseResult: contains an error-message and the remaining input.   * No back-tracking is done when a parser returns an `Error'    *   *  @param msg    An error message string describing the error.   *  @param next   The parser's unconsumed input at the point where the error occurred.   */  case class Error(override val msg: String, override val next: Input) extends NoSuccess(msg, next) {    /** The toString method of an Error yields an error message */    override def toString = "["+next.pos+"] error: "+msg+"\n\n"+next.pos.longString    def append[U >: Nothing](a: => ParseResult[U]): ParseResult[U] = this  }    def Parser[T](f: Input => ParseResult[T]): Parser[T]     = new Parser[T]{ def apply(in: Input) = f(in) }    def OnceParser[T](f: Input => ParseResult[T]): Parser[T] with OnceParser[T]     = new Parser[T] with OnceParser[T] { def apply(in: Input) = f(in) }    /** The root class of parsers.    *  Parsers are functions from the Input type to ParseResult    */  abstract class Parser[+T] extends (Input => ParseResult[T]) {    private var name: String = ""    def named(n: String): this.type = {name=n; this}    override def toString() = "Parser ("+ name +")"        /** An unspecified method that defines the behaviour of this parser.     */    def apply(in: Input): ParseResult[T]    def flatMap[U](f: T => Parser[U]): Parser[U]      = Parser{ in => this(in) flatMapWithNext(f)}                                          def map[U](f: T => U): Parser[U] //= flatMap{x => success(f(x))}      = Parser{ in => this(in) map(f)}    // no filter yet, dealing with zero is tricky!      def append[U >: T](p: => Parser[U]): Parser[U]       = Parser{ in => this(in) append p(in)}                                          // the operator formerly known as +++, ++, &, but now, behold the venerable ~    // it's short, light (looks like whitespace), has few overloaded meaning (thanks to the recent change from ~ to unary_~)    // and we love it! (or do we like `,` better?)                                          /** A parser combinator for sequential composition      *     * <p> `p ~ q' succeeds if `p' succeeds and `q' succeeds on the input     *          left over by `p'.</p>     *      * @param q a parser that will be executed after `p' (this parser) succeeds     * @return a `Parser' that -- on success -- returns a `~' (like a Pair, but easier to pattern match on)      *         that contains the result of `p' and that of `q'.      *         The resulting parser fails if either `p' or `q' fails.     */    def ~ [U](p: => Parser[U]): Parser[~[T, U]] = (for(a <- this; b <- p) yield new ~(a,b)).named("~")    def ~> [U](p: => Parser[U]): Parser[U] = (for(a <- this; b <- p) yield b).named("~>")    def <~ [U](p: => Parser[U]): Parser[T] = (for(a <- this; b <- p) yield a).named("<~")        /* not really useful: V cannot be inferred because Parser is covariant in first type parameter (V is always trivially Nothing)    def ~~ [U, V](q: => Parser[U])(implicit combine: (T, U) => V): Parser[V] = new Parser[V] {      def apply(in: Input) = seq(Parser.this, q)((x, y) => combine(x,y))(in)    }  */       /** A parser combinator for non-back-tracking sequential composition      *     *<p>`p ~! q' succeeds if `p' succeeds and `q' succeeds on the input     *          left over by `p'. In case of failure, no back-tracking is performed      *          (in an earlier parser produced by the | combinator).</p>     * 

⌨️ 快捷键说明

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