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

  1. IDE uses such as code style detection (ESLint, etc.), code formatting, code highlighting, code errors, etc

  2. Obfuscated compression of code

  3. 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