JavaScriptのソースマップは通常、tokenの粒度よりも細かくないようです。例として、 identity-mapはトークンの粒度を使用します です。
他の例を見たことがありますが、どこで覚えているかわかりません。
代わりに、ASTノードベースの粒度を使用しないのはなぜですか?つまり、ソースマップにすべての場所があり、ASTノードの開始点のみが含まれている場合、どのような欠点がありますか?
私の理解では、ソースマップはクラッシュスタックのデコードとデバッグに使用されます。ASTノードの先頭にないエラーの場所や有用なブレークポイントはありませんよね?
いくつかのさらなる明確化:
この質問は、ASTがすでに知られている場合に関係します。したがって、「ASTトークンの配列よりも生成する方がコストが高い」と答えることはできません。質問。
この質問の実際的な影響は、デバッガーとクラッシュスタックデコーダーの動作を維持しながらソースマップの粒度を減らすことができれば、ソースマップがはるかに小さくなる可能性があることです。主な利点は、デバッガーのパフォーマンスです。開発ツールは、大きなソースファイルを処理するのに長い時間がかかり、デバッグが面倒になります。
source-map ライブラリを使用して、トークンレベルでソースマップの場所を追加する例を次に示します。
for (const token of tokens) {
generator.addMapping({
source: "source.js",
original: token.location(),
generated: generated.get(token).location(),
});
}
また、ASTノードレベルで場所を追加する例を次に示します。
for (const node of nodes) {
generator.addMapping({
source: "source.js",
original: node.location(),
generated: generated.get(node).location(),
});
}
Q1:ASTノードの開始がトークンの開始よりも少ないと予想されるのはなぜですか?
A1:ASTノードの開始がトークンの開始より多い場合、AST Nodeは非トークンで始まります。これは、パーサーの作成者にとってはかなりの成果です!これを具体的にするために、次のJavaScriptステートメントがあるとします。
const a = function *() { return a + ++ b }
トークンの開始位置は次のとおりです。
const a = function *() { return a + ++ b } /*
^ ^ ^ ^^^ ^ ^ ^ ^ ^ ^ ^
*/
ここに大体のパーサがASTノードの始まりと言います。
const a = function *() { return a + ++ b } /*
^ ^ ^ ^ ^ ^ ^
*/
これは、ソースマップの場所の数で46%削減です。
Q2:AST-Node-granularityのソースマップが小さくなると予想されるのはなぜですか?
A2:上記のA1を参照
Q3:ASTノードを参照するためにどの形式を使用しますか?
A3:フォーマットはありません。上記のpdate 1のサンプルコードを参照してください。 ASTノードの開始にソースマップの場所を追加することについて話している。このプロセスは、トークンの開始にソースマップの場所を追加するプロセスとほとんど同じですが、追加する数が少ない場所。
Q4:ソースマップを扱うすべてのツールが同じAST表現を使用していると主張するにはどうすればよいですか?
A4:パイプライン全体を制御し、どこでも同じパーサーを使用していると想定します。
AST細分性を使用することは可能ですが、通常ASTを構築するには、とにかくコードをトークン化する前に必要です。デバッグのためにASTは不要なステップです構文アナライザーが機能するためには、トークン化されたデータを供給する必要があるためです。
興味深いリソース トピックについて
acornJS sourcecode を調べて、それがどのように生成されるかを確認することもお勧めします [〜#〜] ast [〜#〜]
TypeScript
コンパイラは、実際にはASTノード境界でのみソースマップの場所を出力しますが、特定の位置のマッピングを期待する特定のツールとの互換性を向上させるためにいくつかの例外があるため、トークンベースのマップは実際にはありませんあなたの例では、TSのソースマップは次のような位置にあります。
const a = function *() { return a + ++ b } /*
^ ^^ ^ ^ ^^ ^ ^^^
*/
通常、どちらも開始ですおよび各識別子の終わりASTノード(およびそれ以外の場合は開始)。
識別子の開始および終了位置の両方をマッピングする根拠ASTノードは非常に単純です-識別子の名前を変更すると、名前を変更した識別子の選択範囲が必ずしもヒューリスティックスに依存せずに、元の識別子にマップできます。