我正在尝试使用Lightyear为Idris构建格式化程序。 到目前为止,整个计划都在这里:
https://github.com/hejfelix/IdrisFMT/blob/501a4a9e8b1b4154ed0d7836676c24d98de8b76a/IdrisFmt.idr
目前,目的是将文件本身标记化,然后将其打印出来,即输入的文件应该是一个固定点。
问题出现在每个字符串文字之后,我的解析器似乎吃掉了空格。如果我在字符串文字之后立即放入除空格之外的任何内容,它将解析该字符以及以下所有空格。
此示例程序将显示错误:
main2 : IO ()
main2 = putStrLn $ str
where
str = case parse tokenParser "\"IdrisFMT.idr\" \n" of
(Left l) => "failed" ++ show l
(Right r) => show $ map (show @{default}) r
打印出来:
*IdrisFMT> :exec main2
["StringLiteral(\"IdrisFMT.idr\")"]
如果我将我正在解析的字符串更改为"\"IdrisFMT.idr\"c \n"
,我会得到:
*IdrisFMT> :exec main2
["StringLiteral(\"IdrisFMT.idr\")", "Identifier(c)", "' '", "'\\n'"]
这就是我的预期。
我认为错误源于我解析字符串文字的方式,但我无法理解我的错误,而且我无法找到调试光年解析器的好方法。 我的字符串文字解析器的实现如下:
escape : Parser String
escape = do
d <- char '\\'
c <- oneOf "\\\"0nrvtbf"
pure $ pack $ (the $ List Char) [d,c]
nonEscape : Parser String
nonEscape = map (\x => pack $ (the $ List _) [x]) $ noneOf "\\\"\0\n\r\v\t\b\f"
character : Parser String
character = nonEscape <|>| escape
stringLiteralToken : Parser Token
stringLiteralToken = map (StringLiteral . concat) $ dquote (many character)
如何防止我的字符串文字解析器在文字后面占用空格?
答案 0 :(得分:1)
在#idris频道聊天之后,我得到了帮助,我了解到大多数内置的高阶解析器(例如dquote
)最后会跳过空白。
就我而言,这不是我想要的。相反,我使用between
函数,它接受3个参数,一个解析器用于何时开始,另一个用于何时停止,以及第三个用于介于两者之间的任何参数。
要解析字符串文字,我现在这样做:
escape : Parser String
escape = do
d <- char '\\'
c <- oneOf "\\\"0nrvtbf'"
pure $ pack $ (the $ List Char) [d,c]
nonEscape : Parser String
nonEscape = map (\x => pack $ (the $ List _) [x]) $ noneOf "\\\"\0\n\r\v\t\b\f"
character : Parser String
character = nonEscape <|>| escape
stringLiteralToken : Parser Token
stringLiteralToken = map (StringLiteral . concat) $ (between (char '"') (char '"')) (many character)
这解决了我的问题。