カランのブログ

今のモード ライト

深入理解 Svelte(0)— 什麼是抽象語法樹? | Svelte 系列文

前書き

このシリーズの記事は、Svelteの原理と実装について探求することを目的としています。読者がSvelteのコンパイルメカニズムとコード生成についてより深い理解を持つことを望んでいます。Svelteのコンパイルプロセスはコード解析を含むため、この記事ではまず抽象構文木(AST)について説明し、ASTの役割と重要性について詳しく説明します。

抽象構文木(AST)とは何ですか?

まずはウィキペディアの説明から始めましょう:

コンピュータ科学において、抽象構文木(abstract syntax tree、AST)または構文木(syntax tree)は、ソースコードの抽象的な構文構造を表すツリー構造の表現です。ここで言う「構文」とは、プログラム言語のソースコードを指します。ツリーの各ノードは、ソースコード内の一つの構造を表します。ここで言う「抽象」というのは、ここでの構文が現実の構文で出現するすべての詳細を表していないためです。

抽象構文木の重要性は、プログラム言語(またはマークアップ言語)をコンピュータが操作しやすい構造的な方法で記述するためです。ここでは、HTMLを見てみましょう:

<h1>これは見出しです</h1>
<p>これは段落です</p>
<ul>
  <li data-item="1">リストアイテム</li>
  <li data-item="2">リストアイテム</li>
  <li data-item="3">リストアイテム</li>
</ul>

<xxx>のようなタグは、HTMLでは「タグ」と呼ばれ、洋服のラベルのように洋服の情報を簡潔に表しています。tagには、このHTMLが表す情報が記録されています。

文字列をツリー構造に変換する理由は、HTMLのようなマークアップ言語は人間にとって理解しやすく構造化されていますが、コンピュータにとっては単なる文字列です。そのため、事前に文字列を解析し、操作しやすいツリー状のデータ構造を構築する必要があります。上記のHTMLは抽象構文木で表現できます:

HTML

HTMLをツリー構造に変換した後は、ツリーの各ノードを走査するアルゴリズムなどを使用して、対応する操作を行うことができます。例えば、ツリー内のliを検索したい場合は、ツリーを走査するアルゴリズムを使用し、tagNameliの場合に結果を返すことができます。

HTMLだけでなく、他のプログラミング言語も、それぞれが定義した構文に基づいて同様の手順があります。また、SQLやGraphQLなども、文字列を抽象構文木に変換してから他の操作を行います。

抽象構文木の表現

前の段落では、抽象構文木を図で表現しましたが、抽象構文木には他の情報も含まれる場合があります。例えば、HTMLの場合:

  • attributesがあるかどうか。ある場合はノードに格納する必要があります。
  • self-closing<input /> <video />など)タグであるかどうか。
  • 解析位置(行番号、列番号)

実際の抽象構文木をより詳しく見るには、AST Explorerを参照できます。さまざまなプログラミング言語を抽象構文木に変換することができます。ここではHTMLを例に取ります:

Screenshot_2021-02-07 AST explorer(1)

次にJavaScriptの抽象構文木を見てみましょう:

Screenshot_2021-02-07 AST explorer(2)

抽象構文木の実装

抽象構文木の実装には主に2つの方法があります。1つは、独自の構文を定義し、直接プログラムで実装する方法(手書き)です。もう1つは、構文規則(BNFなど)を定義し、yaccPEG.jsなどのジェネレータを使用してパーサーを生成する方法です。

以前にJSONパーサーをゼロから実装する方法についても記事を書いていますので、興味があれば参考にしてください:

以前に紹介したlinariaの記事では、ASTの原理についても触れていますので、興味があれば参考にしてください。

ただし、正確な抽象構文木の実装は簡単ではありません。HTMLのような比較的単純なマークアップ言語に対しては比較的簡単ですが、CJavaJavaScriptなどのプログラミング言語に対しては正確でエラーのない抽象構文木を実装するには時間がかかります。また、仕様書に従って実装する必要があります。練習として実装する場合は、一部の構文を実装することをお勧めします。

実際、Svelteでは、HTMLとSvelteテンプレート構文以外は、JavaScriptやCSSなども他の人が作成したパーサーを使用して実装されています。次の記事では、簡単なSvelte構文パーサーの実装方法について説明しますが、ここでは詳細に触れません。

実装を待ちきれない場合は、私が作成した tiny-svelte を参考にするか、Svelteのソースコードを直接参照してください。

抽象構文木の利用

抽象構文木は非常に重要ですが、単独では何もできません。コードをコンパイルするためには、コード生成(code generation)のステップが必要です。抽象構文木は、次のような用途にも使用できます:

  • コードのハイライト表示
  • コードの自動補完
  • prettify
  • eslint

(以下、以前の同僚である @kai が補足)

  • Babelプラグインの作成
  • 静的解析(TypeScript)
  • コードの置換(codemod)

これらのツールはすべて、抽象構文木を基にして構築されています。これは、抽象構文木の重要性を示す十分な証拠です。抽象構文木が手元にあれば、何でもできるようなものです。想像力は無限です。

結論

この記事では、抽象構文木の存在と利用方法について説明しました。抽象構文木をコンパイルするためには、コード生成のステップが必要であることを理解していただきたいです。Svelteのコンパイルプロセスでは、まずコードを抽象構文木に変換する必要があるため、抽象構文木について説明することは、後の記事をより理解しやすくするために重要です。

この文章が役に立つと思うなら、下のリンクで応援してくれると大変嬉しいです✨

Buy me a coffee