ソースの位置情報を使用して AST を構築するためのパーサー コンビネーターをいくつか作成しました。プロファイリングは、少なくとも実行の 30% パーセントが不要な情報を繰り返し解析してソース ロケーション データを生成するために費やされていることを示しています。パフォーマンスを改善するための別のアプローチを見つける手助けが必要です。
問題
「A」と「B」の 2 つのトークンだけで構成される言語を解析しているとします。AST ノードを生成するために、現在、場所を抽出してノードを構築するコンビネータを定義しています。
// Parse body and build resulting node from function
// nodeFactory called with position and result from body.
var node = function(body, nodeFactory) {
return bind(
locParser, // get the current location in the token stream
body,
prevEnd, // get the previous end position in the token stream
function(o, x, c) {
return always(f(Location(o, c), x));
});
};
var a = node(char('A'), buildNodeA);
var b = node(char('B'), buildNodeB);
このアプローチの問題はlocParser
、本体が成功するかどうかに関係なく、常に実行されることです。
var element = either(a, b);
var program = many(element);
run(program, "AAABBA");
予想される行動
a
失敗することが明らかになったらすぐにbody
失敗します。
実際の動作
「B」トークンの場合、最初locParser
に fora
が実行され、body
失敗するとlocParser
forb
が実行されます。ネストと分岐が増えると、これはパフォーマンスの問題になります。
エッジケース
場所には、消費される入力の全範囲が含まれます。
var c = node(next(char(' '), char('C')), buildNodeC);
「C」ノードの位置は、スペース文字の先頭から始まります。
var d = node(between(char('('), char(')'), char('D')), buildNodeD);
「D」ノードの位置は、「(」の開始点から始まり、「)」の終了点で終わります。これらのケースはどちらも、 によって正しく処理されnode
ます。
質問
これらのパーサーをリファクタリングして、すぐに失敗しても正しい位置データにアクセスするにはどうすればよいですか?
各パーサーを自己完結型に保ち、ロジックの繰り返しを避けることをお勧めします。さらに、構築後にノードを変更してはなりません。