web-dev-qa-db-ja.com

JSのソースマップが通常トークン単位であるのはなぜですか?

JavaScriptのソースマップは通常、tokenの粒度よりも細かくないようです。例として、 identity-mapはトークンの粒度を使用します です。

他の例を見たことがありますが、どこで覚えているかわかりません。

代わりに、ASTノードベースの粒度を使用しないのはなぜですか?つまり、ソースマップにすべての場所があり、ASTノードの開始点のみが含まれている場合、どのような欠点がありますか?

私の理解では、ソースマップはクラッシュスタックのデコードとデバッグに使用されます。ASTノードの先頭にないエラーの場所や有用なブレークポイントはありませんよね?

アップデート1

いくつかのさらなる明確化:

  • この質問は、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(),
    });
}

アップデート2

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:パイプライン全体を制御し、どこでも同じパーサーを使用していると想定します。


22
Max Heiber

AST細分性を使用することは可能ですが、通常ASTを構築するには、とにかくコードをトークン化する前に必要です。デバッグのためにASTは不要なステップです構文アナライザーが機能するためには、トークン化されたデータを供給する必要があるためです。

興味深いリソース トピックについて

acornJS sourcecode を調べて、それがどのように生成されるかを確認することもお勧めします [〜#〜] ast [〜#〜]

2
Mosè Raguzzini

TypeScriptコンパイラは、実際にはASTノード境界でのみソースマップの場所を出力しますが、特定の位置のマッピングを期待する特定のツールとの互換性を向上させるためにいくつかの例外があるため、トークンベースのマップは実際にはありませんあなたの例では、TSのソースマップは次のような位置にあります。

const a = function *() { return a + ++ b } /*
^     ^^  ^              ^      ^^  ^  ^^^
*/

通常、どちらも開始ですおよび各識別子の終わりASTノード(およびそれ以外の場合は開始)。

識別子の開始および終了位置の両方をマッピングする根拠ASTノードは非常に単純です-識別子の名前を変更すると、名前を変更した識別子の選択範囲が必ずしもヒューリスティックスに依存せずに、元の識別子にマップできます。

2
Wesley Wigham