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 + -
显示快捷键?