2

別のパーサーからパーサーを作成して、消費された入力を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)]

私が欲しいものを手に入れる別の簡単な方法はありますか、それとも私はそのことを書く必要がありますか?おそらくもっと良い方法だと思います…</p>

4

1 に答える 1

4

実際、簡単ではありません。

始めましょうParser:それは私たちに何を与えることができますか?まあ、 a ParserextendsInput => ParseResultなので、どちらかから情報を抽出する必要があります。

InputRegexParsersとにかく、のエイリアスですscala.util.parsing.input.Reader[Char]。それがたまたまReaderofCharSequenceでない限り、私たちを助けるものはほとんどsourceありませんoffset。それでは使ってみましょう。

には多くのサブクラスがありますが、フィールドを持つParseResultのみに関心があります。それを使用して、これを試すことができます:Successnext: 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
  }
}
于 2012-01-26T18:52:56.670 に答える