タイトルから何を言ってるのか意味わからない気がするので順を追って解説。

スライド版: ECMAScript 6 Draft Hisotry Repo

2015-05-07現在、ES6の仕様はApril 14, 2015 Rev 38 Final Draftが公開されています。 Rev38とわかるようにドラフトは38回ぐらい更新されていて、ちょっとづつ追記されたり変更されたりして結構な変更履歴があります。

これだけ長い間(4年ぐらい?)やってるとある時点では正しかったかもしれないけど、最終版では違うものになってるという挙動があったりします。

例えば、class構文で以下のようにして定義したmethod()が列挙可能な仕様になっていたのが、Rev 32で列挙されないように修正されました。

class Yamada{
    method(){}
} 

こういった変更履歴はharmony:specification_drafts [ES Wiki]にも一応かいてあるのですが、サマリー的な感じなのでもうちょっと具体的なRev同士の差分から追う方法が欲しくなりました。

また最近ずっとECMAScript仕様書を読んでいたりするので、この仕様はなんでこうなっているのだろうというのが変更履歴から分かったりするのでは?と思ったのでそれを補助するものを作ろうとしました。


Revごとの差分管理

harmony:specification_drafts [ES Wiki]に全てのRevのファイル(doc or pdf)が公開されています。

差分管理といえばGit!ということで、以下の様な考えでドラフトのRevをそれぞれ一つのコミットして突っ込んだリポジトリを作成することで、Gitで管理できるES6ドラフトのリポジトリを作ることにしました。

  1. ドラフトを全部ダウンロード
  2. ドラフトをテキストに変換する
  3. GitにRevごとにコミットとして突っ込む
  4. git log -S -i "search"とかで検索できる!
  5. 該当するRevと関連ありそうなrwaldron/tc39-notesを表示

これに関連して色々なツールを書いているのですが、それらはMeta ECMAScriptにまとめてあります。

ドラフトのメタデータ

まずはドラフトのダウンロードですが、まずドラフトのURLとそれが"Rev何"なのかの情報が必要です。

ES Wikiにかいてあるので、それらを取り出してjsonとかにして使えるメタデータをのリポジトリを作りました。

GitHubだとtsvcsvはそのままインクリメンタルサーチできるのでes6-spec-changelog.tsvとかも置いてあります。

ドラフトのダウンロード

上記のメタリポジトリからJSONでドラフト一覧のURLが取れるようになったので、

  • rev1.doc
  • rev2.doc

という感じでダウンロードするコマンドラインツールを書きました。

doc to txt?

docファイルをテキストファイルにしたいのですが、docファイルはそのままだと上手く扱えないので、

doc -> docx -> txt

という手順を取ることにしました。

詳細は以下に書いてありますが、完全には自動化しきれてない微妙な感じです。

更に細かく言うとdocx to txtも一度にするとpandocがスタックオーバーフロー的になるので、doc-to-txt.shでは

pandoc -f docx "${file}" -t native | pandoc -f native -t plain -o "txts/${outputFile}.txt"

のように一度"native"を経由すると問題なく(時間がかかる)変換できることがわかったのでバッドノウハウが色々あります。

txt to Git

後はrev1.txt...rev38.txtをそれぞれ順番に同じファイル名にしてコミットしていったリポジトリを作るnew-git-revision.shというの書いて、ドラフトの差分を持ったGitリポジトリを作って完成。

そして、最終的に完成したリポジトリが以下になります。

Diff検索用リポジトリ

meta-ecmascript/es6-draft-revisionはテキストファイルの変更履歴としてES6ドラフトの変更履歴が取れるので、後は通常のGit検索と同じテクニックを使ってドラフトの差分が検索できるようになると思います。

変更されたRevが特定できたら、関連するChangelogをみたりその前後でやってるTC39のミーティングを読めば何かわかるかもしれません。

git log -Sでコミットの差分に含まれてる内容を検索したりできます。

