我正在研究一種類似于 ruby?? 的語言,稱為gaiman,我正在使用 PEG.js 來生成決議器。
你知道是否有辦法用適當的縮進來實作heredocs?
xxx = <<<END
hello
world
END
輸出應該是:
"hello
world"
我需要這個,因為這段代碼看起來不太好:
def foo(arg) {
if arg == "here" then
return <<<END
xxx
xxx
END
end
end
這是用戶想要回傳的函式:
"xxx
xxx"
我希望代碼看起來像這樣:
def foo(arg) {
if arg == "here" then
return <<<END
xxx
xxx
END
end
end
如果我修剪所有行,用戶將無法在需要時使用帶前導空格的字串。有誰知道 PEG.js 是否允許這樣做?
我還沒有任何用于heredocs 的代碼,只是想確定我想要的東西是否可行。
編輯:
所以我試圖實作heredocs,問題是PEG不允許反向參考。
heredoc = "<<<" marker:[\w] "\n" text:[\s\S] marker {
return text.join('');
}
它說標記未定義。至于修剪我想我可以使用location()功能
uj5u.com熱心網友回復:
我不認為這是對決議器生成器的合理期望;很少有人能與挑戰相提并論。
首先,識別 here-string 語法本質上是背景關系敏感的,因為結束分隔符必須是<<<標記后提供的分隔符的精確副本。所以你需要一個自定義詞法分析器,這意味著你需要一個決議器生成器,它允許你使用自定義詞法分析器。(因此,假設您需要無掃描儀的決議器的決議器生成器可能不是最佳選擇。)
識別 here-string 標記的結尾應該不會太困難,盡管您無法使用單個正則運算式來完成。我的方法是使用自定義掃描函式,將 here-string 分成一系列行,將它們連接起來,直到到達僅包含結束分隔符的行。
一旦你識別了文字的文本,你需要以你想要的方式規范化空格,就是開始的列號<<<。這樣,您可以修剪字串文字中的每一行。所以你只需要一個詞法掃描器,它可以準確地報告標記位置。修整通常不會在生成的詞法掃描器內完成;相反,它將是相關的語意動作。(同樣,它可能是語法中的語意動作。但它始終是您撰寫的代碼。)
當您修剪文字時,您需要處理不可能的情況,因為用戶沒有遵守縮進要求。你需要對制表符做一些事情;得到這些正確的可能意味著你需要一個詞法掃描器來計算可見的列位置而不是字符偏移。
我不知道 peg.js 是否符合這些要求,因為我不使用它。(我確實查看了檔案,但沒有看到有關如何合并自定義掃描儀功能的任何指示。但這并不意味著沒有辦法做到這一點。)我希望至少上面的討論允許您檢查要使用的決議器生成器的詳細檔案,否則可以找到適合您在此用例中使用的其他決議器生成器。
uj5u.com熱心網友回復:
這是 PEG.js 的 Peggy 繼承者中heredocs 的實作,不再維護。此代碼基于GitHub 問題。
heredoc = "<<<" begin:marker "\n" text:($any_char "\n") _ end:marker (
&{ return begin === end; }
/ '' { error(`Expected matched marker "${begin}", but marker "${end}" was found`); }
) {
const loc = location();
const min = loc.start.column - 1;
const re = new RegExp(`\\s{${min}}`);
return text.map(line => {
return line[0].replace(re, '');
}).join('\n');
}
any_char = (!"\n" .)
marker_char = (!" " !"\n" .)
marker "Marker" = $marker_char
_ "whitespace"
= [ \t\n\r]* { return []; }
編輯:上面沒有在heredoc之后使用另一段代碼,這里有更好的語法:
{ let heredoc_begin = null; }
heredoc = "<<<" beginMarker "\n" text:content endMarker {
const loc = location();
const min = loc.start.column - 1;
const re = new RegExp(`^\\s{${min}}`, 'mg');
return {
type: 'Literal',
value: text.replace(re, '')
};
}
__ = (!"\n" !" " .)
marker 'Marker' = $__
beginMarker = m:marker { heredoc_begin = m; }
endMarker = "\n" " "* end:marker &{ return heredoc_begin === end; }
content = $(!endMarker .)*
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/321984.html
上一篇:決議陳述句并為其添加括號
