我的 parsec 解析器可以写入弃用消息吗?

Can my parsec parser write deprecation messages?

我有一个 DSL 和一个用 Haskell 用 Parsec 包编写的解析器。现在我想弃用 DSL 的特定语言功能。在下一个版本中,我希望解析器接受新旧语法,但我希望解析器产生一条弃用消息。我找不到如何做到这一点。这可能吗?如果可能,如何实现?

与其在解析期间发出消息,不如在解析结束时 return 提供额外信息:是否遇到过时的语法。

ParsecT 类型允许用户在解析期间设置的状态类型参数:

ParsecT s u m a is a parser with stream type s, user state type u, underlying monad m and return type a. Parsec is strict in the user state.

用户状态可以用putState and modifyState. It can be obtained using getState设置。

大多数秒差距组合器在用户状态下都是多态的。您自己的 DSL 的大多数组合器也应该是。但是语法中不推荐使用的部分的解析器应该在您的用户状态中设置一个“标志”。

像这样:

import Text.Parsec
import Text.Parsec.Char
import Data.Functor.Identity

type Parser = ParsecT [Char] Bool Identity -- using a Bool state

myParser :: Parser Char
myParser = 
    try (do char 'a' 
            putState True 
            char 'b')
    <|> 
    try (do char 'a' 
            char 'c')

main :: IO ()
main = do
    print $ runParser ((,) <$> myParser <*> getState)  False "" "ab"
    print $ runParser ((,) <$> myParser <*> getState)  False "" "ac"
-- results:
-- Right ('b',True)
-- Right ('c',False)

当然,与其简单的boolean flag,不如把更多的信息放入state中。

请注意,如果 sub-parser 回溯,sub-parser 设置的状态将被“遗忘”。对于我们的目的来说,这是正确的行为:否则,我们会得到由最终被丢弃的分支触发的“误报”。


parsec is megaparsec. The latter doesn't allow for user-defined state in the parser type itself, but it can be emulated using a StateT transformer over the ParsecT 类型的常见替代。