使用foldLine解析许多块

时间:2016-05-16 14:27:15

标签: parsing haskell indentation megaparsec

对于这个简化的问题,我试图解析看起来像

的输入
foo bar
 baz quux 
 woo
hoo xyzzy 
  glulx

进入

[["foo", "bar", "baz", "quux", "woo"], ["hoo", "xyzzy", "glulx"]]

我尝试过的代码如下:

import qualified Text.Megaparsec.Lexer as L
import Text.Megaparsec hiding (space)
import Text.Megaparsec.Char hiding (space)
import Text.Megaparsec.String
import Control.Monad (void)
import Control.Applicative

space :: Parser ()
space = L.space (void spaceChar) empty empty

item :: Parser () -> Parser String
item sp = L.lexeme sp $ some letterChar

items :: Parser () -> Parser [String]
items sp = L.lineFold sp $ \sp' -> some (item sp')

items_ :: Parser [String]
items_ = items space

适用于items的一个块:

λ» parseTest items_ "foo bar\n baz quux\n woo"
["foo","bar","baz","quux","woo"]

但是一旦我尝试解析many items,它就会在第一个未缩进的行上失败:

λ» parseTest (many items_) "foo bar\n baz quux\n woo\nhoo xyzzy\n  glulx"
4:1:
incorrect indentation (got 1, should be greater than 1)

或者,输入更简单:

λ» parseTest (many items_) "a\nb"
2:1:
incorrect indentation (got 1, should be greater than 1)

1 个答案:

答案 0 :(得分:4)

Megaparsec的作者在这里:-)当你合作时要记住一件事 Megaparsec认为它的lexer模块实际上是“低级”的。它 没有做任何你自己无法建立的事情,也没有把你锁定在任何事物中 特别是“框架”。所以基本上在你的情况下你有空间消费者 sp'为您提供,但您应该仔细使用它,因为它肯定会 当缩进级别小于或等于缩进级别时失败 整个折叠的开始,顺便说一句,你的折叠结束了。

引用the docs

  

创建支持换行的解析器。第一个参数用于   消耗线折叠的组件之间的空白区域,因此它必须消耗   换行以便正常工作。第二个参数是回调   接收自定义空间消耗解析器作为参数。这个解析器应该是   在折叠的单独组件之后使用,可以放在不同的部分   线。

sc = L.space (void spaceChar) empty empty

myFold = L.lineFold sc $ \sc' -> do
  L.symbol sc' "foo"
  L.symbol sc' "bar"
  L.symbol sc  "baz" -- for the last symbol we use normal space consumer

折线无法无限期运行,因此您应该预期它会因错误而失败 消息类似于您现在拥有的消息。要想成功,你应该思考 关于完成它的方法。这通常通过使用“正常”来完成 在行尾折叠的空间消费者:

space :: Parser ()
space = L.space (void spaceChar) empty empty

item :: Parser String
item = some letterChar

items :: Parser () -> Parser [String]
items sp = L.lineFold sp $ \sp' ->
  item `sepBy1` try sp' <* sp

items_ :: Parser [String]
items_ = items space

item `sepBy1` try sp'一直运行直至失败,然后sp抓住其余部分,所以 可以解析下一个折叠。

λ> parseTest items_ "foo bar\n baz quux\n woo"
["foo","bar","baz","quux","woo"]
λ> parseTest (many items_) "foo bar\n baz quux\n woo\nhoo xyzzy\n  glulx"
[["foo","bar","baz","quux","woo"],["hoo","xyzzy","glulx"]]
λ> parseTest (many items_) "foo bar\n baz quux\n woo\nhoo\nxyzzy\n  glulx"
[["foo","bar","baz","quux","woo"],["hoo"],["xyzzy","glulx"]]