AST抽象文法ツリー
原文を読む
AST抽象文法ツリーの紹介
AST(Abstract Syntax Tree)はソースコードの抽象的な文法構造ツリー表現形式であり、Webpack、ESLint、JSX、Type Scriptのコンパイルとモジュール化ルールの転換はASTによってコードの検査、分析、コンパイルなどの操作を実現します.
JavaScript文法のAST文法ツリー
JavaScriptではASTを使って開発したいですが、抽象成語法樹のその後の構造は何ですか?中のフィールド名はどんな意味と遍歴のルールを表していますか?http://esprima.org/demo/parse... JavaScript文法のオンライン変換を実現します.
オンラインコンパイルツールにより、
esprim、estraverseとescodegen
1、サプライズはJSをASTに変換します.
esprimモジュールの使い方は以下の通りです.
2、estraverse遍歴とAST修正
巡回中を表示:
実際には、ASTを巡回するということは、各レイヤの
3、escodegenはASTをJSに変換する
次の例は、JSコードブロックがASTに変換され、遍歴、修正されたASTをJSに再変換する全プロセスである.
Babel文法変換プラグインを実現します.
構文変換プラグインを実装するには、
この二つのモジュールを使うには、下記のようにインストールが必要です.
npm install babel-core babel-types
1、plugin-tranform-arrow-functions
内部修正は、
2、plugin-tranform-clases
締め括りをつける
このセクションを通じて、AST抽象的な文法ツリー、抽象的な文法ツリーとJavaScriptの中の表現、およびNodeJSの中でAST抽象的な文法ツリーの生成、遍歴および修正のためのコア依存性を理解し、
AST抽象文法ツリーの紹介
AST(Abstract Syntax Tree)はソースコードの抽象的な文法構造ツリー表現形式であり、Webpack、ESLint、JSX、Type Scriptのコンパイルとモジュール化ルールの転換はASTによってコードの検査、分析、コンパイルなどの操作を実現します.
JavaScript文法のAST文法ツリー
JavaScriptではASTを使って開発したいですが、抽象成語法樹のその後の構造は何ですか?中のフィールド名はどんな意味と遍歴のルールを表していますか?http://esprima.org/demo/parse... JavaScript文法のオンライン変換を実現します.
オンラインコンパイルツールにより、
function fn(a, b) {}
を以下の構成にコンパイルすることができます.{
"type": "Program",
"body": [
{
"type": "FunctionDeclaration",
"id": {
"type": "Identifier",
"name": "fn"
},
"params": [
{
"type": "Identifier",
"name": "a"
},
{
"type": "Identifier",
"name": "b"
}
],
"body": {
"type": "BlockStatement",
"body": []
},
"generator": false,
"expression": false,
"async": false
}
],
"sourceType": "script"
}
JavaScript文法を抽象的な文法ツリーにコンパイルした後、それを遍歴し、修繕し、再コンパイルする必要があります.木の構造を遍歴する過程は「先序深さ優先」です.esprim、estraverseとescodegen
esprima
、estraverse
、escodegen
モジュールは、ASTを動作させる3つの重要なモジュールであり、babel
のコア依存性を実現するものであり、以下に三つのモジュールの役割を説明する.1、サプライズはJSをASTに変換します.
esprimモジュールの使い方は以下の通りです.
// :esprima-test.js
const esprima = require("esprima");
let code = "function fn() {}";
//
let tree = esprima.parseScript(code);
console.log(tree);
// Script {
// type: 'Program',
// body:
// [ FunctionDeclaration {
// type: 'FunctionDeclaration',
// id: [Identifier],
// params: [],
// body: [BlockStatement],
// generator: false,
// expression: false,
// async: false } ],
// sourceType: 'script' }
上記の例から分かるように、JSコードブロックはesprima
モジュールのparseScript
方法で成語ツリーに変換され、コードブロックは文字列に変換される必要があり、parseModule
方法でモジュールを変換することもできる.2、estraverse遍歴とAST修正
巡回中を表示:
// :estraverse-test.js
const esprima = require("esprima");
const estraverse = require("estraverse");
let code = "function fn() {}";
//
estraverse.traverse(esprima.parseScript(code), {
enter(node) {
console.log("enter", node.type);
},
leave() {
console.log("leave", node.type);
}
});
// enter Program
// enter FunctionDeclaration
// enter Identifier
// leave Identifier
// enter BlockStatement
// leave BlockStatement
// leave FunctionDeclaration
// leave Program
上記のコードはestraverse
モジュールのtraverse
方法によってesprima
モジュールに変換されたASTを巡回し、type
属性のすべてを印刷し、type
属性を含むオブジェクトをノードと呼び、対応するタイプを取得し、その時点の属性を変更すれば良い.実際には、ASTを巡回するということは、各レイヤの
type
属性を遍歴することで、2つの段階に分けられ、段階に入ると段階を離れることになり、estraverse
のtraverse
の方法でそれぞれパラメータで指定されたentry
とleave
の2つの関数で傍受されるが、私たちは一般的にはentry
を使用するだけである.3、escodegenはASTをJSに変換する
次の例は、JSコードブロックがASTに変換され、遍歴、修正されたASTをJSに再変換する全プロセスである.
// :escodegen-test.js
const esprima = require("esprima");
const estraverse = require("estraverse");
const escodegen = require("escodegen");
let code = "function fn() {}";
//
let tree = esprima.parseScript(code);
//
estraverse.traverse(tree, {
enter(node) {
//
if (node.type === "FunctionDeclaration") {
node.id.name = "ast";
}
}
});
//
let result = escodegen.generate(tree);
console.log(result);
// function ast() {
// }
ASTを巡回する過程でparams
値は配列であり、type
属性はない.Babel文法変換プラグインを実現します.
構文変換プラグインを実装するには、
babel-core
およびbabel-types
の2つのモジュールを借りる必要がありますが、実は、これらの2つのモジュールは、esprima
、estraverse
、escodegen
142に依存しています.この二つのモジュールを使うには、下記のようにインストールが必要です.
npm install babel-core babel-types
1、plugin-tranform-arrow-functions
plugin-transform-arrow-functions
は、矢印関数をES 5文法に変換するためのBabel家族の一員である.// :plugin-transform-arrow-functions.js
const babel = require("babel-core");
const types = require("babel-types");
//
let sumCode = `
const sum = (a, b) => {
return a + b;
}`;
let minusCode = `const minus = (a, b) => a - b;`;
// ES5
let ArrowPlugin = {
// ( )
visitor: {
// path
ArrowFunctionExpression(path) {
//
let node = path.node;
//
let params = node.params;
let body = node.body;
// , return {}
if (!types.isBlockStatement(body)) {
let returnStatement = types.returnStatement(body);
body = types.blockStatement([returnStatement]);
}
//
let func = types.functionExpression(null, params, body, false, false);
//
types.replaceWith(func);
}
}
};
//
let sumResult = babel.transform(sumCode, {
plugins: [ArrowPlugin]
});
let minusResult = babel.transform(minusCode, {
plugins: [ArrowPlugin]
});
console.log(sumResult.code);
console.log(minusResult.code);
// let sum = function (a, b) {
// return a + b;
// };
// let minus = function (a, b) {
// return a - b;
// };
私たちは主にbabel-core
のtransform
方法を用いてASTをコードブロックに変換し、最初のパラメータは変換前のコードブロック(文字列)であり、第二のパラメータは構成項目であり、plugins
値は配列であり、babal-core
変換されたASTを修正するプラグイン(オブジェクト)を記憶し、transform
方法を用いて古いASTを新しいコードブロックに処理した後、戻り値はオブジェクトで、オブジェクトのcode
属性は変換されたコードブロック(文字列)です.内部修正は、
babel-types
モジュールによって提供される方法によって実現され、APIは、APIに到達することができる.https://github.com/babel/babe... に表示されますArrowPlugin
は、transform
方法に導入されたプラグインであり、visitor
属性(固定)を含んでいなければならない.値は同じオブジェクトであり、構文ツリーを修正する方法を記憶するために使用され、方法名は、APIに厳格に従い、対応する方法は、AST対応するノードを修正する.types.functionExpression
方法では、パラメータはそれぞれ表しています.関数名(匿名関数null
)、関数パラメータ(必須)、関数体(必須)、generator
関数(デフォルトfalse
)かどうか、async
関数(デフォルトfalse
)かどうか、戻り値は修正されたAST、types.replaceWith
方法はASTを置換するために使用されます.2、plugin-tranform-clases
plugin-transform-classes
はまた、Babel家族の一員であり、ES 6のclass
クラスをES 5に変換するためのコンストラクタでもある.// :plugin-transform-classes.js
const babel = require("babel-core");
const types = require("babel-types");
//
let code = `
class Person {
constructor(name) {
this.name = name;
}
getName () {
return this.name;
}
}`;
// ES5
let ClassPlugin = {
visitor: {
ClassDeclaration(path) {
let node = path.node;
let classList = node.body.body;
// { type: 'Identifier', name: 'Person' }
let className = types.identifier(node.id.name);
let body = types.blockStatement([]);
let func = types.functionDeclaration(className, [], body, false, false);
path.replaceWith(func);
//
let es5Func = [];
// class
classList.forEach((item, index) => {
//
let body = classList[index].body;
//
let params = item.params.length ? item.params.map(val => val.name) : [];
//
params = types.identifier(params);
// constructor,
if (item.kind === "constructor") {
//
func = types.functionDeclaration(className, [params], body, false, false);
} else {
//
let proto = types.memberExpression(className, types.identifier("prototype"));
// Person.prototype.getName
let left = types.memberExpression(proto, types.identifier(item.key.name));
//
let right = types.functionExpression(null, [params], body, false, false);
//
es5Func.push(types.assignmentExpression("=", left, right));
}
});
// ,
if (es5Func.length === 0) {
path.replaceWith(func);
} else {
es5Func.push(func);
// n
path.replaceWithMultiple(es5Func);
}
}
}
};
//
result = babel.transform(code, {
plugins: [ClassPlugin]
});
console.log(result.code);
// Person.prototype.getName = function () {
// return this.name;
// }
// function Person(name) {
// this.name = name;
// }
上記のプラグインの実装は、plugin-transform-arrow-functions
より複雑であり、結局は相互に変換されるES 6とES 5シンタックスツリーを比較して、彼らの違いを見つけ、babel-types
で提供されるAPIを使用して、シンタックスツリーに対応するノード属性を修正して、シンタックスツリーを置換します.配列は、複数の構文ツリー構造をサポートしており、構文ツリーを具体的に変更するシーンに応じて選択して使用することができ、場合によっては異なる代替方法を使用することもできる.締め括りをつける
このセクションを通じて、AST抽象的な文法ツリー、抽象的な文法ツリーとJavaScriptの中の表現、およびNodeJSの中でAST抽象的な文法ツリーの生成、遍歴および修正のためのコア依存性を理解し、
path.replaceWithMultiple
とpath.replaceWith
の2つのモジュールを使って、ES 6の新しい特殊性をES 5文法に変換するプロセスを簡易的に模擬しました.後で自分でいくつかのコンパイルのプラグインを実現するために構想を提供することができることを望みます.