我想从另一个解析器编写一个解析器,将消耗的输入作为ast构造的参数。
说我有
def ingredient = amount ~ nameOfIngredient ^^ {
case amount ~ name => Ingredient(name, amount)
}
我正在寻找的方法是让另一个解析器构造一个元素:
case class RecipeRow(orginalText: String, ingredient: Ingredient)
所以我正在寻找一种方法来检索合成中解析器的原始消耗输入。也许是这样的:
def recipeRow = ingredient withConsumedInput ^^ {
case (amount ~ name, consumed) => RecipeRow(consumed, Ingredient(name, amount))
}
我猜这种情况下的签名是:
def withConsumedInput [U](p: => Parser[U]): Parser[(U, String)]
还有另一种简单的方法可以获得我想要的东西吗?我需要写那个东西吗?感觉它可能是一种更好的方式......
答案 0 :(得分:4)
实际上并不容易。
让我们从Parser
开始:它能给我们带来什么?好吧,Parser
扩展Input => ParseResult
,因此我们必须从任何一个中提取信息。
类型Input
是RegexParsers
的别名,scala.util.parsing.input.Reader[Char]
。除非它恰好是Reader
CharSequence
,否则我们可以使用source
和offset
来帮助我们。那就让我们使用它。
现在,ParseResult
有许多子类,但我们只对Success
感兴趣,next: Input
有一个def withConsumedInput [U](p: => Parser[U]): Parser[(U, String)] = new Parser[(U, String)] {
def apply(in: Input) = p(in) match {
case Success(result, next) =>
val parsedString = in.source.subSequence(in.offset, next.offset).toString
Success(result -> parsedString, next)
case other: NoSuccess => other
}
}
字段。使用它,我们可以试试这个:
def withConsumedInput [U](p: => Parser[U]): Parser[(U, String)] = new Parser[(U, String)] {
def apply(in: Input) = p(in) match {
case Success(result, next) =>
val parsedString = in.source.subSequence(handleWhiteSpace(in.source, in.offset), next.offset).toString
Success(result -> parsedString, next)
case other: NoSuccess => other
}
}
但它会捕获任何跳过的空格。您可以对其进行调整以自动避免:
{{1}}