classのメソッドの例

先ほども例に上げた、classのmethod定義が列挙されなくなったRevを変更履歴から特定してみましょう。

まずは、最新のドラフトでどこでclass methodのenumerableが定義されてるかを探します。

class構文周りを探していくと

ClassDefinitionEvaluationはclassの中身を見て定義していくアルゴリズムで長いですが、21に以下のようなステップがあります。

21. For each ClassElement m in order from methods
    a. If IsStatic of m is false, then
        i. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments proto
and false. 
    b. Else,
        i. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments F and false.
    c. If status is an abrupt completion, then
        i. Set the running execution context’s LexicalEnvironment to lex.
        ii. Return Completion(status).

Let status be the result of performing PropertyDefinitionEvaluation for m with arguments proto and false.

この部分のPropertyDefinitionEvaluation(proto, false)という第二引数がenumurableかどうかを決めることが、14.3.9 Runtime Semantics: PropertyDefinitionEvaluationを合わせてみるとわかります。

With parameters object and enumerable.

話を戻して、途中でこのenumerableがtrueからfalseになったということなので、PropertyDefinitionEvaluationの変更というよりも、ClassDefinitionEvaluationのステップが変更された可能性が高そうです。

Let status be the result of performing PropertyDefinitionEvaluation for m with arguments F and false.

falseとなった変更がどっかであれば、その変更があるコミットが"classのmethod定義が列挙されなくなったRev"と言えそうです。

$ git clone https://github.com/meta-ecmascript/es6-draft-revision.git
$ cd es6-draft-revision
# コミットの差分からPropertyDefinitionEvaluationの呼び出しの変更を探す
$ git log -S "PropertyDefinitionEvaluation for m with arguments" | more
commit 62ecee4ed31859ba94359b08cadbf0264eb86c06
Author: azu <azuciao@gmail.com>
Date:   Mon May 4 14:20:12 2015 +0900

    rev32 

rev32にそういうコミットがあるようなので中身を見てみます。

$ git show rev32 | grep "PropertyDefinitionEvaluation for m with arguments" -C10
+25. Else, let methods be NonConstructorMethodDefinitions of
     ClassBody.

-25. For each ClassElement m in order from methods
+26. For each ClassElement m in order from methods

     a.  If IsStatic of m is FALSE, then

         i.  Let status be the result of performing
-            PropertyDefinitionEvaluation for m with argument proto.
+            PropertyDefinitionEvaluation for m with arguments proto
+            and FALSE.

     b.  Else,

         i.  ii. iii. Let status be the result of performing
-            PropertyDefinitionEvaluation for m with argument F.
--
+            and FALSE.

     b.  Else,

         i.  ii. iii. Let status be the result of performing
-            PropertyDefinitionEvaluation for m with argument F.
+            PropertyDefinitionEvaluation for m with arguments F and
+            FALSE.

     c.  If status is an abrupt completion, then

@@ -25329,16 +25333,16 @@ ClassTail : ClassHeritage~opt~ { ClassBody~opt~ }

         ii. Return status.

-26. Set the running execution context’s LexicalEnvironment to lex.
+27. Set the running execution context’s LexicalEnvironment to lex.

最初に答えが書いてありましたが、答えと同じくRev32で変更されていたことが発見できました。

疑問

ES6 moduleのtop levelにあるthisの値は何になるのか? | Web Scratchでも書いてたけど、git log -Gで改行無視して複数行に跨いだ検索が上手くいかない…(pcre拡張はいれてあるのに…) リポジトリのデータがおかしい可能性はある。。

git log --perl-regexp -i -G "GetThisBinding(.|\n)*?Return UNDEFINED"

Gitのdiff検索テクニックもっと知りたい…

まとめ

Meta ECMAScript

Meta ECMAScript はECMAScriptに関連するメタ的なツールを置いておくorganizationとして作ったので、なにか置きたい場合は言ってくれればInviteします。