抽象的な文法の木のJavaScriptの中の応用
11727 ワード
抽象文法の木は何ですか?
コンピュータ科学では、抽象的な文法ツリー(abstract sysntax treeまたはASTと略される)または文法ツリー(syntax tree)は、ソースコードの抽象的な文法構造のツリー表現形式であり、ここではプログラミング言語のソースコードを指す.ツリー上の各ノードはソースコードの構造を表している.文法が「抽象的」というのは、ここの文法は実際の文法に出てくる細部を表していないからです.1
やはり抽象的なほうがいいです.いくつかの例を見てみましょう.
抽象文法ツリーの例
抽象的な文法の木はコンピュータ科学に多くの応用があります.たとえば、コンパイラ、IDE、圧縮最適化コードなどです.抽象的な文法の木のJavaScriptでの応用を紹介します.
JavaScript抽象文法ツリー
JavaScriptを構成する抽象的な文法ツリーには、v 8、Spider Monkey、UglifyJSなどのツールがあります.ここではUglifyJSを紹介します.
UglifyJS
UglifyJSは最も広く使われているJavaScript圧縮ツールの一つで、しかも自身もJavaScriptで書いています.その方法を使うのは簡単です.
まずグローバルインストール:
UglifyJS Tools
UglifyJSはJavaScriptコードを分析するためのツールを提供しています.パーパーパー、JavaScriptコードを抽象文法ツリー に解析します. code generatorは、抽象文法ツリーからコード を生成する. magler、JavaScriptコードを混同する scope anlyzer、変数定義を解析するツール tree walkerは、ツリーノード を巡回します. tree transformer、ツリーノード を変更します.
抽象文法ツリーを生成
UglifyJSを使って抽象的な文法ツリーを生成するのは簡単です.
まずUglifyJSをインストールします.npmパッケージです.
maglerを使ってコードを圧縮します.
maglerを使用すると、ローカル変数を一つの文字に短縮することでコードを圧縮することができます.
ウォーカーを使って抽象的な文法の木を遍歴することができます.この遍歴は深いです.
抽象文法ツリーの応用
抽象的な文法の木を利用してJavaScriptコードを再構築します.
JavaScriptを再構築する需要があれば、役に立ちます.
次はこのような需要を考慮します.
以下はシナリオがあることを望んで、すべての
UglifyJSを使ってこの機能を実現できます.
このような簡単な状況は正則で合わせても便利に変えられます.なぜ抽象的な文法の木を使うのですか?
答えは、抽象的な文法ツリーは、文法を分析することによって実現され、いくつかの正則ではできない(または難しい)利点があります.たとえば、パーrseInt()は全体が文字列であり、または注釈では、このような状況は正則によって誤って判定されます.
チームのフロントエンドでは、YUIをフロントエンドの下のフレームワークとして使用していますが、これまで直面していた実際の問題は、モジュール間の依存関係がミスしやすいことです.たとえば:
ここで
したがって、正確な依存関係は以下の通りであるべきである.コード中のモジュール定義( を見つけました.は、各モジュール内の関数定義、変数定義、割当語句などを分析し、要求( を探し出す.「インターフェース・モジュール」対応関係を生成する .は、各モジュール内の関数呼び出し、変数の使用などを分析し、要求に合致する入力インターフェース( を探し出す.「インターフェース・モジュール」の対応関係を通じて、このモジュールはどの他のモジュール に依存すべきかを見つける.、requiresにエラーがあるかどうかを分析する .
このツールを使って、コードを提出するたびに依存関係が正しいことを保証します.モジュール依存関係の検出の自動化を実現しました.
締め括りをつける
抽象的な文法の木はコンピュータの領域の中で応用が広くて、以上は抽象的な文法の木のJavaScriptの中のいくつかの応用だけを討論しました.
Reference Wikipedia AST UglifyJS node-event-simulte Y.Aray.each 文章に誤りがあり、内容に疑問があることを発見したら、技術チームのWeChat公式アカウントに注目し、バックグラウンドで私達にメッセージを送ることができます.私達は週に1人の熱心な子供を選んで、1部の精巧で美しい贈り物を送ります.早く掃除に来てください.私たちに注目してください.
コンピュータ科学では、抽象的な文法ツリー(abstract sysntax treeまたはASTと略される)または文法ツリー(syntax tree)は、ソースコードの抽象的な文法構造のツリー表現形式であり、ここではプログラミング言語のソースコードを指す.ツリー上の各ノードはソースコードの構造を表している.文法が「抽象的」というのは、ここの文法は実際の文法に出てくる細部を表していないからです.1
やはり抽象的なほうがいいです.いくつかの例を見てみましょう.
抽象文法ツリーの例
foo = 'hello world';
/*
+-------------+
| assign(=) |
+-------------+
X X
X X
+-------+ +-----------------+
| foo | | 'hello world' |
+-------+ +-----------------+
*/
if (foo === true) {
bar = 'hello world';
alert(bar);
}
/*
+------+
| if |
+------+
X X
X X
+--------------+ +-------------+
| equal(===) | | if_body |
+--------------+ +-------------+
X X X X
X X X X
+-------+ +--------+ +-------------+ +------------+
| foo | | true | | assign(=) | | alert() |
+-------+ +--------+ +-------------+ +------------+
X X X
X X X
+-------+ +-----------------+ +-------+
| bar | | 'hello world' | | bar |
+-------+ +-----------------+ +-------+
*/
上記の2つの例から、抽象的な構文ツリーはソースコードをその構文構造に従って、いくつかの詳細(例えば、括弧がノードを生成していない)を省略し、ツリー表現に抽象化することが分かる.抽象的な文法の木はコンピュータ科学に多くの応用があります.たとえば、コンパイラ、IDE、圧縮最適化コードなどです.抽象的な文法の木のJavaScriptでの応用を紹介します.
JavaScript抽象文法ツリー
JavaScriptを構成する抽象的な文法ツリーには、v 8、Spider Monkey、UglifyJSなどのツールがあります.ここではUglifyJSを紹介します.
UglifyJS
UglifyJSは最も広く使われているJavaScript圧縮ツールの一つで、しかも自身もJavaScriptで書いています.その方法を使うのは簡単です.
まずグローバルインストール:
[sudo ]npm install -g uglify-js
そして使用できます.uglifyjs -m srcFileName.js -o destFileName.min.js
UglifyJSの使い方についてはここであまり紹介しません.もっと面白いことをしたいです.UglifyJS Tools
UglifyJSはJavaScriptコードを分析するためのツールを提供しています.
抽象文法ツリーを生成
UglifyJSを使って抽象的な文法ツリーを生成するのは簡単です.
まずUglifyJSをインストールします.npmパッケージです.
npm install uglify-js --save-dev
その後パース方法を使えばいいです.var UglifyJS = require('uglify-js');
var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');
このように生成されたastは、そのセグメントコードの抽象的な文法ツリーである.じゃ私達はどう使いますか?maglerを使ってコードを圧縮します.
maglerを使用すると、ローカル変数を一つの文字に短縮することでコードを圧縮することができます.
var UglifyJS = require('uglify-js');
var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');
ast.figure_out_scope();
ast.mangle_names();
console.log(ast.print_to_string());
// function sum(a,b){return a+b}
ウォーカーを使って抽象的な文法の木を遍歴します.ウォーカーを使って抽象的な文法の木を遍歴することができます.この遍歴は深いです.
var UglifyJS = require('uglify-js');
var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');
ast.figure_out_scope();
ast.walk(new UglifyJS.TreeWalker(function(node) {
console.log(node.print_to_string());
}));
/*
function sum(foo,bar){return foo+bar}
function sum(foo,bar){return foo+bar}
sum
foo
bar
return foo+bar
foo+bar
foo
bar
*/
UglifyJSはコードを直接圧縮するスクリプトを提供しました.walkerは見たところ役に立たないようですが、これらのツールはどのような使用場面がありますか?抽象文法ツリーの応用
抽象的な文法の木を利用してJavaScriptコードを再構築します.
JavaScriptを再構築する需要があれば、役に立ちます.
次はこのような需要を考慮します.
parseInt
は文字列を整数にするために使用されることを知っていますが、第二のパラメータがあります.文字列を何進で識別するかを表しています.parseInt('10.23'); // 10
parseInt('10abc'); // 10
parseInt('10', 10); // 10
parseInt('10', 2); // 2
parseInt('0123'); // 83 or 123 ,
parseInt('0x11'); // 17
私たちが予想していたのとは異なる場合がありますので、いつでも第二のパラメータを加えることをおすすめします.以下はシナリオがあることを望んで、すべての
parseInt
が第2のパラメーターがあるかどうかを調べて、ないなら第2のパラメーター10を加えて、10進数で文字列を識別することを表します.UglifyJSを使ってこの機能を実現できます.
#! /usr/bin/env node
var U2 = require("uglify-js");
function replace_parseint(code) {
var ast = U2.parse(code);
// accumulate `parseInt()` nodes in this array
var parseint_nodes = [];
ast.walk(new U2.TreeWalker(function(node){
if (node instanceof U2.AST_Call
&& node.expression.print_to_string() === 'parseInt'
&& node.args.length === 1) {
parseint_nodes.push(node);
}
}));
// now go through the nodes backwards and replace code
for (var i = parseint_nodes.length; --i >= 0;) {
var node = parseint_nodes[i];
var start_pos = node.start.pos;
var end_pos = node.end.endpos;
node.args.push(new U2.AST_Number({
value: 10
}));
var replacement = node.print_to_string({ beautify: true });
code = splice_string(code, start_pos, end_pos, replacement);
}
return code;
}
function splice_string(str, begin, end, replacement) {
return str.substr(0, begin) + replacement + str.substr(end);
}
// test it
function test() {
if (foo) {
parseInt('12342');
}
parseInt('0012', 3);
}
console.log(replace_parseint(test.toString()));
/*
function test() {
if (foo) {
parseInt("12342", 10);
}
parseInt('0012', 3);
}
*/
ここで、ウォーカーを使ってparseInt
が呼び出したところを見つけ、第二のパラメータがあるかどうかを確認し、なければ記録し、その後、各記録に基づいて、新しい第二のパラメータを含む内容で元の内容を入れ替えて、コードの再構成を完了する.このような簡単な状況は正則で合わせても便利に変えられます.なぜ抽象的な文法の木を使うのですか?
答えは、抽象的な文法ツリーは、文法を分析することによって実現され、いくつかの正則ではできない(または難しい)利点があります.たとえば、パーrseInt()は全体が文字列であり、または注釈では、このような状況は正則によって誤って判定されます.
var foo = 'parseInt("12345")';
// parseInt("12345");
抽象的な文法の木はアメリカ団の中の応用です.チームのフロントエンドでは、YUIをフロントエンドの下のフレームワークとして使用していますが、これまで直面していた実際の問題は、モジュール間の依存関係がミスしやすいことです.たとえば:
YUI.add('mod1', function(Y) {
Y.one('#button1').simulate('click');
Y.Array.each(array, fn);
Y.mod1 = function() {/**/};
}, '', {
requires: [
'node',
'array-extras'
]
});
YUI.add('mod2', function(Y) {
Y.mod1();
// Y.io(uri, config);
}, '', {
requires: [
'mod1',
'io'
]
});
以上のコードは2つのモジュールを定義しており、mod1
はid
の要素をクリックしてbutton1
を実行した後、方法Y.Array.each
を定義し、最後に依存性Y.mod1
とnode
を宣言した.array-extras
はmod2
で定義された方法を実行し、mod1
は注釈され、最後に依存性Y.io
およびmod1
を宣言した.ここで
io
は、2つのよくあるエラーが発生しています.1つはmod1
上の方法で、文依存性を忘れがちです.もう1つはsimulate
上の方法の一部のみがY.Node.prototype
に依存する必要があるので、ここで多くの文が示されました.node-event-simulate
に注釈を追加すると、元の書き込みの依存性を削除することを忘れがちである.したがって、正確な依存関係は以下の通りであるべきである.
YUI.add('mod1', function(Y) {
Y.one('#button1').simulate('click');
Y.Array.each(array, fn);
Y.mod1 = function() {/**/};
}, '', {
requires: [
'node',
'node-event-simulate'
]
});
YUI.add('mod2', function(Y) {
Y.mod1();
// Y.io(uri, config);
}, '', {
requires: [
'mod1'
]
});
モジュール依存性の検出を自動化するために、モジュール依存関係の検出ツールを作成しました.抽象的な文法ツリーを利用して、どのインターフェースを定義し、どのインターフェースを使用しているかを分析しました.そして、これらのインターフェースがどのモジュールに依存すべきかを調べて、モジュール依存関係のエラーを見つけました.大体のプロセスは以下の通りです.Y.Array
)の部分array-extras
で始まる)に合致する出力インターフェース(array-extras
のmod2
)io
、YUI.add
、Y
、mod1
)このツールを使って、コードを提出するたびに依存関係が正しいことを保証します.モジュール依存関係の検出の自動化を実現しました.
締め括りをつける
抽象的な文法の木はコンピュータの領域の中で応用が広くて、以上は抽象的な文法の木のJavaScriptの中のいくつかの応用だけを討論しました.
Reference