Reputation: 557
I am trying to use JavaTokenParser to parse a number of repeat of a string that reads the size from a previous token, i.e.
list-name:5
ABCDE
second-list-name:2
AB //<--the length of the string determines by the value at the token before
so the repN would be determined by the token I after the list name
def body = (listname <~ ":") ~ (numOfRepeat <~ LF) ~ repN(?, char)
def char = """[A-Z]""".r
Is any trick I could pass the just-passed-token (numOfRepeat) as Int value to the next parser (repN)?
Thanks!
Upvotes: 2
Views: 984
Reputation: 139048
Yes!—this is exactly what monadic parsing allows you to do: to have subsequent parsing depend on earlier results. For example:
import scala.util.parsing.combinator._
object parser extends JavaTokenParsers {
override val skipWhitespace = false
val lengthAndBody: Parser[String] = for {
_ <- ident
_ <- literal(":")
n <- decimalNumber
_ <- literal("\\n")
body <- repN(n.toInt, "[A-Z]".r)
} yield body.mkString
def apply(in: String) = parseAll(lengthAndBody, in)
}
And then:
scala> parser("""listName:5\nABCDE""")
res5: parser.ParseResult[String] = [1.18] parsed: ABCDE
But:
scala> parser("""listName:5\nABCD""")
res6: parser.ParseResult[String] =
[1.17] failure: string matching regex `[A-Z]' expected but end of source found
listName:5\nABCD
^
And:
scala> parser("""listName:5\nABCDEF""")
res7: parser.ParseResult[String] =
[1.18] failure: string matching regex `\z' expected but `F' found
listName:5\nABCDEF
^
You could also use the ~>
, ^^
, etc. operators together with >>
, which is an alias for flatMap
, but I personally find the for
-comprehension a lot clearer in this case.
Upvotes: 6