Не просто, на самом деле.
Давайте начнем с 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
}
}