Skip to content

Instantly share code, notes, and snippets.

@travisbrown
Created September 19, 2012 02:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save travisbrown/3747234 to your computer and use it in GitHub Desktop.
Save travisbrown/3747234 to your computer and use it in GitHub Desktop.
Threading extra state through a parser in Scala
import scala.util.parsing.combinator._
import scalaz._, Scalaz._
trait ExtraStateParsers[S] { this: Parsers =>
type ESP[A] = StateT[Parser, S, A]
protected implicit def monadInstance: Monad[Parser]
protected implicit def monadStateInstance =
implicitly[MonadState[({type F[T, +B] = StateT[Parser, T, B]})#F, S]]
def lift[A](p: Parser[A]) = StateT.StateMonadTrans[S].liftM(p)
def get: ESP[S] = monadStateInstance gets identity
def put(s: S): ESP[Unit] = monadStateInstance put s
def build[A](f: (S, Input) => ParseResult[(S, A)]): ESP[A] =
StateT(s => new Parser[(S, A)] { def apply(in: Input) = f(s, in) })
def rep1[A](p: => ESP[A]): ESP[List[A]] = rep1(p, p)
def rep1[A](first: => ESP[A], p0: => ESP[A]) = build { (s, in) =>
lazy val p = p0
val elems = new scala.collection.mutable.ListBuffer[A]
def continue(in: Input, t: S): ParseResult[(S, List[A])] = {
val p0 = p
@scala.annotation.tailrec
def applyp(in0: Input, u: S): ParseResult[(S, List[A])] =
p0.run(u)(in0) match {
case Success((v, x), rest) => elems += x; applyp(rest, v)
case _ => Success((u, elems.toList), in0)
}
applyp(in, t)
}
first.run(s)(in) match {
case Success((t, x), rest) => elems += x; continue(rest, t)
case ns: NoSuccess => ns
}
}
class ESPWrapper[A](p: ESP[A]) {
def append[B >: A](q0: => ESP[B]): ESP[B] = {
lazy val q = q0
build { (s, in) => p.run(s)(in) append q.run(s)(in) }
}
def ~> [B](q0: => ESP[B]): ESP[B] = build { (s, in) =>
lazy val q = q0
p.run(s)(in).flatMapWithNext { case (t, _) => q.run(t) }
}
def <~ [B](q0: => ESP[B]): ESP[A] = build { (s, in) =>
lazy val q = q0
p.run(s)(in) match {
case Success((t, r), rest) => q.run(t)(rest).map {
case (u, _) => (u, r)
}
case e => e
}
}
def | [B >: A](q: => ESP[B]): ESP[B] = append(q)
}
implicit def toESPWrapper[A](p: ESP[A]) = new ESPWrapper(p)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment