如果unindent与任何外部缩进级别不匹配,则使Text.Parsec.Indent解析失败

时间:2014-07-27 16:51:38

标签: haskell indentation parsec

我正在尝试解析代表树的Haskell中的字符串。每个节点都在一行上,缩进决定了嵌套(例如Python或Haskell的语法)。

成功的解析结果应该是[Tree]类型(玫瑰树林),其中

data Tree = Tree String [Tree]
          deriving Show

例如,字符串

A
    B
    C
D
    E
        F

应该导致

[Tree "A" [Tree "B" [], Tree "C" []], Tree "D" [Tree "E" [Tree "F" []]]]

使用Haskell indents packagearticle about how to parse indented trees的帮助,我可以解析这样的示例。

问题是我当前的实现成功解析了字符串

A
    B
        C
      D

作为

[Tree "A" [Tree "B" [Tree "C" []]], Tree "D" []]

节点D被解析为另一个根。但是,我想使解析失败,因为D相对于C是未缩进的,但它与AB的缩进级别不匹配。

我的实现如下(简化:树标签非空且仅包含字母数字字符;不支持所有类型的Unicode换行符。)

import qualified Control.Applicative as A
import qualified Control.Monad as M
import qualified Text.Parsec as P
import qualified Text.Parsec.Indent as I

parse :: String -> Either P.ParseError [Tree]
parse = I.runIndent "" . P.runParserT forest () ""

forest = P.many tree A.<* P.eof

tree = spacing A.*> I.withBlock Tree node tree

spacing = P.many P.newline A.*> indentation

indentation = P.many $ P.char ' '

node = label A.<* spacing

label = P.many1 P.alphaNum A.<* lineEnd

lineEnd = M.void P.newline P.<|> P.eof

如何将此解析器更改为仅接受与某些外部缩进级别匹配的unindents?提前谢谢。

1 个答案:

答案 0 :(得分:2)

只需用{/ 1>替换forest的定义即可

forest = I.block tree A.<* P.eof

似乎可以解决问题。 I.block这里确保源字符串的根缩进到同一级别。

示例

A
    B
        C
      D

现在失败了

(line 4, column 7):
unexpected 'D'
expecting " " or end of input
not indented or indentation doesn't match

P.many tree的问题是tree可以任意缩进。只要tree的未注册与任何外部缩进级别(示例中为D)不匹配,解析器就会愉快地生成{{{的另一个顶级tree(根) 1}}而不是失败。