Lightyear 解析器以意想不到的方式运行

Lightyear parser behaves in unexpected way

我正在尝试使用 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'"]

这是我所期望的。

我认为错误是由于我解析字符串文字的方式引起的,但我无法理解我的错误,而且我找不到调试 lightyear 解析器的好方法。 我的字符串文字解析器的实现如下:

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 "\\"[=13=]\n\r\v\t\b\f"

character : Parser String
character = nonEscape <|>| escape

stringLiteralToken : Parser Token
stringLiteralToken = map (StringLiteral . concat) $ dquote (many character)

如何防止我的字符串文字解析器耗尽文字后的空格?

在#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 "\\"[=10=]\n\r\v\t\b\f"

character : Parser String
character = nonEscape <|>| escape

stringLiteralToken : Parser Token
stringLiteralToken = map (StringLiteral . concat) $ (between (char '"') (char '"')) (many character)

这解决了我的问题。