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