/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2006-2009, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ // $Id: Scanners.scala 18387 2009-07-24 15:28:37Z odersky $ package scala.util.parsing.combinator.lexical import scala.util.parsing.combinator._ import scala.util.parsing.syntax._ import scala.util.parsing.input._ /** <p> * This component provides core functionality for lexical parsers. * </p> * <p> * See its subclasses {@see Lexical} and -- most interestingly * {@see StdLexical}, for more functionality. * </p> * * @requires token a parser that produces a token (from a stream of characters) * @requires whitespace a unit-parser for white-space * @provides Scanner essentially a parser that parses a stream of characters * to produce `Token's, which are typically passed to a * syntactical parser (which operates on `Token's, not on * individual characters). * * @author Martin Odersky, Adriaan Moors */ trait Scanners extends Parsers { type Elem = Char type Token /** This token is produced by a scanner {@see Scanner} when scanning failed. */ def errorToken(msg: String): Token /** a parser that produces a token (from a stream of characters) */ def token: Parser[Token] /** a parser for white-space -- its result will be discarded */ def whitespace: Parser[Any] /** <p> * <code>Scanner</code> is essentially(*) a parser that produces `Token's * from a stream of characters. The tokens it produces are typically * passed to parsers in <code>TokenParsers</code>. * </p> * <p> * Note: (*) <code>Scanner</code> is really a `Reader' of `Token's * </p> */ class Scanner(in: Reader[Char]) extends Reader[Token] { /** Convenience constructor (makes a character reader out of the given string) */ def this(in: String) = this(new CharArrayReader(in.toCharArray())) private val (tok, rest1, rest2) = whitespace(in) match { case Success(_, in1) => token(in1) match { case Success(tok, in2) => (tok, in1, in2) case ns: NoSuccess => (errorToken(ns.msg), ns.next, skip(ns.next)) } case ns: NoSuccess => (errorToken(ns.msg), ns.next, skip(ns.next)) } private def skip(in: Reader[Char]) = if (in.atEnd) in else in.rest override def source: java.lang.CharSequence = in.source override def offset: Int = in.offset def first = tok def rest = new Scanner(rest2) def pos = rest1.pos def atEnd = in.atEnd || (whitespace(in) match { case Success(_, in1) => in1.atEnd case _ => false }) } }