Пользовательские ошибки для RegexParsers - PullRequest
1 голос
/ 12 ноября 2011

Может кто-нибудь помочь мне понять следующее поведение: parseAll (parseIf, "If bla blablaa") должно привести к is expected.Вместо этого я всегда получаю string matching regex 'is\b' expected but 'b' found.Я думаю, это как-то связано с пробелами, потому что " If 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 Ответ

0 голосов
/ 13 ноября 2011

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

Когда вы пытаетесь выполнить синтаксический анализ непосредственно с giverRole, это дает ожидаемый результат.Однако если вы добавите успешное совпадение до сбоя, оно даст результат, который вы видите.

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

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

If bla blablaa
   ^ kwIs fails here
  ^ failure fails here

Следовательно, сообщение об ошибке на kwIs имеет приоритет по правилу, которое я упомянул.

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

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

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

...