はじめに
「RubyでつくるRuby ゼロから学びなおすプログラミング言語入門」(ラムダノート, Amazon) という本を読んで、簡易的なプログラミング言語を作りたい熱が出てきました。そんなおりに PythonでつくるPythonという記事を読み、自分でもNode.jsでミニNode.js作りにチャンレンジするとにしました。
どこまで続くかわかりませんが、最後はブートストラップまで行くことを目指して始めます。
Step 1 - ソースコードのパース
「RubyでつくるRuby」の実装は2つの部分に分かれています。
- ソースコードを解析するところ (parse)
- ソースコードを実行するところ (evaluate)
parseの部分はあらかじめ作者が用意している minruby.rb が担当してくれていて、読者は実行のevaluateだけ作る構成になっています。
PythonでつくるPythonでもparseはastモジュールで行なっていました。
Node.jsでもAST(抽象構文木)という名前は耳にします。調べて見ると、次の2つの系列があるようです。(JavaScript ASTを始める最初の一歩より)
- Esprima
- Acorn
特にこだわりもないので、Esprimaを使ってみます。
$ npm install esprima
初めての AST
こんなコードを書いて、パースした結果のASTがどうなっているか見ました。
const esprima = require("esprima");
function parseSrc(src) {
const ast = esprima.parseScript(src);
return ast;
}
function printObj(obj) {
console.dir(obj, {depth: 10});
}
// --------
const ast1 = parseSrc('1');
printObj(ast1);
'1' をパースした結果がこちらです。
Script {
type: 'Program',
body:
[ ExpressionStatement {
type: 'ExpressionStatement',
expression: Literal { type: 'Literal', value: 1, raw: '1' } } ],
sourceType: 'script' }
何やらそれっぽいです。
もう一丁、'2+3' をパースした結果もやってみます。
Script {
type: 'Program',
body:
[ ExpressionStatement {
type: 'ExpressionStatement',
expression:
BinaryExpression {
type: 'BinaryExpression',
operator: '+',
left: Literal { type: 'Literal', value: 2, raw: '2' },
right: Literal { type: 'Literal', value: 3, raw: '3' } } } ],
sourceType: 'script' }
想像していたより複雑になってますが、ソースの構造が反映されているようです。今後これを出発点に進めていきます。
ASTが使われているところ
AST初心者なので、実際どんなところで使われているのか調べてみました。
- ESLint ... 静的検証ツール
- ASTはespreeというモジュールで生成 https://eslint.org/docs/developer-guide/architecture#the-eslint-object
- power-assert ... JavaScriptのテスト用フレームワーク
- t_wadaさんの東京Node学園祭2014での講演資料 power-assert, mechanism and philosophy
- AltJS の変換 ... babel などのツール
- babel ... Babel Plugin Handbook
ASTを使いこなせば、自分でAltJSを作るのも不可能ではなさそうです。