Skip to content
Browse files

make backtracking explicit, OrElse parser fails if lhs consumes any i…

…nput.
  • Loading branch information...
1 parent c206f96 commit 0f9924a174dbb9314e99b342ac976c6130f1820b @freels committed Jul 14, 2011
View
2 src/main/scala/com/twitter/finagle/memcached/Protocol.scala
@@ -102,7 +102,7 @@ object ResponseDecoder {
val readNumber = readLine map { bytes => Number(decodeDecimalInt(bytes)) }
- val parser: Parser[Response] = readResponse orElse readNumber
+ val parser: Parser[Response] = readResponse or readNumber
}
View
2 src/main/scala/com/twitter/finagle/parser/incremental/MatchingParser.scala
@@ -54,7 +54,7 @@ object SwitchParser {
}
}
-class SwitchParser[+Out](choices: Array[(Matcher, Parser[Out])]) extends UnsafeParser[Out] {
+class SwitchParser[+Out](choices: Array[(Matcher, Parser[Out])]) extends Parser[Out] {
val maxMatcherLength = (choices map { _._1.bytesNeeded }) ++ Array(0) max
View
49 src/main/scala/com/twitter/finagle/parser/incremental/Parser.scala
@@ -15,33 +15,29 @@ case class Throw(err: ParseException) extends ParseResult[Nothing]
abstract class Parser[+Out] {
def decode(buffer: ChannelBuffer): ParseResult[Out]
- def map[T](f: Out => T): Parser[T] = flatMap { out =>
+ def map[T](f: Out => T): Parser[T] = this into { out =>
try {
new ConstParser(f(out))
} catch {
case e: ParseException => new FailParser(e)
}
}
- def flatMap[T](f: Out => Parser[T]): Parser[T] = {
+ def into[T](f: Out => Parser[T]): Parser[T] = {
new FlatMapParser(this, f)
}
- def flatMap[T](next: Parser[T]): Parser[T] = {
+ def then[T](next: Parser[T]): Parser[T] = {
new ChainedParser(this, next)
}
- def orElse[T >: Out](other: Parser[T]): Parser[T] = {
- if (isSafe) {
- new OrElseParser(this, other)
- } else {
- new BacktrackingParser(this) orElse other
- }
- }
+ def flatMap[T](f: Out => Parser[T]) = this into f
+
+ def flatMap[T](next: Parser[T]) = this then next
- // if true, then it is safe to assume that either parsing cannot
- // normally fail, or if it does, then it does not consume any bytes
- def isSafe = true
+ def or[T >: Out](other: Parser[T]): Parser[T] = {
+ new OrElseParser(this, other)
+ }
}
class FailParser(err: ParseException) extends Parser[Nothing] {
@@ -52,11 +48,7 @@ class ConstParser[+Out](out: Out) extends Parser[Out] {
def decode(buffer: ChannelBuffer) = Return(out)
}
-abstract class UnsafeParser[+Out] extends Parser[Out] {
- override def isSafe = false
-}
-
-abstract class AbstractChainedParser[A,+B] extends UnsafeParser[B] {
+abstract class AbstractChainedParser[A,+B] extends Parser[B] {
protected def left: Parser[A]
protected def right(ret: A): Parser[B]
protected def continued(next: Parser[A]): Parser[B]
@@ -76,6 +68,11 @@ class ChainedParser[A,+B](protected val left: Parser[A], rhs: Parser[B])
extends AbstractChainedParser[A,B] {
protected def right(ret: A) = rhs
protected def continued(next: Parser[A]) = new ChainedParser(next, rhs)
+
+ // override to be right-associative
+ override def then[T](other: Parser[T]) = {
+ new ChainedParser(left, rhs then other)
+ }
}
class FlatMapParser[A,+B](protected val left: Parser[A], f: A => Parser[B])
@@ -84,26 +81,24 @@ extends AbstractChainedParser[A,B] {
protected def continued(next: Parser[A]) = new FlatMapParser(next, f)
}
-// parsec's alternative op only attempts its rhs if the left side
-// hasn't consumed any input. Allowing explicit backtracking only.
class OrElseParser[+Out](lhs: Parser[Out], rhs: Parser[Out]) extends Parser[Out] {
def decode(buffer: ChannelBuffer) = {
+ val start = buffer.readerIndex
+
lhs.decode(buffer) match {
- case e: Throw => rhs.decode(buffer)
- case r: Return[Out] => r
+ case e: Throw => if (start == buffer.readerIndex) rhs.decode(buffer) else e
+ case r: Return[Out] => r
case c: Continue[Out] => if (c.next eq lhs) {
Continue(this)
} else {
- Continue(c.next orElse rhs)
+ Continue(c.next or rhs)
}
}
}
- override def isSafe = rhs.isSafe
-
// override to be right-associative
- override def orElse[T >: Out](other: Parser[T]) = {
- new OrElseParser(lhs, rhs orElse other)
+ override def or[T >: Out](other: Parser[T]) = {
+ new OrElseParser(lhs, rhs or other)
}
}
View
2 src/main/scala/com/twitter/finagle/parser/incremental/Parsers.scala
@@ -39,7 +39,7 @@ object Parsers {
val end = guard(choices: _*) { const[List[T]](Nil) }
def go(): Parser[List[T]] = {
- end orElse (for (t <- parser; ts <- go) yield { t :: ts })
+ end or (for (t <- parser; ts <- go) yield { t :: ts })
}
go()
View
2 src/test/scala/com/twitter/finagle/parser/IncrementalParserSpec.scala
@@ -54,7 +54,7 @@ object ParserSpec extends ParserSpecification {
parser mustParse "xxy" andThrow() readingBytes(2)
backtracking mustParse "xxy" andThrow() readingBytes(0)
- parser orElse const("foo") mustParse "xxy" andReturn("foo") readingBytes(0)
+ backtracking or const("foo") mustParse "xxy" andReturn("foo") readingBytes(0)
}
"Parsers" in {

0 comments on commit 0f9924a

Please sign in to comment.
Something went wrong with that request. Please try again.