type Parser[T] = StateT[Option, String, T]
def pure[T](x: T): Parser[T] =
StateT.pure[Option, String, T](x)
def failure: Parser[String] =
StateT[Option, String, String](_ => None)
def item: Parser[String] =
StateT{
case "" => None
case xs => Some(xs.tail, xs.head.toString)
}
implicit class ParserOps[T](p: Parser[T]) {
def +++(q: Parser[T]): Parser[T] =
StateT[Option, String, T] { inp =>
p.run(inp) orElse q.run(inp)
}
}
println((item +++ pure("d")).run("abc"))
println((failure +++ pure("d")).run("abc"))
println((failure +++ failure).run("abc"))
def item2 = for {
s1 <- item
_ <- item
s2 <- item
} yield s1 + s2
println(item2.run("abcd"))
def sat(p: String => Boolean): Parser[String] =
for {
x <- item
r <- if (p(x)) pure(x) else failure
} yield r
def digit = sat(_.matches("^\\d$"))
def lower = sat(_.matches("^[a-z]$"))
def upper = sat(_.matches("^[A-Z]$"))
def letter = sat(_.matches("^[a-zA-Z]$"))
def alphanum = sat(_.matches("^[0-9a-zA-Z]$"))
def char(x: String) = sat(_ == x)
println(sat(x => x.matches("^1$")).run("22"))
def string(str: String): Parser[String] = str match {
case "" => pure("")
case _ => for {
x <- char(str.head.toString)
xs <- string(str.tail.mkString)
} yield x + xs
}
println(string("abc").run("abcdef"))
def many[T](p: Parser[T]): Parser[List[T]] = many1(p) +++ pure(Nil)
def many1[T](p: Parser[T]): Parser[List[T]] =
for {
v <- p
vs <- many(p)
} yield v :: vs
println(many(digit).run("123abc"))
println(many(digit).run("abcdef"))
def ident: Parser[String] =
for {
x <- lower
xs <- many(alphanum)
} yield x + xs.mkString
def nat: Parser[Int] =
many1(digit).map(_.mkString.toInt)
def space: Parser[String] =
for {
_ <- many(sat(_ == " "))
r <- pure("")
} yield r
println(nat.run("123abc"))
println(space.run(" abc"))