Пользовательские ошибки для RegexParsers

Может кто-нибудь помочь мне понять следующее поведение: parseAll (parseIf, "If bla blablaa") должен привести к ожидается . Вместо этого я всегда получаю string matching regex 'is \ b' expected, но 'b' found . Я предполагаю, что это имеет какое-то отношение к пробелам, потому что «Если bla is blablaa» (обратите внимание на пробелы в начале), это приводит к такому же поведению. Я попробовал это с помощью StandardTokenParsers, и все сработало нормально. Но STP, к сожалению, не поддерживает регулярное выражение. Последующий вопрос: как мне придется изменять RegexParsers, чтобы он использовал последовательность строк вместо последовательности символов? Это значительно облегчило бы отчетность об ошибках.

lazy val parseIf = roleGiverIf ~ giverRole

lazy val roleGiverIf =
  kwIf ~> identifier | failure("""A rule must begin with if""")
lazy val giverRole =
  kwIs ~> identifier | failure("""is expected""")

lazy val keyword =
  kwIf | kwAnd | kwThen | kwOf | kwIs | kwFrom | kwTo

lazy val identifier =
  not(keyword) ~ roleEntityLiteral
// ...

def roleEntityLiteral: Parser[String] =
  """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})\S*""".r 
def kwIf: Parser[String] = "If\\b".r
def kwIs: Parser[String] = "is\\b".r

// ...

parseAll(parseIf, "If bla blablaa") match {
  case Success(parseIf, _) => println(parseIf)
  case Failure(msg, _) => println("Failure: " + msg)
  case Error(msg, _) => println("Error: " + msg)
1

1 ответы

Эта проблема очень странная. Когда вы вызываете | , а обе стороны - сбои, выбрана сторона, где произошел сбой last , а ссылки - влево-влево.

Когда вы пытаетесь разобрать непосредственно с помощью giverRole , он дает ожидаемый результат. Если вы добавите успешное совпадение перед сбоем, он даст результат, который вы видите.

Причина довольно тонкая - я нашел ее только при помощи разметки log для всех парсеров. Чтобы понять это, вы должны понимать , как RegexParser пропускает пробелы . В частности, пробелы пропускаются на accept . Поскольку failure не вызывает accept , он не пропускает пробелы.

В то время как сбой kwIs происходит в b , как пробел, пропущенный, сбой failure происходит на пробеле после Если . Вот:

If bla blablaa
   ^ kwIs fails here
  ^ failure fails here

Поэтому сообщение об ошибке на kwIs имеет приоритет по указанному выше правилу.

Вы можете обойти эту проблему, заставив синтаксический анализатор пропустить пробелы, не прибегая к чему-либо. Важно, чтобы этот шаблон всегда соответствовал, или вы получите еще более запутанное сообщение об ошибке. Вот предложение, которое, я думаю, работает:

"\\b|$".r ~ failure("is expected")

Другим решением является использование acceptIf или acceptMatch вместо использования неявного выражения regex, и в этом случае вы можете предоставить соответствующее сообщение об ошибке.

0
добавлено
@awertos Я наконец выяснил, в чем проблема. Первое решение было более подходящим, чем я думал - я просто изменил его, чтобы ошибка появилась в нужном месте, не потребляя никаких непространственных символов.
добавлено автор Daniel C. Sobral, источник
Я написал парсер с регулярным выражением и лексической способностью и использовал acceptIf, как вы предлагаете. Но странно, что приведенный выше пример не будет работать так, как ожидалось. Спасибо за вашу помощь
добавлено автор awertos, источник
pro.jvm
pro.jvm
3 503 участник(ов)

Сообщество разработчиков Java Scala Kotlin Groovy Clojure Чат для нач-их: @javastart Наш сайт: projvm.com projvm.ru Наш канал: @proJVM Вакансии: @jvmjobs Конфы: @jvmconf

Scala User Group
Scala User Group
1 486 участник(ов)

[RU] Scala Chat. Rules, additional links, FAQ: https://telegra.ph/Russian-Speaking-Scala-User-Group-08-27

Scala Jobs
Scala Jobs
852 участник(ов)

Rules: http://telegra.ph/My-lyudi-i-ehto-znachit-chto-nam-nuzhna-organizaciya-02-07 Main Scala Channel: https://t.me/scala_jobs_feed Flood Room: https://t.me/scala_ponv