preface
Babel is one of the most popular JavaScript compilers. It uses a JavaScript parser called Babel-Parser, originally fork from the Acorn project. Acorn was fast, easy to use, and designed a plug-in based architecture for non-standard features (and those that will be standard features in the future). This article mainly introduces the abstract syntax tree nodes generated by esprima parsing. Esprima implementation is also based on Acorn.
The original address
The Parser Parser
JavaScript Parser is a Parser that converts JS source code into abstract syntax trees (AST). This step is divided into two stages: Lexical Analysis and Syntactic Analysis.
Common JavaScript Parser:
-
esprima
-
uglifyJS2
-
traceur
-
acorn
-
espree
-
@babel/parser
Lexical analysis
The lexical analysis phase transforms the string code into a stream of tokens. You can think of a token as a flat array of syntax fragments.
n * n;
Copy the code
For example, the lexical analysis of n*n is as follows:
[{type: {... },value: "n".start: 0.end: 1.loc: {... }}, {type: {... },value: "*".start: 2.end: 3.loc: {... }}, {type: {... },value: "n".start: 4.end: 5.loc: {... }},]Copy the code
Each type has a set of attributes that describe the token:
{
type: {
label: 'name',
keyword: undefined,
beforeExpr: false,
startsExpr: true,
rightAssociative: false,
isLoop: false,
isAssign: false,
prefix: false,
postfix: false,
binop: null,
updateContext: null},... }Copy the code
Like AST nodes, they have start, end, and LOC attributes.
Syntax analysis
Parsing is transforming tokens into AST based on the results of lexical analysis.
function square(n) {
return n * n;
}
Copy the code
As in the code above, the generated AST structure looks like this:
{
type: "FunctionDeclaration".id: {
type: "Identifier".name: "square"
},
params: [{
type: "Identifier".name: "n"}].body: {
type: "BlockStatement".body: [{
type: "ReturnStatement".argument: {
type: "BinaryExpression".operator: "*".left: {
type: "Identifier".name: "n"
},
right: {
type: "Identifier".name: "n"}}}]}}Copy the code
The following sections explain the different types of AST nodes. More AST generated with the following entry:
-
eslint
-
AST Explorer
-
esprima
With visual tools, for example
The following code:
var a = 42;
var b = 5;
function addA(d) {
return a + d;
}
var c = addA(2) + b;
Copy the code
After the first step of lexical analysis, it will grow as shown in the figure below:
Syntax analysis, production of abstract syntax tree, generated abstract syntax tree as shown in the figure below
Base
Node
All node types implement the following interfaces:
interface Node {
type: string; range? : [number.number]; loc? : SourceLocation; }Copy the code
The Type field is a string representing the AST variant type. This LOC field represents the source location information of the node. This field is null if the parser does not generate information about the node’s source location; Otherwise it is an object with a start position (the position of the first character of the source region being parsed) and an end position.
interfaceSourceLocation { start: Position; end: Position; source? :string | null;
}
Copy the code
Each Position object consists of a line number (index 1) and a column number (index 0) :
interface Position {
line: uint32 >= 1;
column: uint32 >= 0;
}
Copy the code
Programs
interface Program <: Node {
type: "Program";
sourceType: 'script' | 'module';
body: StatementListItem[] | ModuleItem[];
}
Copy the code
Represents a complete source code tree.
Scripts and Modules
Source code number includes two sources, one is script script, the other is modules
When script, the body is StatementListItem. When modules, body is ModuleItem.
The types StatementListItem and ModuleItem are as follows.
type StatementListItem = Declaration | Statement;
type ModuleItem = ImportDeclaration | ExportDeclaration | StatementListItem;
Copy the code
ImportDeclaration
Import syntax, import modules
type ImportDeclaration {
type: 'ImportDeclaration';
specifiers: ImportSpecifier[];
source: Literal;
}
Copy the code
ImportSpecifier has the following types:
interface ImportSpecifier {
type: 'ImportSpecifier' | 'ImportDefaultSpecifier' | 'ImportNamespaceSpecifier'; local: Identifier; imported? : Identifier; }Copy the code
ImportSpecifier syntax is as follows:
import { foo } from './foo';
Copy the code
The syntax for ImportDefaultSpecifier is as follows:
import foo from './foo';
Copy the code
The syntax of ImportNamespaceSpecifier is as follows
import * as foo from './foo';
Copy the code
ExportDeclaration
Export type is as follows
type ExportDeclaration = ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration;
Copy the code
ExportAllDeclaration Exports from the specified module
interface ExportAllDeclaration {
type: 'ExportAllDeclaration';
source: Literal;
}
Copy the code
The syntax is as follows:
export * from './foo';
Copy the code
ExportDefaultDeclaration Exports the default module
interface ExportDefaultDeclaration {
type: 'ExportDefaultDeclaration';
declaration: Identifier | BindingPattern | ClassDeclaration | Expression | FunctionDeclaration;
}
Copy the code
The syntax is as follows:
export default 'foo';
Copy the code
ExportNamedDeclaration Exports some modules
interface ExportNamedDeclaration {
type: 'ExportNamedDeclaration';
declaration: ClassDeclaration | FunctionDeclaration | VariableDeclaration;
specifiers: ExportSpecifier[];
source: Literal;
}
Copy the code
The syntax is as follows:
export const foo = 'foo';
Copy the code
Declarations and Statements
The type of declaration is as follows:
type Declaration = VariableDeclaration | FunctionDeclaration | ClassDeclaration;
Copy the code
Statements are of the following types:
type Statement = BlockStatement | BreakStatement | ContinueStatement |
DebuggerStatement | DoWhileStatement | EmptyStatement |
ExpressionStatement | ForStatement | ForInStatement |
ForOfStatement | FunctionDeclaration | IfStatement |
LabeledStatement | ReturnStatement | SwitchStatement |
ThrowStatement | TryStatement | VariableDeclaration |
WhileStatement | WithStatement;
Copy the code
VariableDeclarator
Variable declarations. The kind attribute indicates what type of declaration it is, since ES6 introduced const/let.
interface VariableDeclaration <: Declaration {
type: "VariableDeclaration";
declarations: [ VariableDeclarator ];
kind: "var" | "let" | "const";
}
Copy the code
FunctionDeclaration
Function declarations (non-function expressions)
interface FunctionDeclaration {
type: 'FunctionDeclaration';
id: Identifier | null;
params: FunctionParameter[];
body: BlockStatement;
generator: boolean;
async: boolean;
expression: false;
}
Copy the code
Such as:
function foo() {}
function *bar() { yield "44"; }
async function noop() { await new Promise(function(resolve, reject) { resolve('55'); })}Copy the code
ClassDeclaration
Class declaration (non-class expression)
interface ClassDeclaration {
type: 'ClassDeclaration';
id: Identifier | null;
superClass: Identifier | null;
body: ClassBody;
}
Copy the code
The ClassBody declaration reads as follows:
interface ClassBody {
type: 'ClassBody';
body: MethodDefinition[];
}
Copy the code
MethodDefinition represents a method declaration;
interface MethodDefinition {
type: 'MethodDefinition';
key: Expression | null;
computed: boolean;
value: FunctionExpression | null;
kind: 'method' | 'constructor';
static: boolean;
}
Copy the code
class foo {
constructor() {}
method() {}
};
Copy the code
ContinueStatement
The continue statement
interface ContinueStatement {
type: 'ContinueStatement';
label: Identifier | null;
}
Copy the code
Such as:
for (var i = 0; i < 10; i++) {
if (i === 0) {
continue; }}Copy the code
DebuggerStatement
The debugger statement
interface DebuggerStatement {
type: 'DebuggerStatement';
}
Copy the code
For example,
while(true) {
debugger;
}
Copy the code
DoWhileStatement
Do – while statement
interface DoWhileStatement {
type: 'DoWhileStatement';
body: Statement;
test: Expression;
}
Copy the code
Test denotes the while condition
Such as:
var i = 0;
do {
i++;
} while(i = 2)
Copy the code
EmptyStatement
An empty statement
interface EmptyStatement {
type: 'EmptyStatement';
}
Copy the code
Such as:
if(true);
var a = [];
for(i = 0; i < a.length; a[i++] = 0);
Copy the code
ExpressionStatement
Expression statements, that is, statements that consist of a single expression.
interface ExpressionStatement {
type: 'ExpressionStatement'; expression: Expression; directive? :string;
}
Copy the code
When an expression statement represents a directive (for example, “Use strict”), the directive property contains the directive string.
Such as:
(function(){});
Copy the code
ForStatement
For statement
interface ForStatement {
type: 'ForStatement';
init: Expression | VariableDeclaration | null;
test: Expression | null;
update: Expression | null;
body: Statement;
}
Copy the code
ForInStatement
for… In statement
interface ForInStatement {
type: 'ForInStatement';
left: Expression;
right: Expression;
body: Statement;
each: false;
}
Copy the code
ForOfStatement
for… Of the statement
interface ForOfStatement {
type: 'ForOfStatement';
left: Expression;
right: Expression;
body: Statement;
}
Copy the code
IfStatement
If statement
interface IfStatement {
type: 'IfStatement'; test: Expression; consequent: Statement; alternate? : Statement; }Copy the code
Possession means if hit, alternate means else or else if.
LabeledStatement
The label statement is used to precisely use the continue and break statements in nested loops.
interface LabeledStatement {
type: 'LabeledStatement';
label: Identifier;
body: Statement;
}
Copy the code
Such as:
var num = 0;
outPoint:
for (var i = 0 ; i < 10 ; i++){
for (var j = 0 ; j < 10 ; j++){
if( i == 5 && j == 5) {breakoutPoint; } num++; }}Copy the code
ReturnStatement
Return statement
interface ReturnStatement {
type: 'ReturnStatement';
argument: Expression | null;
}
Copy the code
SwitchStatement
A Switch statement
interface SwitchStatement {
type: 'SwitchStatement';
discriminant: Expression;
cases: SwitchCase[];
}
Copy the code
Discriminant indicates the variable of the switch.
The SwitchCase type is as follows
interface SwitchCase {
type: 'SwitchCase';
test: Expression | null;
consequent: Statement[];
}
Copy the code
ThrowStatement
Throw statement
interface ThrowStatement {
type: 'ThrowStatement';
argument: Expression;
}
Copy the code
TryStatement
try… Catch statement
interface TryStatement {
type: 'TryStatement';
block: BlockStatement;
handler: CatchClause | null;
finalizer: BlockStatement | null;
}
Copy the code
Handler Processes the declaration content for a catch. Finalizer is finally content.
The types of CatchClaus are as follows
interface CatchClause {
type: 'CatchClause';
param: Identifier | BindingPattern;
body: BlockStatement;
}
Copy the code
Such as:
try {
foo();
} catch (e) {
console.erroe(e);
} finally {
bar();
}
Copy the code
WhileStatement
While statement
interface WhileStatement {
type: 'WhileStatement';
test: Expression;
body: Statement;
}
Copy the code
Test is a decision expression
WithStatement
With statement (scope that specifies the scope of the block statement)
interface WithStatement {
type: 'WithStatement';
object: Expression;
body: Statement;
}
Copy the code
Such as:
var a = {};
with(a) {
name = 'xiao.ming';
}
console.log(a); // {name: 'xiao.ming'}
Copy the code
Expressions and Patterns
Expressions can be of the following types:
type Expression = ThisExpression | Identifier | Literal |
ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | ClassExpression |
TaggedTemplateExpression | MemberExpression | Super | MetaProperty |
NewExpression | CallExpression | UpdateExpression | AwaitExpression | UnaryExpression |
BinaryExpression | LogicalExpression | ConditionalExpression |
YieldExpression | AssignmentExpression | SequenceExpression;
Copy the code
There are two types of Patterns available, function and object Patterns:
type BindingPattern = ArrayPattern | ObjectPattern;
Copy the code
ThisExpression
This expression
interface ThisExpression {
type: 'ThisExpression';
}
Copy the code
Identifier
Identifiers are the names we define when we write JS, such as variable names, function names, and attribute names, all belong to identifiers. The corresponding interface looks like this:
interface Identifier {
type: 'Identifier';
name: string;
}
Copy the code
Literal
Literals, not [] or {}, but literals that semantically represent a value, such as 1, “hello”, true, and regular expressions (with an extended Node to represent regular expressions) such as /\d? /.
interface Literal {
type: 'Literal';
value: boolean | number | string | RegExp | null;
raw: string; regex? : { pattern:string, flags: string };
}
Copy the code
Such as:
var a = 1;
var b = 'b';
var c = false;
var d = /\d/;
Copy the code
ArrayExpression
Array expression
interface ArrayExpression {
type: 'ArrayExpression';
elements: ArrayExpressionElement[];
}
Copy the code
Ex. :
[1.2.3.4];
Copy the code
ArrayExpressionElement
The node of an array expression has the following type
type ArrayExpressionElement = Expression | SpreadElement;
Copy the code
Expression contains all expressions, and SpreadElement is the extended operator syntax.
SpreadElement
Extended operator
interface SpreadElement {
type: 'SpreadElement';
argument: Expression;
}
Copy the code
Such as:
var a = [3.4];
var b = [1.2. a];var c = {foo: 1};
var b = {bar: 2. c};Copy the code
ObjectExpression
Object expression
interface ObjectExpression {
type: 'ObjectExpression';
properties: Property[];
}
Copy the code
Property represents the attribute description of the object
Type the following
interface Property {
type: 'Property';
key: Expression;
computed: boolean;
value: Expression | null;
kind: 'get' | 'set' | 'init';
method: false;
shorthand: boolean;
}
Copy the code
Kind means normal initialization, or get/set.
Such as:
var obj = {
foo: 'foo'.bar: function() {},
noop() {}, / / method to true
['computed'] :'computed' / / computed to true
}
Copy the code
FunctionExpression
Functional expression
interface FunctionExpression {
type: 'FunctionExpression';
id: Identifier | null;
params: FunctionParameter[];
body: BlockStatement;
generator: boolean;
async: boolean;
expression: boolean;
}
Copy the code
Such as:
var foo = function () {}
Copy the code
ArrowFunctionExpression
Arrow function expression
interface ArrowFunctionExpression {
type: 'ArrowFunctionExpression';
id: Identifier | null;
params: FunctionParameter[];
body: BlockStatement | Expression;
generator: boolean;
async: boolean;
expression: false;
}
Copy the code
Generator indicates whether it is a generator function, async indicates whether it is an async/await function, and params is a parameter definition.
The FunctionParameter types are as follows
type FunctionParameter = AssignmentPattern | Identifier | BindingPattern;
Copy the code
Ex. :
var foo = (a)= > {};
Copy the code
ClassExpression
Such expressions
interface ClassExpression {
type: 'ClassExpression';
id: Identifier | null;
superClass: Identifier | null;
body: ClassBody;
}
Copy the code
Such as:
var foo = class {
constructor() {}
method() {}
};
Copy the code
TaggedTemplateExpression
Tag template text function
interface TaggedTemplateExpression {
type: 'TaggedTemplateExpression';
readonly tag: Expression;
readonly quasi: TemplateLiteral;
}
Copy the code
The TemplateLiteral types are as follows
interface TemplateLiteral {
type: 'TemplateLiteral';
quasis: TemplateElement[];
expressions: Expression[];
}
Copy the code
The TemplateElement type is as follows
interface TemplateElement {
type: 'TemplateElement';
value: { cooked: string; raw: string };
tail: boolean;
}
Copy the code
For example,
var foo = function(a){ console.log(a); }
foo`test`;
Copy the code
MemberExpression
Attribute member expression
interface MemberExpression {
type: 'MemberExpression';
computed: boolean;
object: Expression;
property: Expression;
}
Copy the code
Such as:
const foo = {bar: 'bar'};
foo.bar;
foo['bar']; / / computed to true
Copy the code
Super
Superclass keyword
interface Super {
type: 'Super';
}
Copy the code
Such as:
class foo {};
class bar extends foo {
constructor() {
super();
}
}
Copy the code
MetaProperty
(I don’t know what this is for.)
interface MetaProperty {
type: 'MetaProperty';
meta: Identifier;
property: Identifier;
}
Copy the code
Such as:
new.target // Object declared by new, new.target will exist
import.meta
Copy the code
CallExpression
Function execution expression
interface CallExpression {
type: 'CallExpression';
callee: Expression | Import;
arguments: ArgumentListElement[];
}
Copy the code
Import type.
interface Import {
type: 'Import'
}
Copy the code
ArgumentListElement type
type ArgumentListElement = Expression | SpreadElement;
Copy the code
Such as:
var foo = function (){};
foo();
Copy the code
NewExpression
New expressions
interface NewExpression {
type: 'NewExpression';
callee: Expression;
arguments: ArgumentListElement[];
}
Copy the code
UpdateExpression
Update operator expressions such as ++, –;
interface UpdateExpression {
type: "UpdateExpression";
operator: '+ +' | The '-';
argument: Expression;
prefix: boolean;
}
Copy the code
Such as:
var i = 0;
i++;
++i; / / the prefix to true
Copy the code
AwaitExpression
Await expressions are used with async.
interface AwaitExpression {
type: 'AwaitExpression';
argument: Expression;
}
Copy the code
Such as
async function foo() {
var bar = function() {
new Primise(function(resolve, reject) {
setTimeout(function() {
resove('foo')},1000);
});
}
return await bar();
}
foo() // foo
Copy the code
UnaryExpression
Unary operator expressions
interface UnaryExpression {
type: "UnaryExpression";
operator: UnaryOperator;
prefix: boolean;
argument: Expression;
}
Copy the code
Enumeration UnaryOperator
enum UnaryOperator {
"-" | "+" | "!" | "~" | "typeof" | "void" | "delete" | "throw"
}
Copy the code
BinaryExpression
Binary operator expressions
interface BinaryExpression {
type: 'BinaryExpression';
operator: BinaryOperator;
left: Expression;
right: Expression;
}
Copy the code
Enumeration BinaryOperator
enum BinaryOperator {
"= =" | ! "" =" | "= = =" | ! "" = ="
| "<" | "< =" | ">" | "> ="
| "< <" | "> >" | "> > >"
| "+" | "-" | "*" | "/" | "%"
| "* *" | "|" | "^" | "&" | "in"
| "instanceof"
| "| >"
}
Copy the code
LogicalExpression
Logical operator expressions
interface LogicalExpression {
type: 'LogicalExpression';
operator: '| |' | '&';
left: Expression;
right: Expression;
}
Copy the code
Such as:
var a = The '-';
var b = a || The '-';
if (a && b) {}
Copy the code
ConditionalExpression
Conditional operator
interface ConditionalExpression {
type: 'ConditionalExpression';
test: Expression;
consequent: Expression;
alternate: Expression;
}
Copy the code
Such as:
var a = true;
var b = a ? 'consequent' : 'alternate';
Copy the code
YieldExpression
Yield expression
interface YieldExpression {
type: 'YieldExpression';
argument: Expression | null;
delegate: boolean;
}
Copy the code
Such as:
function* gen(x) {
var y = yield x + 2;
return y;
}
Copy the code
AssignmentExpression
Assignment expression.
interface AssignmentExpression {
type: 'AssignmentExpression';
operator: '=' | '* =' | * * = ' ' | '/ =' | '% =' | '+ =' | '- =' |
'< < =' | '> > =' | '> > > =' | '& =' | '^ =' | '| =';
left: Expression;
right: Expression;
}
Copy the code
The operator property represents an assignment operator, and left and right are expressions around the assignment operator.
SequenceExpression
Sequence expressions (using commas).
interface SequenceExpression {
type: 'SequenceExpression';
expressions: Expression[];
}
Copy the code
var a, b;
a = 1, b = 2
Copy the code
ArrayPattern
Array parsing mode
interface ArrayPattern {
type: 'ArrayPattern';
elements: ArrayPatternElement[];
}
Copy the code
Ex. :
const [a, b] = [1.3];
Copy the code
Elements represents the array node
ArrayPatternElement as follows
type ArrayPatternElement = AssignmentPattern | Identifier | BindingPattern | RestElement | null;
Copy the code
AssignmentPattern
Default assignment mode, array resolution, object resolution, function parameter default values used.
interface AssignmentPattern {
type: 'AssignmentPattern';
left: Identifier | BindingPattern;
right: Expression;
}
Copy the code
Ex. :
const [a, b = 4] = [1.3];
Copy the code
RestElement
Residual parameter pattern, syntax similar to extended operator.
interface RestElement {
type: 'RestElement';
argument: Identifier | BindingPattern;
}
Copy the code
Ex. :
const [a, b, ...c] = [1.2.3.4];
Copy the code
ObjectPatterns
Object resolution pattern
interface ObjectPattern {
type: 'ObjectPattern';
properties: Property[];
}
Copy the code
Ex. :
const object = {a: 1.b: 2};
const { a, b } = object;
Copy the code
The end of the
The effects of AST can be broadly divided into several categories
-
IDE uses such as code style detection (ESLint, etc.), code formatting, code highlighting, code errors, etc
-
Obfuscated compression of code
-
Tools to transform code. Such as Webpack, rollup, conversion between various code specifications, TS, JSX etc to native JS
Learning about the AST, ultimately, gives us an idea of the tools we use, and of course allows us to understand JavaScript and get closer to JavaScript.
reference
-
Front-end advanced Javascript abstract syntax tree
-
Abstract Syntax Tree