ソースマッピング
コンパイラは、ASTの出力の一部として、ASTの各ノードで表現されるソースコードの範囲を提供します。 これは、ASTに基づいてエラーを報告する静的解析ツールや、ローカル変数とその用途を強調するデバッグツールなど、さまざまな目的に利用できます。
さらに、コンパイラは、バイトコードから、その命令を生成したソースコードの範囲へのマッピングを生成することもできます。 これは、バイトコードレベルで動作する静的解析ツールや、デバッガ内でソースコードの現在の位置を表示したり、ブレークポイントを処理する際にも重要です。 このマッピングには、ジャンプタイプやモディファイアの深さなど、他の情報も含まれています(後述)。
どちらのソースマッピングも、ソースファイルの参照には整数の識別子を使用します。
ソースファイルの識別子は output['sources'][sourceName]['id']
に格納され、 output
はJSONとして解析されたstandard-jsonコンパイラインターフェースの出力です。
一部のユーティリティルーチンでは、コンパイラーは元の入力の一部ではなく、ソースマッピングから参照される「内部」ソースファイルを生成します。
これらのソースファイルは、その識別子とともに、 output['contracts'][sourceName][contractName]['evm']['bytecode']['generatedSources']
を通じて入手できます。
注釈
特定のソースファイルに関連付けられていない命令の場合、ソースマッピングでは -1
という整数の識別子が割り当てられます。
これは、コンパイラによって生成されたインラインアセンブリ文に由来するバイトコードセクションで発生する可能性があります。
AST内部のソースマッピングは以下の表記を使用しています。
s:l:f
s
はソースファイル内の範囲の開始点へのバイトオフセット、 l
はソース範囲の長さ(バイト)、 f
は前述のソースインデックスです。
バイトコードのソースマッピングでのエンコーディングはもっと複雑です。
それは ;
で区切られた s:l:f:j:m
のリストです。
これらの要素はそれぞれ命令に対応しています。
つまり、バイトオフセットを使用することはできず、命令オフセットを使用する必要があります(プッシュ命令は1バイトよりも長い)。
フィールド s
、 l
、 f
は上記の通りです。
j
は i
、 o
、 -
のいずれかで、ジャンプ命令が関数に入るのか、関数から戻るのか、ループなどの一部としての通常のジャンプなのかを示します。
最後のフィールド m
は、「モディファイアの深さ」を示す整数です。
この深さは、モディファイアにプレースホルダー文( _
)が入力されるたびに増加し、再び入力されると減少します。
これにより、同じモディファイアが2回使われたり、1つのモディファイアに複数のプレースホルダー文が使われたりするようなトリッキーなケースをデバッガーが追跡できます。
特にバイトコードの場合、これらのソースマッピングを圧縮するために、以下のルールが使われています。
フィールドが空の場合は、直前の要素の値が使用されます。
:
がない場合、以下のすべてのフィールドは空であるとみなされます。
これは、次のソースマッピングが同じ情報を表していることを意味します。
1:2:1;1:9:1;2:1:2;2:1:2;2:1:2
1:2:1;:9;2:1:2;;
重要なのは、 verbatim ビルトインを使用すると、ソースマッピングが無効になることです。 ビルドインは複数の命令ではなく、1つの命令とみなされます。