JavaScriptがもっと好きになる。JavaScriptを知るために

JSがもっと好きになる。JSを知るために

自己紹介

「JavaScriptとは何か」

みたいな話はしません

「JavaScriptの歴史」

みたいな話でもないです

「JavaScriptを知るために」

知るためには?

「作ってみる」

のは大変なので

「解析してみる」

というわけで

「静的解析しましょうか」

「静的解析しましょうか」

(オチがわかっても何も言わないのが良い観衆)

「静的解析」とは

コードを文字列として分割し、どういった内容が書かれているか解釈すること

コードを文字列として分割し、どういった内容が書かれているか解釈すること

/*
 block comment
*/
(function () {
	//line comment
	console.log(/regexp/);
	return 'string';
})()

ただ、ちゃんとした解析は大変なので今回はコードとそれ以外のものに分割してみます

ここからはコードの話になります

その1
「エスケープのエンコード」

まず解析を簡単にするために\エスケープを%エンコード(%nn)します

ただ、単純に変換すると後で戻せないのでまずは%を%%へ変換します

code = code.replace(/%/g, '%%');

次に\エスケープを%エンコードします
(encodeAllは全文字列を%エンコードするfunctionと思ってください)

code = code.eplace(/\\./g, encodeAll);

これで\エスケープされた文字列がなくなったので"等の対応がとれた状態になりました

(function () {
	var a = 1 % 1;
	return "\"" + a + "\n";
})()

これで\エスケープされた文字列がなくなったので"等の対応がとれた状態になりました

(function () {
	var a = 1 %% 1;
	return "%22" + a + "%6e";
})()

その2
「リテラルの切り出し」

ここまでで"の対応はつくようになっていますが、更にコメントや正規表現内の記号もすべて変換することでコードと分離しやすくします

正規表現で一気に

code.replace(/(['"])([\s\S]*?)\1|\/\*([\s\S]*)\*\/|\/\/(.*?)$|\/(.+?)\//g, encodeAll);

正規表現で一気に

code.replace(/(['"])([\s\S]*?)\1|\/\*([\s\S]*)\*\/|\/\/(.*?)$|\/(.+?)\//g, encodeAll);
/*
 function () {}
*/
(function () {
	// return /hoge/
	console.log(/[regexp]]/);
	return ';';
})()

正規表現で一気に

code.replace(/(['"])([\s\S]*?)\1|\/\*([\s\S]*)\*\/|\/\/(.*?)$|\/(.+?)\//g, encodeAll);
/*
%20%66%75%6e%63%74%69%6f%6e%20%28%29%20%7b%7d
*/
(function () {
	//%20%72%65%74%75%72%6e%20%2f%68%6f%67%65%2f
	console.log(/%5b%72%65%67%65%78%70%5d/);
	return ';';
})()

正規表現解説

(['"])[\s\S]*?\1 // string
|
\/\*[\s\S]*\*\/ // block comment
|
\/\/.*?$        // line comment
|
\/.+?\/         // regexp

入れ子判定が難しくなるので、解析は一回で行います
(「/* "" */」や「"/*" + "*/"」も解析できるように)

これで文字列、コメント、正規表現内の記号が%エスケープできました

/*
%20%66%75%6e%63%74%69%6f%6e%20%28%29%20%7b%7d
*/
(function () {
	//%20%72%65%74%75%72%6e%20%2f%68%6f%67%65%2f
	console.log(/%5b%72%65%67%65%78%70%5d/);
	return ';';
})()

文字列、コメント、正規表現内の記号が%エスケープできればもう記号はコード内にしか無いので解析は容易になります
(functionを取得したい場合、'function'を全体から探せばいい)

コードの話はここまで

「なんに使うのか」

使い道

「ちなみに」

ここで紹介したコードは自分が2009年に作成したTest.Sweetsというdoc test用フレームワークをベースにしています

Test.Sweets – CodeRepos::Share – Trac

このスライドを書いてる途中でmozillaが作ってるsweet.jsのドキュメントで正規表現と/演算子の見分け方を見つけました

design · mozilla/sweet.js Wiki

。。。名前?

注意

ここで紹介したコードは以下の様なコードの解釈に失敗します

オチ

Esprimaはこのへんの問題なく解析してくれるので、まともに静的解析をしたい場合はEsprimaを使用しましょう

ご清聴ありがとうございました