Instaparse: есть ошибка, но она не сообщается

Я пытаюсь создать грамматику с Instaparse. Довольно часто я обнаруживаю, что этот код не соответствует первому утверждению, выдавая "Пустой список":

(defn parse-it []
  (let [parser (insta/parser ebnf)
        res (insta/parses parser input)
        _ (assert (seq res) (str "Empty list"))
        choices (count res)
        _ (assert (= choices 1))]
    (first res)))

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

Примером исправления проблемы является удаление завершающих пробелов из файла, который становится input в приведенном выше коде.

редактировать

Основываясь на ответе Стефана, я изменил код:

(defn parse-it []
  (let [my-parser (insta/parser ebnf)
        xs (insta/parses my-parser input)
        num-choices (count xs)
        msg (cond
              (zero? num-choices) "insta/parses might be able to be corrected"
              (> num-choices 1) (str "insta/parses shows more than one way to parse: " num-choices)
              (= 1 num-choices) "insta/parses shows one choice, so all good")
        res (cond
              ;; Just fix there being more than one rather than show them all
              ;(> num-choices 1) xs
              (= num-choices 1) (first xs)
              (zero? num-choices) (insta/parse my-parser input))
        _ (assert res (str "No result. Num of choices is: " num-choices))]
    [msg res]))

Приведенный выше код делает свое дело: всегда получайте точный ответ. Для меня это не так очевидно, что после insta/parses возвращает пустой список, insta/parse необходимо вызвать, чтобы получить информацию об ошибке. Использование документации разбора ошибок приведет к лучшему коду, чем выше. Он показывает, как информация об ошибке на самом деле присутствует в метаданных и как ее получить - ответ на этот вопрос уже есть в документации!

1 ответ

Решение

Когда вы используете parser сам на входе вместо того, чтобы пройти insta/parses, он печатает довольно точное сообщение об ошибке в REPL.

Пример:

(def ebnf
  "expr = A DOT
   A    = 'A'
   DOT  = '.'")

user> ((insta/parser ebnf) "A.")
[:expr [:A "A"] [:DOT "."]]
user> ((insta/parser ebnf) "B.")
Parse error at line 1, column 1:
B.
^
Expected:
"A"
Другие вопросы по тегам