我有一个我正在解析的语法,它包含正好两个必需且唯一的逻辑部分Alpha
和Beta
。这些部分可以按Alpha
或签证之前的任何顺序Beta
定义。我想为精通技术的用户提供强大的错误消息。
在下面的示例中,存在多个解析失败的情况。我将失败消息String
与unlines
函数连接起来,并将结果串联传递给fail
组合子。在grammarDefinition
上调用ParseError
时,这会创建一个Message
值,其中包含单 parse
值。
示例场景:
import Data.Either (partitionEithers)
import Data.Set (Set)
import Text.Parsec (Parsec)
import Text.Parsec.Char
import Text.ParserCombinators.Parsec
data Result = Result Alpha Beta
type Alpha = Set (Int,Float)
type Beta = Set String
grammarDefinition :: Parsec String u Result
grammarDefinition = do
segments <- partitionEithers <$> many segment
_ <- eof
case segments of
( [], []) -> fail $ unlines [missingAlpha, missingBeta]
( _, []) -> fail $ missingBeta
( [], _) -> fail $ missingAlpha
((_:_:_), (_:_:_)) -> fail $ unlines [multipleAlpha, multipleBeta]
( _, (_:_:_)) -> fail $ multipleBeta
((_:_:_), _) -> fail $ multipleAlpha
( [x], [y]) -> pure $ Result x y
where
missingAlpha = message "No" "alpha"
missingBeta = message "No" "beta"
multipleAlpha = message "Multiple" "alpha"
multipleBeta = message "Multiple" "beta"
message x y = concat [x," ",y," defined in input, ","exactly one ",y," definition required"]
-- Type signature is important!
segment :: Parsec String u (Either Alpha Beta)
segment = undefined -- implementation irrelevant
我希望ParseError
在多次失败的情况下包含多个 Message
值。由于存在addErrorMessage
函数,这应该是可能的。在通过调用parse
实现结果之前,我不确定在Parsec monadic上下文中是否会提供多个失败。
示例功能:
fails :: [String] -> ParsecT s u m a
fails = undefined -- Not sure how to define this!
如何向 {{3>提供多个 Message
值在 Parsec的monadic上下文中结果
答案 0 :(得分:2)
Text.Parsec.Prim
相当于parserFail :: String -> ParsecT s u m a
parserFail msg
= ParsecT $ \s _ _ _ eerr ->
eerr $ newErrorMessage (Message msg) (statePos s)
中定义的parserFail
:
newErrorMessage
由于addErrorMessage
和ParseError
都创建了parserFail
,
parserFail' :: String -> ParsecT s u m a
parserFail' msg
= ParsecT $ \s _ _ _ eerr ->
eerr $ theMessages s
where
theMessages s =
addErrorMessage (Message "blah") $
addErrorMessage (Expect "expected this") $
newErrorMessage (Message msg) (statePos s)
的这种变体也应该有效:
label
应该将3条消息推送到错误消息列表中。
同样在该模块中,请查看labels
和addErrorMessage
唯一使用labels
的地方。 <?>
只是一条多消息
foldr
运算符的版本。请注意它如何使用labels :: ParsecT s u m a -> [String] -> ParsecT s u m a
labels p msgs =
ParsecT $ \s cok cerr eok eerr ->
let eok' x s' error = eok x s' $ if errorIsUnknown error
then error
else setExpectErrors error msgs
eerr' err = eerr $ setExpectErrors err msgs
in unParser p s cok cerr eok' eerr'
where
setExpectErrors err [] = setErrorMessage (Expect "") err
setExpectErrors err [msg] = setErrorMessage (Expect msg) err
setExpectErrors err (msg:msgs)
= foldr (\msg' err' -> addErrorMessage (Expect msg') err')
(setErrorMessage (Expect msg) err) msgs
来构建化合物
错误讯息:
ParsecT
唯一的问题是你需要访问Text.Parsec.Prim
构造函数
labels
未导出。也许你可以找到一种方法来使用parsec
或者另一种解决方法。否则你可以随时包括你的
使用您的代码拥有{{1}}的黑客版本。
答案 1 :(得分:0)