AST is the abbreviation of Abstract Syntax Tree, namely "Abstract Syntax Tree" It represents the syntax structure of programming language in the form of tree When webpack packages JS code, webpack will add some code on the basis of our original code. For example, when we package JS code, we can convert high-level code into low-level code through ast syntax tree
AST online address generation
babel plug-in to view the usage address
The AST generation process consists of source code - > lexical analysis - > syntax analysis - > abstract syntax tree
for example
let a = 1 + 2
lexical analysis
- From left to right, one character is read into the source program one by one, from which a "word" and "symbol" are recognized. What is read out is ordinary characters, and there is no function of any programming language
- Save the analysis results in a lexical unit array
word | word | Symbol | number | Symbol | number |
---|---|---|---|---|---|
let | a | = | 1 | + | 2 |
[ {"type": "word", value: "let"}, {"type": "word", value: "a"}, {"type": "Punctuator", value: "="}, {"type": "Numberic", value: "1"}, {"type": "Punctuator", value: "+"}, {"type": "Numberic", value: "2"}, ]
Then enter lexical analysis
Grammar analysis
Combine word sequences into various grammatical phrases
keyword | identifier | Assignment Operators | Literal | Binary operator | Literal |
---|---|---|---|---|---|
let | a | = | 1 | + | 2 |
[{ "type": "VariableDecLaration", "content": { {"type": "kind", "value": "let"}, // kind indicates what type of declaration it is {"type": "Identifier", "value": "a"}, // Identifier means identifier {"type": "init", "value": "="}, // An expression that represents the initial value {"type": "Literal", "value": "1"}, // Literal means a literal quantity {"type": "operator", "value": "+"}, // The operator representation is a binary operator {"type": "Literal", "value": "2"}, } }]
Abstract syntax tree
"program": { "type": "Program", "start": 0, "end": 13, "loc": { "start": { "line": 1, "column": 0 }, "end": { "line": 1, "column": 13 } }, "sourceType": "module", "interpreter": null, "body": [ { "type": "VariableDeclaration", "start": 0, "end": 13, "loc": { "start": { "line": 1, "column": 0 }, "end": { "line": 1, "column": 13 } }, "declarations": [ // Here is an array, indicating that multiple variables can be declared at the same time { "type": "VariableDeclarator", "start": 4, "end": 13, "loc": { "start": { "line": 1, "column": 4 }, "end": { "line": 1, "column": 13 } }, "id": { "type": "Identifier", "start": 4, "end": 5, "loc": { "start": { "line": 1, "column": 4 }, "end": { "line": 1, "column": 5 }, "identifierName": "a" }, "name": "a" }, "init": { "type": "BinaryExpression", "start": 8, "end": 13, "loc": { "start": { "line": 1, "column": 8 }, "end": { "line": 1, "column": 13 } }, "left": { "type": "NumericLiteral", "start": 8, "end": 9, "loc": { "start": { "line": 1, "column": 8 }, "end": { "line": 1, "column": 9 } }, "extra": { "rawValue": 1, "raw": "1" }, "value": 1 }, "operator": "+", "right": { "type": "NumericLiteral", "start": 12, "end": 13, "loc": { "start": { "line": 1, "column": 12 }, "end": { "line": 1, "column": 13 } }, "extra": { "rawValue": 2, "raw": "2" }, "value": 2 } } } ], "kind": "let" } ], "directives": [] }
Program example
package.json dependency
"@babel/generator": "^7.11.6", // Convert AST structure "@babel/parser": "^7.11.5", // Disassemble AST tree structure "@babel/traverse": "^7.11.5", "@babel/types": "^7.11.5",
@Generate AST from babel/parse
import * as parser from '@babel/parser' const code = `let a = 1 + 2` const ast = parser.parse(code) console.log(ast)
Modify syntax tree
Traverse the nodes through the traverse module of babel. After finding the corresponding nodes, convert the syntax tree into code through the generator module in babel
import * as parser from '@babel/parser' import traverse from "@babel/traverse" import generator from '@babel/generator' const code = `let val = 1 + 2` const ast = parser.parse(code) console.log(ast) // Traverse method can traverse all syntax tree nodes traverse(ast, { enter(path) { // This path will find all node s if (path.node.type == 'Identifier') { path.node.name = 'modify' path.stop() } } }) const ret = generator(ast) console.log(ret)
Here, val will be changed to modify
Create syntax tree
Create a syntax tree node through the @ babel/types module, and then push it into the body to manually create the syntax tree,
import * as parser from '@babel/parser' import traverse from "@babel/traverse" import generator from '@babel/generator' import * as t from '@babel/types' let code = `` let ast = parser.parse(code) let left = t.NumericLiteral(1) let right = t.NumericLiteral(2) let init = t.binaryExpression("+", left, right) let id = t.identifier("add") let variable = t.variableDeclarator(id, init) let declaration = t.variableDeclaration('let', [variable]) ast.program.body.push(declaration) // Convert to code let genCode = generator(ast) console.log(genCode.code)
Delete syntax tree node
The core of deleting syntax nodes is to traverse and find all nodes first, and complete it through @ babel/traverse. After finding each node, you can complete the operation of adding, deleting, modifying and querying through specific methods
- Common properties of NodePath
- Node: get the current node
- Parent: parent node
- parentPath: parent path
- Scope: scope
- context: context
- Common methods of NodePath
- get: current node
- findParent: search parent node
- getSibling: get sibling node
- replaceWith: replace this node with the AST node
- replaceWithMultiple: replace this node with multiple AST nodes
- insertBefore: inserts a node before it
- insertAfter: inserts a node after the node
- remove: delete node
const parser = require('@babel/parser') const traverse = require('@babel/traverse').default const generator = require('@babel/generator').default let code = ` console.log('jake') let sum = 1 + 2 let minus = 2 - 1 console.log("tom") ` let ast = parser.parse(code) console.log(ast) // traverse traverses the syntax tree traverse(ast, { Identifier(path) { if (path.node.name == 'sum') { path.parentPath.remove() } } }) console.log(generator(ast))
After deleting sum