那么,这里有一个方法来做到这一点。这可能不是最好的,它绝对不是直觉(我不知道我明白它为什么可行,而我写道它:)但它似乎是相当强大的。
基本上它说:一个tree
是一个line
可选后跟一个block
。 A block
又是tree
s的缩进列表。
indent
是一个函数,它接受当前缩进级别,并返回一个需要缩进的分析器。返回的解析器返回一堆以前的缩进级别。
我之前说过它很健壮 - 实际上,它的也是健壮。它接受真正应该抛出错误的输入:如果您取消缩进与之前的级别不匹配的缩进级别,它基本上会“向上舍入”到下一个缩进级别。我不确定要修复的逻辑应该在哪里进行 - 相互递归与解析器“链”混合在一起很难遵循!
var {regex, seq} = Parsimmon;
function tree(state) {
return seq(
line,
block(state).atMost(1).map(x => x[0]? x[0] : [])
);
}
function block(state) {
return indent(state)
.chain(tree).atLeast(1);
}
function indent(state) {
return regex(/\s/).atLeast(state + 1)
.map(x => x.length)
.desc('indent');
}
let item = regex(/[^\s].*/).desc('item');
let line = item.skip(regex(/\n?/));
let start = block(-1);
let result = start.parse('top item 1\n sub item 1\n sub item 2\n' +
' even deeper\n sub item 3\ntop item 2');
console.log(JSON.stringify(result['value'], null, 2));
<script src="https://cdn.rawgit.com/jneen/parsimmon/master/src/parsimmon.js"></script>
我知道我们鼓励代码示例,但我到目前为止在这花了6小时,没有代码,甚至部分还没有工作... – Josh