那麼,這裏有一個方法來做到這一點。這可能不是最好的,它絕對不是直覺(我不知道我明白它爲什麼可行,而我寫道它:)但它似乎是相當強大的。
基本上它說:一個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