Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Acorn への Explicit Resource Management 構文サポート実装

Acorn への Explicit Resource Management 構文サポート実装

本スライドでは、JavaScript パーサー Acorn における Explicit Resource Management (ERM) 構文サポートの実装について解説します。
• ECMAScript 提案の背景と目的
メモリやファイルハンドルなどのリソースを明示的に管理する仕組みを提供することで、コードの安全性・可読性を高める狙いがあります。
• 仕様書の読み解き方
ECMAScript 言語仕様の構文定義を実例を交えながら紹介し、using や await using などの新しい構文がどのように定義されているかを説明します 。
• 実装における課題
• using が 予約語でないことによるパース上の曖昧さ
• バックトラックのない Acorn での判定の難しさ
• 部分的に再解釈する実装手法やカバー文法の工夫
• 具体的な実装例
Acorn のコード断片を引用し、どのように await using を解釈しているかを詳細に解説します 。

この発表は、言語仕様やパーサー実装に関心のあるエンジニアを対象に、仕様書と実装の橋渡しを意識した内容となっています。

Avatar for Yuichiro Yamashita

Yuichiro Yamashita

September 06, 2025
Tweet

More Decks by Yuichiro Yamashita

Other Decks in Programming

Transcript

  1. 自己紹介
 • 株式会社フライル
 ◦ ソフトウェアエンジニア
 ◦ 最近は ClickHouse というデータベースと格闘しています
 


    • Svelte コアチーム
 ◦ 最近は eslint-plugin-svelte や svelte-eslint-parser を担当しています

  2. アジェンダ
 • ECMAScript / TC39 とは何か
 • JavaScript パーサー /

    Acorn とは何か
 • Explicit Resource Management とは何か
 • 言語仕様書の読み方
 • 実装する上で難しかったこと

  3. ECMAScript / TC39 とは何か
 Ecma International という標準化団体が様々な仕様の標準化を推進しており、「ECMA-262」という文書にて、 「ECMAScript」を定義しています。 
 (ちなみに、JSONの規格は

    ECMA-404 で定義されています) 
 「ECMAScript」は、JavaScriptの言語仕様です。JavaScriptの機能や文法、APIなどの仕様を定義しています。 
 Ecma International の TC39 は、JavaScript開発者、実装者、専門家などのグループで、JavaScriptの仕様をメ ンテナンスし発展させるためにコミュニティと協力しています。 
 (出典: https://tc39.es/ja/)
 1言で簡単にいうと TC39 というグループが JavaScript の仕様を決めている。

  4. ECMAScript / TC39 とは何か
 TC39 には、正式に仕様として承認されるまでに複数のステージが存在します 
 ステージ
 説明
 0


    新しい提案。TC39では未検討 
 1
 検討中。チャンピオン (提案責任者) が設定される 
 2
 設計はまだ草案段階であり、今後大幅に変更される可能性があるが、委員会は、この 機能が開発され、最終的に標準規格に含まれることを期待している 
 2.7
 提案は原則的に承認され、検証中 
 3
 この提案は実装が推奨されている 
 4
 提案された機能は完成している。2つの独立したVMによって提供されている 

  5. JavaScript パーサー / Acorn とは何か
 JavaScriptパーサーとは、JavaScriptのコードを「構造化された情報」に変換するプログラムのことで す。
 Acorn とは、JavaScript パーサーのひとつ。Next.js

    / Svelte / Webpack / Prettier / ESLint / Rollup (スター数順) など多くの有名なライブラリが Acorn に依存しています。 
 A tiny, fast JavaScript parser, written completely in JavaScript. 
 (完全に JavaScript で書かれた、小型で高速な JavaScript パーサーです) 
 (出典: https://github.com/Acornjs/Acorn) 

  6. JavaScript パーサー / Acorn とは何か
 console.log("hi!")
 {
 "type": "Program",
 "body":

    [{
 "type": "ExpressionStatement",
 "expression": {
 "type": "CallExpression",
 "callee": {
 "type": "MemberExpression",
 "object": { "type": "Identifier", "name": "console" },
 "property": { "type": "Identifier", "name": "log" },
 "computed": false,
 "optional": false
 },
 "arguments": [{ "type": "Literal", "value": "hi", "raw": "\"hi\"" }],
 "optional": false
 }
 }],
 "sourceType": "module"
 }
 
 パースすると
  7. Explicit Resource Management とは何か
 This proposal intends to address a

    common pattern in software development regarding the lifetime and management of various resources (memory, I/O, etc.). This pattern generally includes the allocation of a resource and the ability to explicitly release critical resources. 
 この提案は、ソフトウェア開発における様々なリソース(メモリ、I/Oなど)の有効期間と管理に関する 一般的なパターンに対処することを目的としています。このパターンには、一般的に、リソースの割り 当てと、重要なリソースを明示的に解放する機能が含まれます。 
 
 出典: https://github.com/tc39/proposal-explicit-resource-management 
 
 

  8. Explicit Resource Management とは何か
 function begin() {
 const conn =

    {
 execute: (sql) => { console.log(`[log] Run SQL "${sql}".`) },
 dispose: () => { console.log('[log] Connection disposed.' ) },
 };
 console.log(`[log] Connection established.` );
 return {
 execute: conn.execute,
 [Symbol.dispose]() {
 conn.dispose();
 },
 };
 }
 function main() {
 using conn = begin();
 conn.execute('SELECT 1');
 }
 
 main();

  9. Explicit Resource Management とは何か
 function begin() {
 const conn =

    {
 execute: (sql) => { console.log(`[log] Run SQL "${sql}".`) },
 dispose: () => { console.log('[log] Connection disposed.' ) },
 };
 console.log(`[log] Connection established.` );
 return {
 execute: conn.execute,
 [Symbol.dispose]() {
 conn.dispose();
 },
 };
 }
 function main() {
 using conn = begin();
 conn.execute('SELECT 1');
 }
 
 main();
 ポイント1
 
 dispose というシンボルの関数を定 義する
 ポイント2
 
 using というキーワード (≠予約語) を用いて変数宣言する 

  10. Explicit Resource Management とは何か
 function begin() {
 const conn =

    {
 execute: (sql) => { console.log(`[log] Run SQL "${sql}".`) },
 dispose: () => { console.log('[log] Connection disposed.' ) },
 };
 console.log(`[log] Connection established.` );
 return {
 execute: conn.execute,
 [Symbol.dispose]() {
 conn.dispose();
 },
 };
 }
 function main() {
 using conn = begin();
 conn.execute('SELECT 1');
 }
 
 main();

  11. Explicit Resource Management とは何か
 他にも
 • using の非同期版である await using

    / symbol.asyncDispose
 • using を更に込み入った使い方をするための DisposableStack
 • DisposableStack の非同期版である AsyncDisposableStack
 があります。

  12. Explicit Resource Management とは何か
 ⚠ 注意
 • 本機能は TC39 にてステージ4に進むことが承認されているフェーズです


    • 2025年9月4日時点では、 v8 (Chrome) / SpiderMonkey (Firefox) に実装済みで す。(JavaScript Core (Safari) は現在実装中)
 

  13. 言語仕様書の読み方
 UsingDeclaration は、 
 using という終端記号の後に、 
 改行を含まずに BindingList 非終端記号が続く

    
 
 (BindingList は、例えば foo = 1; みたいな) 
 出典: https://arai-a.github.io/ecma262-compare/snapshot.html?pr=3000
  14. 言語仕様書の読み方
 LexicalDeclaration は、 let, const で宣言する以外 に using, await using

    で宣言できる。 
 出典: https://arai-a.github.io/ecma262-compare/snapshot.html?pr=3000
  15. using が予約語でないことによる難しさ
 予約語とは変数名や関数名に使用できないキーワードのこと 
 例: if, for, while, class, const

    など
 出典: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords
 条件つきの予約語もある
 • strict mode でのみ予約語: let, static, yield 
 • モジュールもしくは非同期関数でのみ予約語: await 
 将来のために予め予約されている語もある 
 例: enum, implements, interface (※ enum 以外は strict mode でのみ予約されている)
 👉 ここに using もあったらよかったのに 😅

  16. using が予約語でないことによる難しさ
 {
 // ケース1
 using using = foo();
 //

    ケース2
 using = 5;
 
 // ケース3
 using
 x = resource;
 }
 

  17. using が予約語でないことによる難しさ
 【ケース1,2】
 using だけを読んでも、何も確定できない。 
 using の後にシンボルが来た場合のみ、変数宣言であると確定できる。 
 (await

    using の場合は2トークン分先読みしないと変数宣言であると確定できな い)
 {
 // ケース1
 using using = foo();
 // ケース2
 using = 5;
 
 // ケース3
 using
 x = resource;
 }
 【ケース3】
 using だけを読んでも、何も確定できない。 
 using の後に改行が来た場合は using はただの変数参照になる。 
 
 using が予約語であれば、using がシンボルに使われることはない ので、using が現れた時点で (Await)UsingDeclaration であることを 前提に処理できた。

  18. using が予約語でないことによる難しさ
 問い: 単に using を予約語にしたらいいやん
 
 回答: 例えば const

    using = 5; というコードがあったとして、
 Chrome の特定のバージョンまでは動くけど、特定のバージョン以降ではエラーになり ます! だと困る。
 既に存在する JavaScript を壊さないようにするために、後方互換性を維持しながら新 機能を追加していく必要がある。

  19. Acorn にバックトラックがないことによる難しさ
 • パーサーの種類 (一部)
 ◦ LLパーサー (Acornはこれがベース) 
 ▪

    実装はシンプルだが曖昧な構文に弱い 
 ◦ LRパーサー (V8 はこれ (らしい)) 
 ▪ 実装は複雑だが曖昧な構文に強い 
 
 • LLパーサーには、バックトラッキングを備える場合がある 
 ◦ 例えば await が来たら一旦 await foo() のような文法が来ると過程して読み進めて、違っ ていたら、戻ってきて、次は await using foo = bar() のような文法であると過程して読んで みる。

  20. Acorn にバックトラックがないことによる難しさ
 • LLパーサーとは (非常に簡単に説明すると)
 await bar(); / await using

    foo = bar();
 
 
 • LRパーサーとは (非常に簡単に説明すると)
 await bar(); / await using foo = bar();
 
 await を見つけたら、文字列を右に読み進めて (lookaheadして)
 どの文法規則を適用できるかを判定する。
 適用できる文法規則が1つに定まるまで読み進めて、文法規則が確定した時点で、 その範囲の文法規則を確定する。

  21. Acorn にバックトラックがないことによる難しさ
 例: await というキーワードが来た場合に、それが await using であるかを判定するプログラム (の一部) 


    
 直後が “using” でなければ違う 
 出典: https://github.com/acornjs/acorn/commit/b4ae0d29384f2bf3fafac7d42f1c3e2ee9a48204#diff-781c700ea716836ca6843f093b6a7d4 86849dec5b3c1ab428c6ce286592913dfR86-R91
  22. Acorn にバックトラックがないことによる難しさ
 例: await というキーワードが来た場合に、それが await using であるかを判定するプログラム (の一部) 


    
 “await” でファイルが終わっていたら違う 
 出典: https://github.com/acornjs/acorn/commit/b4ae0d29384f2bf3fafac7d42f1c3e2ee9a48204#diff-781c700ea716836ca6843f093b6a7d4 86849dec5b3c1ab428c6ce286592913dfR86-R91
  23. Acorn にバックトラックがないことによる難しさ
 例: await というキーワードが来た場合に、それが await using であるかを判定するプログラム (の一部) 


    
 “await” の次の文字が 識別子 の場合は違う 
 (サロゲートペアの上位領域であるかも確認しないと いけない
 出典: https://github.com/acornjs/acorn/commit/b4ae0d29384f2bf3fafac7d42f1c3e2ee9a48204#diff-781c700ea716836ca6843f093b6a7d4 86849dec5b3c1ab428c6ce286592913dfR86-R91
  24. 振り返り
 • パーサーの種類
 ◦ LLパーサー (Acornはこれがベース) 
 ▪ 実装はシンプルだが曖昧な構文に弱い 


    ◦ LRパーサー (V8 はこれ (らしい)) 
 ▪ 実装は複雑だが曖昧な構文に強い 
 
 • Acorn は性能を良くするためにバックトラックを使用しない 

  25. 振り返り
 A tiny, fast JavaScript parser, written completely in JavaScript.

    
 (完全に JavaScript で書かれた、小型で高速な JavaScript パーサーです) 
 (出典: https://github.com/Acornjs/Acorn) 
 言い換えると 完全に JavaScript で書かれた、 LL方式でバックトラックを使用しない JavaScript パーサー です

  26. 想定質問と回答
 Q. using って何を解決するんですか? finally で書けばよくないんですか? 
 A. finally で手動で解放処理を書くのは忘れやすく冗長です。using

    を使うとスコープ終了時に自動で解放されるため、コードが簡潔で安全になります。 
 
 Q. 非同期の using はどうやって書くんですか? 
 A. await using と書きます。例えば非同期でリソースを開放するオブジェクトを扱う場合に使えます。 
 
 Q. using と await using の違いは何ですか? 
 A. using は同期的に解放、await using は非同期処理を待ってから解放します。 
 
 Q. TypeScript でも使えますか? 
 A. TypeScript 5.2 から使用可能です。