scala组合分析器以保持原始输入

scala组合分析器以保持原始输入,scala,parser-combinators,Scala,Parser Combinators,我想从另一个解析器组成一个解析器,将使用的输入作为ast构造的参数 说我有 def ingredient = amount ~ nameOfIngredient ^^ { case amount ~ name => Ingredient(name, amount) } 我要寻找的是一种让另一个解析器构造以下元素的方法: case class RecipeRow(orginalText: String, ingredient: Ingredient) 因此,我正在寻找一种方法,在合成

我想从另一个解析器组成一个解析器,将使用的输入作为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)]
有没有其他简单的方法来得到我想要的东西,或者我需要写那个东西?感觉这可能是一种更好的方式…

实际上并不容易

让我们从解析器开始:它能给我们什么?嗯,
Parser
扩展了
Input=>ParseResult
,因此我们必须从其中任何一个提取信息

类型
Input
RegexParsers
上的别名,用于
scala.util.parsing.Input.Reader[Char]
。除非它恰好是
字符序列
读取器
,在这种情况下,我们可以使用
源代码
偏移量
。那我们就用这个吧

现在,
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
  }
}
其实不容易

让我们从解析器开始:它能给我们什么?嗯,
Parser
扩展了
Input=>ParseResult
,因此我们必须从其中任何一个提取信息

类型
Input
RegexParsers
上的别名,用于
scala.util.parsing.Input.Reader[Char]
。除非它恰好是
字符序列
读取器
,在这种情况下,我们可以使用
源代码
偏移量
。那我们就用这个吧

现在,
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
  }
}

这对你有用吗?不,我看不出来。这对你有用吗?不,我看不出来。