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"