parsers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 741 行 · 第 1/3 页
SCALA
741 行
* @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, this failure is fatal. */ def ~! [U](p: => Parser[U]): Parser[~[T, U]] = OnceParser{ (for(a <- this; b <- commit(p)) yield new ~(a,b)).named("~!") } /** 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' that returns the result of the first parser to succeed (out of `p' and `q') * The resulting 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 | [U >: T](q: => Parser[U]): Parser[U] = append(q).named("|") // TODO /** 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 ||| [U >: T](q: => Parser[U]): Parser[U] = new Parser[U] { def apply(in: Input) = { val res1 = Parser.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 ^^ f' succeeds if `p' succeeds; it returns `f' applied to the result of `p'.</p> * * @param f a function that will be applied to this parser's result (see `map' in `ParseResult'). * @return a parser that has the same behaviour as the current parser, but whose result is * transformed by `f'. */ def ^^ [U](f: T => U): Parser[U] = map(f).named(toString+"^^") def ^^^ [U](r: U): Parser[U] = ^^ (x => r) /** A parser combinator for partial function application * *<p>`p ^? (f, error)' 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'. If `f' is not applicable, * error(the result of `p') should explain why.</p> * * @param f a partial function that will be applied to this parser's result * (see `mapPartial' in `ParseResult'). * @param error a function that takes the same argument as `f' and produces an error message * to explain why `f' wasn't applicable * @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], error: T => String): Parser[U] = Parser{ in => this(in).mapPartial(f, error)}.named(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] = ^?(f, r => "Constructor function not defined at "+r) /** 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] = flatMap(fq) // 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. * 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) } // 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]) = Parser{ in => p(in) match{ case s @ Success(_, _) => s case e @ Error(_, _) => e case f @ Failure(msg, next) => Error(msg, next) } } /*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) = acceptIf(p)(inEl => kind+" expected") /** 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] = accept(e) /** A parser that matches only the given element `e' *<p> * The method is implicit so that elements can automatically be lifted to their parsers. * For example, when parsing `Token's, Identifier("new") (which is a `Token') can be used directly, * instead of first creating a `Parser' 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 `tParser' that succeeds if `e' is the next available input. */ implicit def accept(e: Elem): Parser[Elem] = acceptIf(_ == e)("`"+e+"' expected but " + _ + " found") /** 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 Parser that recognizes a specified list of elements */ def accept[ES <% List[Elem]](es: ES): Parser[List[Elem]] = acceptSeq(es) /** The parser that matches an element in the domain of the partial function `f' *<p> * If `f' is defined on the first element in the input, `f' is applied to it to produce * this parser's result.</p> *<p> * Example: The parser <code>accept("name", {case Identifier(n) => Name(n)})</code> * accepts an <code>Identifier(n)</code> and returns a <code>Name(n)</code>.</p> * * @param expected a description of the kind of element this parser expects (for error messages) * @param f a partial function that determines when this parser is successful and what its output is * @return A parser that succeeds if `f' is applicable to the first element of the input, * applying `f' to it to produce the result. */ def accept[U](expected: String, f: PartialFunction[Elem, U]): Parser[U] = acceptMatch(expected, f) def acceptIf(p: Elem => Boolean)(err: Elem => String): Parser[Elem] = Parser { in => if (p(in.first)) Success(in.first, in.rest) else Failure(err(in.first), in) } def acceptMatch[U](expected: String, f: PartialFunction[Elem, U]): Parser[U] = Parser{ in => if (f.isDefinedAt(in.first)) Success(f(in.first), in.rest) else Failure(expected+" expected", in) } def acceptSeq[ES <% Iterable[Elem]](es: ES): Parser[List[Elem]] = es.foldRight[Parser[List[Elem]]](success(Nil)){(x, pxs) => accept(x) ~ pxs ^^ mkList} /** A parser that always fails * * @param msg The error message describing the failure. * @return A parser that always fails with the specified error message. */ def failure(msg: String) = Parser{ in => Failure(msg, in) }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?