光年解析器以意想不到的方式表现

时间:2017-08-14 07:19:36

标签: whitespace idris parser-combinators lightyear

我正在尝试使用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)

如何防止我的字符串文字解析器在文字后面占用空格?

1 个答案:

答案 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)

这解决了我的问题。