Permalink
Browse files

Either works

  • Loading branch information...
Li Haoyi
Li Haoyi committed Apr 26, 2015
1 parent b50b6c2 commit c1278df16d4318f67a1ea5537c3ba1752a1d7fa3
Showing with 65 additions and 14 deletions.
  1. +40 −7 parsing/src/main/scala/parsing/Parsing.scala
  2. +25 −7 parsing/src/test/scala/parsing/ParsingTests.scala
@@ -1,23 +1,56 @@
package parsing
import parsing.Parsing.Res.Success
import scala.annotation.tailrec
import scala.collection.mutable
object Parsing {
sealed trait Res[+T]
object Res{
case class Success[T](t: T, index: Int) extends Res[T]
case class Failure(index: Int) extends Res[Nothing]
}
import Res._
sealed trait Parser[T]{
def parse(s: String, index: Int): Res[T]
def parse(input: String, index: Int): Res[T]
def rep = Parser.Repeat(this, 0)
def rep1 = Parser.Repeat(this, 1)
def |[T1 >: T, V <: T1](p: Parser[V]) = Parser.Either(this, p)
}
object Parser{
// case class Repeat[T](p: Parser[T]) extends Parser[Vector[T]]{
// def parse
// }
// case class Either[T, V1 <: T, V2 <: T](p1: Parser[V1], p2: Parser[V2]) extends Parser[T]
case class Repeat[T](p: Parser[T], min: Int) extends Parser[Seq[T]]{
def parse(input: String, index: Int) = {
val res = mutable.Buffer.empty[T]
var finalIndex = index
@tailrec def rec(index: Int): Unit = {
p.parse(input, index) match{
case Failure(_) =>
case Success(t, i) =>
res.append(t)
finalIndex = i
rec(i)
}
}
rec(index)
if (res.length >= min) Success(res, finalIndex)
else Failure(index)
}
}
case class Either[T, V1 <: T, V2 <: T](p1: Parser[V1], p2: Parser[V2]) extends Parser[T]{
def parse(input: String, index: Int) = {
p1.parse(input, index) match{
case s: Success[_] => s
case f: Failure => p2.parse(input, index) match{
case s: Success[_] => s
case f: Failure => Failure(index)
}
}
}
}
case class Literal(s: String) extends Parser[String]{
def parse(input: String, index: Int) = {
println("LITERAL |" + s + "|" + input + "|" + index + "|" + input.startsWith(s, index))
if (input.startsWith(s, index)) Res.Success(s, index + s.length)
else Res.Failure(index)
}
@@ -4,14 +4,32 @@ import parsing.Parsing._
import parsing.Parsing.Parser._
import parsing.Parsing.Res._
object ParsingTests extends TestSuite{
def check[T](parser: Parser[T], input: (String, Int), rhs: Res[T]) = {
val (str, index) = input
val parsed = parser.parse(str, index)
assert({parser; str; parsed} == rhs)
}
val tests = TestSuite{
'hello{
assert(
Literal("Hello WOrld!").parse("Hello", 0) == Failure(0),
Literal("Hello").parse("Hello WOrld!", 0) == Success("Hello", 5),
Literal("Hello").parse("Hello WOrld!", 5) == Failure(5),
Literal(" WO").parse("Hello WOrld!", 5) == Success(" WO", 8)
)
'literal{
check("Hello WOrld!", ("Hello", 0), Failure(0))
check("Hello", ("Hello WOrld!", 0), Success("Hello", 5))
check("Hello", ("Hello WOrld!", 5), Failure(5))
check(" WO", ("Hello WOrld!", 5), Success(" WO", 8))
}
'repeat{
check("Hello".rep, ("HelloHello!", 0), Success(Seq("Hello", "Hello"), 10))
check("Hello".rep, ("HelloHello!", 2), Success(Seq(), 2))
check("Hello".rep, ("HelloHello!", 5), Success(Seq("Hello"), 10))
check("Hello".rep1, ("HelloHello!", 0), Success(Seq("Hello", "Hello"), 10))
check("Hello".rep1, ("HelloHello!", 2), Failure(2))
}
'either{
check("Hello" | "Bye", ("HelloBye", 0), Success("Hello", 5))
check("Hello" | "Bye", ("HelloBye", 5), Success("Bye", 8))
check("Hello" | "Bye", ("HelloBye", 2), Failure(2))
check(("Hello" | "Bye").rep, ("HelloBye", 0), Success(Seq("Hello", "Bye"), 8))
}
}
}

0 comments on commit c1278df

Please sign in to comment.