Skip to content

Commit

Permalink
Success Cuts now work
Browse files Browse the repository at this point in the history
  • Loading branch information
Li Haoyi committed Apr 29, 2015
1 parent a89e152 commit f970b37
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 23 deletions.
35 changes: 18 additions & 17 deletions parsing/src/main/scala/parsing/Parsing.scala
Expand Up @@ -11,12 +11,12 @@ import acyclic.file
*/
sealed trait Res[+T]
object Res{
case class Success[T](t: T, index: Int) extends Res[T]{
case class Success[T](t: T, index: Int, cut: Boolean = false) extends Res[T]{
override def toString = {
s"Success($index)"
}
}
case class Failure(input: String, ps: List[(Int, Parser[_])], fatal: Boolean) extends Res[Nothing]{
case class Failure(input: String, ps: List[(Int, Parser[_])], cut: Boolean) extends Res[Nothing]{
override def toString = {
s"Failure\n" + ps.map(x => x._1 + "\t..." + input.slice(x._1, x._1 + 5) + ":\t" + x._2).mkString("\n")
}
Expand Down Expand Up @@ -75,9 +75,9 @@ sealed trait Parser[+T]{
def ! = Parser.Capturing(this)

protected def fail(input: String, index: Int) =
Failure(input, (index -> this) :: Nil, fatal=false)
protected def failMore(f: Failure, index: Int, newFatal: Boolean = false) =
Failure(f.input, (index -> this) :: f.ps, fatal=f.fatal || newFatal)
Failure(input, (index -> this) :: Nil, cut=false)
protected def failMore(f: Failure, index: Int, cut: Boolean = false) =
Failure(f.input, (index -> this) :: f.ps, cut=f.cut || cut)
}

object Parser{
Expand All @@ -99,7 +99,7 @@ object Parser{
case class Capturing(p: Parser[_]) extends Parser[String]{
def parse(input: String, index: Int) = {
p.parse(input, index) match {
case Success(t, i) => Success(input.substring(index, i), i)
case s: Success[_] => Success(input.substring(index, s.index), s.index, s.cut)
case f: Failure => f
}
}
Expand Down Expand Up @@ -229,8 +229,8 @@ object Parser{

def parse(input: String, index: Int) = {
p.parse(input, index) match{
case Success(t, index) => Success(ev(Some(t)), index)
case f: Failure if f.fatal => failMore(f, index)
case Success(t, index, cut) => Success(ev(Some(t)), index, cut)
case f: Failure if f.cut => failMore(f, index)
case _ => Success(ev(None), index)
}
}
Expand All @@ -244,11 +244,12 @@ object Parser{
case class Sequence[+T1, +T2, R](p1: Parser[T1], p2: Parser[T2], cut: Boolean)
(implicit ev: Implicits.Sequencer[T1, T2, R]) extends Parser[R]{
def parse(input: String, index: Int) = {

p1.parse(input, index) match{
case f: Failure => failMore(f, index, newFatal = cut)
case f: Failure => failMore(f, index, cut = cut | f.cut)
case s1: Success[_] => p2.parse(input, s1.index) match{
case f: Failure => failMore(f, index, newFatal = cut)
case s2: Success[_] => Success(ev(s1.t, s2.t), s2.index)
case f: Failure => failMore(f, index, cut = cut || f.cut || s1.cut)
case s2: Success[_] => Success(ev(s1.t, s2.t), s2.index, s2.cut || s1.cut | cut)
}
}
}
Expand All @@ -271,21 +272,21 @@ object Parser{
var lastFailure: Failure = null
@tailrec def rec(index: Int, del: Parser[_]): Unit = {
del.parse(input, index) match{
case f: Failure if f.fatal => lastFailure = failMore(f, index)
case f: Failure if f.cut => lastFailure = failMore(f, index)
case f: Failure => lastFailure = f
case Success(t, i) =>
case Success(t, i, cut1) =>
p.parse(input, i) match{
case f: Failure if f.fatal => lastFailure = failMore(f, index)
case f: Failure if f.cut | cut1 => lastFailure = failMore(f, index, f.cut | cut1)
case f: Failure => lastFailure = f
case Success(t, i) =>
case Success(t, i, cut2) =>
res.append(t)
finalIndex = i
rec(i, delimiter)
}
}
}
rec(index, Pass)
if (lastFailure != null && lastFailure.fatal) {
if (lastFailure != null && lastFailure.cut) {
failMore(lastFailure, index)
}
else if (res.length >= min) Success(ev(res.iterator), finalIndex)
Expand All @@ -304,7 +305,7 @@ object Parser{
def parse(input: String, index: Int) = {
p1.parse(input, index) match{
case s: Success[_] => s
case f: Failure if f.fatal => failMore(f, index)
case f: Failure if f.cut => failMore(f, index)
case _ => p2.parse(input, index) match{
case s: Success[_] => s
case f: Failure => fail(input, index)
Expand Down
7 changes: 1 addition & 6 deletions parsing/src/test/scala/parsing/JsonTests.scala
Expand Up @@ -21,15 +21,10 @@ object JsonTests extends TestSuite{
val obj = R( "{" ~ pair ~ ("," ~ pair).rep ~ space.? ~ "}" )
val jsonExpr: Parser[_] = R(space.? ~ (obj | array | string | `true` | `false` | `null` | number) ~ space.?)

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{
'literal {
def test(p: Parser[_], s: String) = p.parse(s, 0) match{
case Res.Success(v, i) =>
case Res.Success(v, i, cut) =>
val expectedIndex = s.length
assert(i == {s; expectedIndex})
case f: Res.Failure => throw new Exception(f.ps.mkString("\n"))
Expand Down
1 change: 1 addition & 0 deletions parsing/src/test/scala/parsing/ParsingTests.scala
Expand Up @@ -58,6 +58,7 @@ object ParsingTests extends TestSuite{
checkFail("Hello" ~ ("wtf" ~ "omg" | "bbq"), ("Hellowtfom", 0), 5)
checkFail("Hello" ~ ("wtf" ~! "omg" | "wtfom"), ("Hellowtfom", 0), 8)
checkFail("Hello" ~ ("wtf" ~ "omg" ~! "bbq" | "wtfom"), ("Hellowtfomgbbe", 0), 11)
checkFail("Hello" ~ ("wtf" ~! "omg" ~ "bbq" | "wtfom"), ("Hellowtfomgbbe", 0), 11)
}
'rep {
check(("Hello" ~ "Bye").rep, ("HelloByeHello", 0), Success((), 8))
Expand Down

0 comments on commit f970b37

Please sign in to comment.