public
Created

Threading extra state through a parser in Scala

  • Download Gist
ExtraStateParsers.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
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)
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.