Skip to content

決定事項

ECMAScript® 2023 言語仕様 は、JavaScript 言語のすべてを詳細に記述しており、誰もが独自の JavaScript エンジンを実装できるようにしています。

当社のパーサーを学習するには、以下の章を理解する必要があります:

  • 第5章:表記規則
  • 第11章:ECMAScript 言語:ソーステキスト
  • 第12章:ECMAScript 言語:構文解析
  • 第13~16章:式、文、関数、クラス、スクリプトおよびモジュール
  • 付録B:ウェブブラウザ用の追加の ECMAScript 機能
  • 付録C:ECMAScript の厳格モード

仕様書内のナビゲーションについて:

  • クリック可能な要素はすべて永続的なリンクを持ち、URL のアンカーとして表示されます。たとえば #sec-identifiers
  • 要素にカーソルを合わせるとツールチップが表示され、参照 をクリックするとすべての参照が表示されます

表記規則

第5.1.5節 语法表記 を読む必要があります。

ここでの注目ポイントは以下の通りです:

再帰

これは、文法におけるリストの表現方法です。

引数リスト :
  代入式
  引数リスト , 代入式

これは次のように意味します。

javascript
a, b = 1, c = 2
^_____________^ 引数リスト
   ^__________^ 引数リスト, 代入式,
          ^___^ 代入式

オプション

オプションの構文には _opt_ という接尾辞が付けられます。例えば、

変数宣言 :
  バインディング識別子 初期化子_opt

これは次のように意味します。

javascript
var binding_identifier;
var binding_identifier = 初期化子;
                       ______________ 初期化子_opt

パラメータ

[Return] および [In] は、文法のパラメータです。

たとえば

スクリプト本体 :
    文のリスト[~Yield, ~Await, ~Return]

は、スクリプト内ではトップレベルの yieldawaitreturn は許可されないことを意味しますが、

モジュール項目 :
  インポート宣言
  エクスポート宣言
  文項目リスト[~Yield, +Await, ~Return]

は、トップレベルの await を許可します。

ソーステキスト

第11.2節 ソースコードの種類 によると、 スクリプトコードとモジュールコードの間に大きな違いがあることがわかります。 また、use strict モードにより、古い JavaScript の振る舞いを禁止することで、文法がより明確になります。

スクリプトコード は非厳格モードであり、use strict をファイルの先頭に挿入することで、スクリプトコードを厳格モードにする必要があります。 HTML では <script src="javascript.js"></script> と記述します。

モジュールコード は自動的に厳格モードです。 HTML では <script type="module" src="main.mjs"></script> と記述します。

ECMAScript 言語:構文解析

より詳しく知りたい場合は、V8ブログの ECMAScript仕様の理解 を読んでください。

自動セミコロン挿入

この節では、JavaScriptを書く際にセミコロンを省略できるすべてのルールについて説明しています。 すべての説明は次のようになります。

rust
    pub fn asi(&mut self) -> Result<()> {
        if self.eat(Kind::Semicolon) || self.can_insert_semicolon() {
            return Ok(());
        }
        let range = self.prev_node_end..self.cur_token().start;
        Err(SyntaxError::AutoSemicolonInsertion(range.into()))
    }

    pub const fn can_insert_semicolon(&self) -> bool {
        self.cur_token().is_on_new_line || matches!(self.cur_kind(), Kind::RCurly | Kind::Eof)
    }

asi 関数は、適用可能な場所で手動で呼び出す必要があります。たとえば、文の終端では:

rust
fn parse_debugger_statement(&mut self) -> Result<Statement<'a>> {
    let node = self.start_node();
    self.expect(Kind::Debugger)?;
    self.asi()?; 
    self.ast.debugger_statement(self.finish_node(node))
}

INFO

この ASI(自動セミコロン挿入)に関するセクションは、パーサーを想定して書かれています。 明確に、ソーステキストは左から右へとパースされるということを述べており、これにより他の方法でパーサーを書くことはほとんど不可能です。 jsparagusの作者がこの点について怒っている記事がこちらにあります。

この機能の仕様は非常に高レベルであり、奇妙な手続き的表現(「ソーステキストが左から右にパースされる際、トークンが出現したとき…」など、まるでブラウザの物語を語っているかのようです。少なくとも私の知る限り、仕様書の中でパーサーの内部実装の詳細について何か仮定または暗黙に示しているのは、これが唯一の例です。しかし、ASI をそれ以外の方法で規定するのは困難でしょう。 :::

式、文、関数、クラス、スクリプトおよびモジュール

構文論の仕様を理解するには時間がかかりますが、その後、それをパーサーの作成に適用することができるようになります。