aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/scala/org/perl8/test/tap/Parser.scala
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-03-06 15:32:26 -0600
committerJesse Luehrs <doy@tozt.net>2013-03-06 15:32:26 -0600
commit7efb2caf7d8832a7d3a9d2ac55862e43267a3eb2 (patch)
tree49fcb4d31bec67bcb67c1262abc25c5e5ecb1e51 /src/main/scala/org/perl8/test/tap/Parser.scala
parent66bcf3627a38ef58dabaf90b7e597569b91ea3e8 (diff)
downloadscala-test-more-7efb2caf7d8832a7d3a9d2ac55862e43267a3eb2.tar.gz
scala-test-more-7efb2caf7d8832a7d3a9d2ac55862e43267a3eb2.zip
move the directory structure too
Diffstat (limited to 'src/main/scala/org/perl8/test/tap/Parser.scala')
-rw-r--r--src/main/scala/org/perl8/test/tap/Parser.scala232
1 files changed, 0 insertions, 232 deletions
diff --git a/src/main/scala/org/perl8/test/tap/Parser.scala b/src/main/scala/org/perl8/test/tap/Parser.scala
deleted file mode 100644
index 7bc44d3..0000000
--- a/src/main/scala/org/perl8/test/tap/Parser.scala
+++ /dev/null
@@ -1,232 +0,0 @@
-package com.iinteractive.test.tap
-
-import java.io.{ByteArrayInputStream,InputStream,OutputStream}
-import scala.annotation.tailrec
-import scala.io.Source
-import scala.util.parsing.combinator._
-import scala.util.parsing.input.{Position,Reader}
-
-import com.iinteractive.test.Plan
-import com.iinteractive.test.tap.Consumer._
-
-/** This class parses a TAP stream. It can either parse it all at once (from a
- * string), or it can be used as a streaming parser, where TAP events are
- * emitted through a given callback.
- */
-class Parser private (
- cb: TAPEvent => Unit,
- indent: String
-) {
- /** Creates a parser instance.
- * @param cb The event handler callback. It will be called after each
- * meaningful line of TAP, with a
- * [[com.iinteractive.test.tap.TAPEvent TAPEvent]] instance
- * representing the event that was just parsed.
- */
- def this (cb: TAPEvent => Unit = e => ()) =
- this(cb, "")
-
- private def this (indent: String) =
- this(e => (), indent)
-
- /** Parses TAP from an input stream. This variant will actually parse lines
- * as they are available to read from the input stream, so this can be used
- * as a streaming parser.
- */
- def parse (input: InputStream): TAPResult = {
- import parser._
-
- cb(StartEvent)
- tap(new LineReader(input)) match {
- case Success(result, _) => {
- cb(EndEvent(result))
- result
- }
- case failure: NoSuccess => throw new ParseException(failure.msg)
- }
- }
-
- /** Parses TAP contained in a string. This isn't useful for incremental
- * parsing, because the entire input string must be created before
- * parsing can begin.
- */
- def parse (input: String): TAPResult =
- parse(new ByteArrayInputStream(input.getBytes))
-
- /** Parses TAP from an output stream.
- *
- * @todo Doesn't currently work as a streaming parser, since it just
- * collects the entire output as a string and feeds it to the parser
- * for strings. This could likely be improved.
- */
- def parse (input: OutputStream): TAPResult =
- parse(input.toString)
-
- private val parser = new TAPParser(cb, indent)
-
- private class TAPParser (
- cb: TAPEvent => Unit,
- indent: String
- ) extends Parsers {
- type Elem = Line
-
- def tap: Parser[TAPResult] =
- planFirst | planLast
-
- private def planFirst: Parser[TAPResult] =
- plan ~ rep(result) ^^ { case plan ~ results =>
- new TAPResult(plan, results)
- }
-
- private def planLast: Parser[TAPResult] =
- rep(result) ~ plan ^^ { case results ~ plan =>
- new TAPResult(plan, results)
- }
-
- private def plan: Parser[Plan] =
- planLine ^^ { p =>
- cb(PlanEvent(p.plan))
- p.plan
- }
-
- private def result: Parser[TestResult] =
- simpleResult | subtestResult
-
- private def simpleResult: Parser[TestResult] =
- resultLine ^^ { r =>
- cb(ResultEvent(r.result))
- r.result
- }
-
- private def subtestResult: Parser[TestResult] =
- subtest ~ simpleResult ^^ { case subtest ~ simpleResult =>
- new TestResult(
- simpleResult.passed,
- simpleResult.number,
- simpleResult.description,
- simpleResult.directive,
- Some(subtest)
- )
- }
-
- private def subtest: Parser[TAPResult] =
- LineParser("subtest") { in =>
- // can't just return the result directly, because it's of a different
- // type (the path dependent type associated with the new Parser
- // instance we create here, rather than the path dependent type
- // associated with this)
- val subParser = new TAPParser(
- e => (),
- in.first.indent
- )
- subParser.tap(in) match {
- case subParser.Success(p, rest) => Success(p, rest)
- case subParser.Failure(m, rest) => Failure(m, rest)
- case subParser.Error(m, rest) => Error(m, rest)
- }
- }
-
- private def planLine: Parser[PlanLine] = LineParser("plan") { in =>
- val line = in.first
- if (line.indent == indent) {
- line match {
- case p: PlanLine =>
- Success(p, in.rest)
- case _ =>
- Failure("Plan line expected, but '" + line + "' found", in)
- }
- }
- else {
- Failure(
- "Plan line expected, but " +
- "'" + line + "' has incorrect indentation",
- in
- )
- }
- }
-
- private def resultLine: Parser[ResultLine] = LineParser("result") { in =>
- val line = in.first
- if (line.indent == indent) {
- line match {
- case p: ResultLine =>
- Success(p, in.rest)
- case _ =>
- Failure("Result line expected, but '" + line + "' found", in)
- }
- }
- else {
- Failure(
- "Result line expected, but " +
- "'" + line + "' has incorrect indentation",
- in
- )
- }
- }
-
- private def LineParser[T] (lineType: String)(
- body: Input => ParseResult[T]
- ): Parser[T] = Parser { in =>
- if (in.atEnd) {
- Failure(lineType + " line expected, but end of input found", in)
- }
- else {
- body(in)
- }
- }
- }
-
- private class LineReader (
- in: Iterator[Char],
- lineNum: Int
- ) extends Reader[Line] {
- def this (in: InputStream) =
- this(Source.fromInputStream(in), 1)
-
- def atEnd: Boolean =
- nextLine.isEmpty
-
- def first: Line =
- nextLine.getOrElse(throw new RuntimeException("read from empty input"))
-
- lazy val pos =
- new LinePosition(lineNum, nextLine.map(_.toString).getOrElse(""))
-
- lazy val rest: Reader[Line] =
- new LineReader(remainingStream, lineNum + 1)
-
- private def nextLine: Option[Line] =
- state._1
-
- private def remainingStream: Iterator[Char] =
- state._2
-
- private lazy val state: (Option[Line], Iterator[Char]) =
- readNextLine(in)
-
- @tailrec
- private def readNextLine (
- stream: Iterator[Char]
- ): (Option[Line], Iterator[Char]) = {
- if (stream.hasNext) {
- val (line, rest) = stream.span(_ != '\n') match {
- case (l, r) => (parseLine(l.mkString), r.drop(1))
- }
- line match {
- case _: CommentLine => readNextLine(rest)
- case other => (Some(other), rest)
- }
- }
- else {
- (None, in)
- }
- }
- }
-
- private case class LinePosition (
- line: Int,
- lineContents: String
- ) extends Position {
- def column: Int = 1
- }
-}