如何使用 megaparsec 报告多个错误?
How to report multiple errors using megaparsec?
根据 megaparsec 文档,"Since version 8, reporting multiple parse errors at once has become much easier." I haven't been able to find a single example of doing it. The only one I find is this. However it only shows how to parse a newline delimited toy language and also does not show how to combine multiple errors into ParseErrorBundle. This 不是决定性的。
您想使用 withRecovery
与 registerParseError
(或 registerFailure
或 registerFancyFailure
)一起从 Megaparsec 生成的错误中恢复到 "register"延迟处理的错误(或您自己产生的错误)。
解析结束时,如果没有注册解析错误,则解析成功,如果注册了一个或多个解析错误,则立即打印。如果你注册了解析错误,然后又触发了一个未恢复的错误,解析会立即终止,注册的错误和最终未恢复的错误都会被打印出来。
这是一个非常简单的示例,用于解析以逗号分隔的数字列表:
import Data.Void
import Text.Megaparsec
import Text.Megaparsec.Char
type Parser = Parsec Void String
numbers :: Parser [Int]
numbers = sepBy number comma <* eof
where number = read <$> some digitChar
comma = recover $ char ','
-- recover to next comma
recover = withRecovery $ \e -> do
registerParseError e
some (anySingleBut ',')
char ','
输入良好:
> parseTest numbers "1,2,3,4,5"
[1,2,3,4,5]
输入有多个错误:
> parseTest numbers "1.2,3e5,4,5x"
1:2:
|
1 | 1.2,3e5,4,5x
| ^
unexpected '.'
expecting ','
1:6:
|
1 | 1.2,3e5,4,5x
| ^
unexpected 'e'
expecting ','
1:12:
|
1 | 1.2,3e5,4,5x
| ^
unexpected 'x'
expecting ',', digit, or end of input
这里有一些微妙之处。对于以下,仅处理第一个解析错误:
> parseTest numbers "1,2,e,4,5x"
1:5:
|
1 | 1,2,e,4,5x
| ^
unexpected 'e'
expecting digit
并且您必须仔细研究解析器才能了解原因。 sepBy
成功地以交替顺序应用 number
和 comma
解析器来解析 "1,2,"
。当它到达 e
时,它应用失败的 number
解析器(因为 some digitChar
需要至少一个数字字符)。这是一个未恢复的错误,所以解析立即结束,没有注册其他错误,所以只打印一个错误。
此外,如果您从 numbers
的定义中删除 <* eof
(例如,使其成为更大解析器的一部分),您会发现:
> parseTest numbers "1,2,3.4,5"
给出句点的解析错误,但是:
> parseTest numbers "1,2,3.4"
解析正常。另一方面:
> parseTest numbers "1,2,3.4\n hundreds of lines without commas\nfinal line, with comma"
文件末尾的句点和逗号出现解析错误。
问题是 comma
解析器被 sepBy
用来确定逗号分隔的数字列表何时结束。如果解析器成功(它可以通过恢复来完成,将数百行吞噬到下一个逗号),sepBy
将尝试保留 运行;如果解析器失败(最初失败,并且因为恢复代码在扫描整个文件后找不到逗号),sepBy
将完成。
最终,编写可恢复的解析器有点棘手。
根据 megaparsec 文档,"Since version 8, reporting multiple parse errors at once has become much easier." I haven't been able to find a single example of doing it. The only one I find is this. However it only shows how to parse a newline delimited toy language and also does not show how to combine multiple errors into ParseErrorBundle. This
您想使用 withRecovery
与 registerParseError
(或 registerFailure
或 registerFancyFailure
)一起从 Megaparsec 生成的错误中恢复到 "register"延迟处理的错误(或您自己产生的错误)。
解析结束时,如果没有注册解析错误,则解析成功,如果注册了一个或多个解析错误,则立即打印。如果你注册了解析错误,然后又触发了一个未恢复的错误,解析会立即终止,注册的错误和最终未恢复的错误都会被打印出来。
这是一个非常简单的示例,用于解析以逗号分隔的数字列表:
import Data.Void
import Text.Megaparsec
import Text.Megaparsec.Char
type Parser = Parsec Void String
numbers :: Parser [Int]
numbers = sepBy number comma <* eof
where number = read <$> some digitChar
comma = recover $ char ','
-- recover to next comma
recover = withRecovery $ \e -> do
registerParseError e
some (anySingleBut ',')
char ','
输入良好:
> parseTest numbers "1,2,3,4,5"
[1,2,3,4,5]
输入有多个错误:
> parseTest numbers "1.2,3e5,4,5x"
1:2:
|
1 | 1.2,3e5,4,5x
| ^
unexpected '.'
expecting ','
1:6:
|
1 | 1.2,3e5,4,5x
| ^
unexpected 'e'
expecting ','
1:12:
|
1 | 1.2,3e5,4,5x
| ^
unexpected 'x'
expecting ',', digit, or end of input
这里有一些微妙之处。对于以下,仅处理第一个解析错误:
> parseTest numbers "1,2,e,4,5x"
1:5:
|
1 | 1,2,e,4,5x
| ^
unexpected 'e'
expecting digit
并且您必须仔细研究解析器才能了解原因。 sepBy
成功地以交替顺序应用 number
和 comma
解析器来解析 "1,2,"
。当它到达 e
时,它应用失败的 number
解析器(因为 some digitChar
需要至少一个数字字符)。这是一个未恢复的错误,所以解析立即结束,没有注册其他错误,所以只打印一个错误。
此外,如果您从 numbers
的定义中删除 <* eof
(例如,使其成为更大解析器的一部分),您会发现:
> parseTest numbers "1,2,3.4,5"
给出句点的解析错误,但是:
> parseTest numbers "1,2,3.4"
解析正常。另一方面:
> parseTest numbers "1,2,3.4\n hundreds of lines without commas\nfinal line, with comma"
文件末尾的句点和逗号出现解析错误。
问题是 comma
解析器被 sepBy
用来确定逗号分隔的数字列表何时结束。如果解析器成功(它可以通过恢复来完成,将数百行吞噬到下一个逗号),sepBy
将尝试保留 运行;如果解析器失败(最初失败,并且因为恢复代码在扫描整个文件后找不到逗号),sepBy
将完成。
最终,编写可恢复的解析器有点棘手。