首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将MegaParsec "ParseErrorBundle“转换为"SourcePos”和错误消息的列表

如何将MegaParsec "ParseErrorBundle“转换为"SourcePos”和错误消息的列表
EN

Stack Overflow用户
提问于 2021-11-27 16:11:14
回答 2查看 90关注 0票数 2

使用MegaParsec parse function,我能够运行一个解析器,并获得一个ParseErrorBundle if it fails

我知道我能够很好地打印ParseErrorBundle,并获得整个解析失败的错误消息,这将包括行号和字符号,使用errorBundlePretty

我还知道,我可以使用list of ParseError'sParseErrorBundle获得bundleErrors。我可以用parseErrorPrettyparseErrorTextPretty打印这些东西。

我希望能够运行一个解析器,如果它失败了,获取一个(SourcePos, Text)列表,这样我就可以知道各个错误消息以及每个错误的位置。我想不出一种优雅的方法。虽然理论上我可以从source code to errorBundlePretty中获取相当多的数据,但我觉得自己想要对错误进行折叠,使用reachOffset来推进PosState并不是最简单的方法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-27 22:05:49

注意,如果您使用的是megaparsec >= 7.0.0,我认为您应该使用attachSourcePos进行遍历。它返回NonEmpty of (ParseError, SourcePos)对。我想它看起来会是:

代码语言:javascript
复制
import qualified Text.Megaparsec as MP
import qualified Data.Text as T
import Data.List.NonEmpty (NonEmpty (..))
import Data.Void

annotateErrorBundle :: MP.ParseErrorBundle T.Text Void -> NonEmpty (MP.SourcePos, T.Text)
annotateErrorBundle bundle
  = fmap (\(err, pos) -> (pos, T.pack . MP.parseErrorTextPretty $ err)) . fst $
    MP.attachSourcePos MP.errorOffset
                       (MP.bundleErrors bundle)
                       (MP.bundlePosState bundle)

请注意,与您建议的答案不同,attachSourcePos通过错误包的遍历正确地线程PosState,而不是在每次reachOffset调用之后抛出更新的状态。因此,我相信它将更有效地处理大量错误。(它还使用reachOffsetNoLine而不是reachOffset,这对于某些流类型可能更有效。

如果您使用的是megaparsec < 7.0.0,您可能需要尝试从更晚的版本中调整attachSourcePos的源代码。

票数 1
EN

Stack Overflow用户

发布于 2021-11-27 16:29:11

我做到了以下几点:

代码语言:javascript
复制
import qualified Text.Megaparsec as MP
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Text as T

annotateErrorBundle :: MP.ParseErrorBundle Text Void -> NonEmpty (MP.SourcePos, Text)
annotateErrorBundle bundle = (\e -> (errorSrcPos e, T.pack $ MP.parseErrorTextPretty e)) <$> MP.bundleErrors bundle
  where 
    initialPosState = MP.bundlePosState bundle
    errors = MP.bundleErrors bundle
    errorSrcPos e = MP.pstateSourcePos . snd $ MP.reachOffset (MP.errorOffset e) initialPosState 

我怀疑这可能不是超级高效,因为我每次错误都要调用reachOffset一次。然而,在实践中,错误列表可能没有那么大,所以我不太担心。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70136516

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档