如何将MegaParsec的ParseErrorBundle转换为SourcePos与错误信息列表
解决方案
你可以直接复用Megaparsec内置的reachOffset接口实现需求,不需要复刻整个errorBundlePretty的逻辑,最简实现代码如下:
import qualified Data.Text as T import Text.Megaparsec import Text.Megaparsec.Error getParseErrors :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => ParseErrorBundle s e -> [(SourcePos, T.Text)] getParseErrors bundle = map wrapError $ bundleErrors bundle where basePosState = bundlePosState bundle wrapError err = (errPos, T.pack $ parseErrorTextPretty err) where -- 直接调用官方接口通过错误偏移计算对应SourcePos (errPos, _, _) = reachOffset (errorOffset err) basePosState
这个实现完全复用官方的位置计算逻辑,返回的行号、列号和errorBundlePretty的输出完全一致,代码量非常少,适合绝大多数场景。
如果你的解析结果经常出现大量错误,可以优化为单遍遍历推进位置状态的版本,避免重复计算偏移:
import Data.List (sortOn) import qualified Data.Text as T import Text.Megaparsec import Text.Megaparsec.Error getParseErrorsOptimized :: (VisualStream s, TraversableStream s, ShowErrorComponent e) => ParseErrorBundle s e -> [(SourcePos, T.Text)] getParseErrorsOptimized bundle = snd $ foldl process (basePosState, []) sortedErrs where -- 先按错误偏移从小到大排序,方便顺序推进位置状态 sortedErrs = sortOn errorOffset $ bundleErrors bundle basePosState = bundlePosState bundle process (currState, res) err = (newState, res ++ [(errPos, errText)]) where (errPos, newState, _) = reachOffset (errorOffset err) currState errText = T.pack $ parseErrorTextPretty err
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

