parsers.scala

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

SCALA
961
字号
     */    def ^? [U](f: PartialFunction[T, U], error: T => String): Parser[U] = new Parser[U] {      def apply(in: Input) = Parser.this(in).mapPartial(f, error)      override def toString = Parser.this.toString+"^?"    }             /** A parser combinator for partial function application      *     *<p>`p ^? f' succeeds if `p' succeeds AND `f' is defined at the result of `p';      *  in that case, it returns `f' applied to the result of `p'.</p>     *     * @param f a partial function that will be applied to this parser's result      *          (see `mapPartial' in `ParseResult').     * @return a parser that succeeds if the current parser succeeds <i>and</i> `f' is applicable      *         to the result. If so, the result will be transformed by `f'.          */    def ^? [U](f: PartialFunction[T, U]): Parser[U] = new Parser[U] {      def apply(in: Input) = Parser.this(in).mapPartial(f, result => "Constructor function not defined at "+result)      override def toString = Parser.this.toString+"^?"    }                      /** A parser combinator that parameterises a subsequent parser with the result of this one     *     *<p>     * Use this combinator when a parser depends on the result of a previous parser. `p' should be     * a function that takes the result from the first parser and returns the second parser.</p>     *     *<p> `p into fq' (with `fq' typically `{x => q}') first applies `p', and then, if `p' successfully       *    returned result `r', applies `fq(r)' to the rest of the input. </p>     *     *<p> From: G. Hutton. Higher-order functions for parsing. J. Funct. Program., 2(3):323--343, 1992. </p>     *     * @param fq a function that, given the result from this parser, returns the second parser to be applied     * @return a parser that succeeds if this parser succeeds (with result `x') and if then `fq(x)' succeeds     */    def into[U](fq: T => Parser[U]): Parser[U] = new Parser[U] {       def apply(in: Input) = Parser.this(in) match {         case Success(result, next) => fq(result)(next)         case ns: NoSuccess => ns       }     }        // shortcuts for combinators:        /** Returns into(fq) */    def >>[U](fq: T => Parser[U])=into(fq)            /** Returns a parser that repeatedly parses what this parser parses     *     * @return rep(this)      */    def * = rep(this)        /** Returns a parser that repeatedly parses what this parser parses, interleaved with the `sep' parser.     *     * @return repsep(this, sep)     */    def *[Q <% UnitParser](sep: => Q) = repsep(this, sep)        /** Returns a parser that repeatedly parses what this parser parses, interleaved with the `sep' parser.     * The `sep' parser specifies how the results parsed by this parser should be combined.     *     * @return chainl1(this, sep)      */        def *[U >: T](sep: => Parser[(U, U) => U]) = chainl1(this, sep)        // TODO: improve precedence? a ~ b*(",") = a ~ (b*(","))  should be true         /** Returns a parser that repeatedly (at least once) parses what this parser parses.     *     * @return rep1(this)      */          def + = rep1(this)        /** Returns a parser that optionally parses what this parser parses.     *     * @return opt(this)      */           def ? = opt(this)  }  /** The root class of special parsers returning the trivial result <code>Unit</code>   *  These compose differently from normal parsers in that the <code>Unit</code>   *  result in a sequential or function composition is dropped.   */  abstract class UnitParser extends (Input => ParseResult[Unit]) {                                          /** An unspecified method that defines the behaviour of this parser.     */    def apply(in: Input): ParseResult[Unit]    /** 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 the result of `q'.      *         The resulting parser fails if either `p' or `q' fails.     */    def ~ [U](q: => Parser[U]): Parser[U] = new Parser[U] {      def apply(in: Input): ParseResult[U] = seq(UnitParser.this, q)((x, y) => y)(in)      override def toString = "~"    }         /** A parser combinator for sequential composition with a unit-parser      *     * <p>`p ~ q' succeeds if `p' succeeds and `q' succeeds on the input     *          left over by `p'.</p>     *     * @param q a parser (convertible to a UnitParser) that will be executed after `p' (this parser)     *          succeeds     * @return a `UnitParser' that fails if either `p' or `q' fails.      */     def ~ [A <% UnitParser](q: => A): UnitParser = new UnitParser {      def apply(in: Input): ParseResult[Unit] = seq(UnitParser.this, q)((x, y) => y)(in)      override def toString = "~"    }         /** 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>     *      * @param q a parser that will be executed after `p' (this parser) succeeds     * @return a `Parser' that -- on success -- returns the result of `q`.      *         The resulting parser fails if either `p' or `q' fails, this failure is fatal.     */    def ~! [U](q: => Parser[U]): Parser[U] = new Parser[U] with OnceParser[U] {      def apply(in: Input) = seq(UnitParser.this, commit(q))((x, y) => y)(in)      override def toString = "~!"    }    /** A parser combinator for non-back-tracking sequential composition with a unit-parser     *     *  <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>     *      * @param q a parser that will be executed after `p' (this parser) succeeds     * @return a `UnitParser' that fails if either `p' or `q' fails, this failure is fatal.     */    def ~! [Q <% UnitParser](q: => Q): UnitParser = new UnitParser with UnitOnceParser {      def apply(in: Input) = seq(UnitParser.this, commit(q))((x, y) => y)(in)      override def toString = "~!"    }     /** A parser combinator for alternative composition      *     *<p>`p | q' succeeds if `p' succeeds or `q' succeeds     *          Note that `q' is only tried if `p's failure is non-fatal (i.e., back-tracking is     *          allowed).</p>     *      * @param q a parser that will be executed if `p' (this parser) fails (and allows back-tracking)     * @return a `Parser' succeeds if (and only if) <ul>     *           <li> `p' succeeds, <i>or</i>  </li>     *           <li> if `p' fails allowing back-tracking and `q' succeeds. </li> </ul>     */    def | [Q <% UnitParser](q: => Q): UnitParser = new UnitParser {      def apply(in: Input) = UnitParser.this(in) match {        case s1 @ Success(_, _) => s1        case e1 @ Error(_, _) => e1        case f1 @ Failure(_, next1) => q(in) match {              case s2 @ Success(_, _) => s2              case f2 @ Failure(_, next2) => if (next2.pos < next1.pos) f1 else f2              case e2 @ Error(_, next2) => if (next2.pos < next1.pos) f1 else e2        }      }      override def toString = "|"    }        /** A parser combinator for alternative with longest match composition      *     *<p>`p ||| q' succeeds if `p' succeeds or `q' succeeds     *          If `p' and `q' both succeed, the parser that consumed the most     *          characters accepts.</p>     *      * @param q a parser that accepts if p consumes less characters.     * @return a `Parser' that returns the result of the parser consuming the most characteres (out of `p' and `q').     */    def ||| [Q <% UnitParser](q: => Q): UnitParser = new UnitParser {      def apply(in: Input) = {        val res1 = UnitParser.this(in)        val res2 = q(in)                (res1, res2) match {          case (s1 @ Success(_, next1), s2 @ Success(_, next2)) => if (next2.pos < next1.pos) s1 else s2          case (s1 @ Success(_, _), _) => s1          case (_, s2 @ Success(_, _)) => s2          case (e1 @ Error(_, _), _) => e1          case (f1 @ Failure(_, next1), f2 @ Failure(_, next2)) => if (next2.pos < next1.pos) f1 else f2          case (f1 @ Failure(_, next1), e2 @ Error(_, next2)) => if (next2.pos < next1.pos) f1 else e2        }      }      override def toString = "|||"    }              /** A parser combinator for function application      *     *  <p>`p ^^ v' succeeds if `p' succeeds; it returns `v'.</p>     *     * @param v a value that's used as the result of the returned Parser (if it was successful).     * @return a parser that has the same behaviour as the current parser, but whose result is     *         consists of `v'.     */    def ^^ [U](v: U): Parser[U] = new Parser[U] {      def apply(in: Input) = UnitParser.this(in).map(x => v)      override def toString = UnitParser.this.toString+"^^"    }  }  // TODO: can this implemented in ParseResult, like map?  /** A helper method for sequential composition of (unit-)parsers  */  private def seq[T, U, V](p: => Input => ParseResult[T], q: => Input => ParseResult[U])                          (compose: (T, U) => V)                          (in: Input): ParseResult[V]     = p(in) match {      case Success(x, next1) => q(next1) match {          case Success(y, next2) => Success(compose(x, y), next2)          case ns: NoSuccess => ns        }      case ns: NoSuccess => ns    }    /** Wrap a parser so that its failures become errors (the | combinator will give up as soon as    *  it encounters an error, on failure it simply tries the next alternative)    */  def commit[T](p: => Parser[T]) = new Parser[T] {    def apply(in: Input) = p(in) match{      case s @ Success(_, _) => s      case e @ Error(_, _) => e      case f @ Failure(msg, next) => Error(msg, next)    }  }    /** Wrap a parser so that its failures become errors (the | combinator will give up as soon as    *  it encounters an error, on failure it simply tries the next alternative)    */  def commit[Q <% UnitParser](p: => Q) = new UnitParser {    def apply(in: Input) = p(in) match{      case s @ Success(_, _) => s      case e @ Error(_, _) => e      case f @ Failure(msg, next) => Error(msg, next)    }  }    /** Wrap a parser so that its failures&errors become success and vice versa -- it never consumes any input    */  def not[Q <% UnitParser](p: => Q) = new UnitParser {    def apply(in: Input) = p(in) match{      case s @ Success(_, _) => Failure("Expected failure", in)      case e @ Error(_, _) => Success((), in)      case f @ Failure(msg, next) => Success((), in)    }  }    	/*trait ElemFun  case class EFCons(hd: Elem => ElemFun, tl: ElemFun) extends ElemFun  case class EFNil(res: Boolean) extends ElemFun*/     /** A parser matching input elements that satisfy a given predicate   *   * <p>elem(kind, p) succeeds if the input starts with an element `e' for which p(e) is true.</p>   *   * @param  kind   The element kind, used for error messages   * @param  p      A predicate that determines which elements match.   * @return    */  def elem(kind: String, p: Elem => Boolean) = new Parser[Elem] {    def apply(in: Input) =      if (p(in.first)) Success(in.first, in.rest)      else Failure(kind+" expected", in)  }       /** A parser that matches only the given element `e'   *   * <p>elem(e) succeeds if the input starts with an element `e'</p>   *   * @param e the `Elem' that must be the next piece of input for the returned parser to succeed   * @return a `Parser' that succeeds if `e' is the next available input (and returns it).   */  def elem(e: Elem): Parser[Elem] = new Parser[Elem] {    def apply(in: Input) =      if (in.first == e) Success(e, in.rest)      else Failure("`"+e+"' expected but " + in.first + " found", in)  }      /** A parser that matches only the given element `e'    *<p>   * The method is implicit so that elements can automatically be lifted to their unit-parsers.    * For example, when parsing `Token's, Identifier("new") (which is a `Token') can be used directly,   * instead of first creating a `UnitParser' using accept(Identifier("new")).</p>   *   * @param e the `Elem' that must be the next piece of input for the returned parser to succeed   * @return a `UnitParser' that succeeds if `e' is the next available input.   */  implicit def accept(e: Elem): UnitParser = new UnitParser {    def apply(in: Input) =      if (in.first == e) Success((), in.rest)      else Failure("`"+e+"' expected but " + in.first + " found", in)  }     /** A parser that matches only the given list of element `es'   *   * <p>accept(es) succeeds if the input subsequently provides the elements in the list `es'.</p>   *   * @param  es the list of expected elements   * @return a UnitParser that recognizes a specified list of elements   */  def accept[ES <% List[Elem]](es: ES): UnitParser = new UnitParser {    def apply(in0: Input) = {      var res = new scala.collection.mutable.ListBuffer[Elem]      var these: List[Elem] = es      var in = in0

⌨️ 快捷键说明

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