This is the 9th day of my participation in Gwen Challenge.
preface
From the previous study, we learned about the three modules for template compilation. In this article, we’ll take a closer look at the compiler.
The role of the parser
We can’t do optimizations or generate code strings based on the AST until we parse the template into an AST. How does the parser parse the template into an AST?
Here’s a simple example:
<div>
<p>{{name}}</p>
</div>
Copy the code
After converting to AST:
{
tag: "div".type: 1.staticRoot: false.sttatic: false.plain: true.parent: undefined.attrsList: [].atttrsMap: {},
children: [{tag: "p".type: 1.staticRoot: false.static: false.plain: true.parent: {tag:"div". },atttrsList: [].attrsMap: {},
children: [{type: 2.text: "{{name}}".static: false.expression: "_s(name)"}]}]}Copy the code
The AST is not a fancy thing, but it uses ordinary objects in Javascript to describe a node. Properties in each object hold various data required by the node. For example, the parent property holds the parent node’s description object, and the children property is an array that holds the child node’s description object. For example, the type attribute indicates the type of a node and so on. When multiple independent nodes are linked together using the parent and children attributes, the tree is called an AST.
Internal operation principle
There are several child parsers inside the parser, the most important of which is the HTML parser.
The function of HTML parser is to parse HTML, it will constantly trigger various hook functions in the process of parsing HTML. These hook functions include the start tag hook function, the end tag hook function, the text hook function, and the comment hook function.
ParseHTML (template, {start(tag, attrs, unary, start, end){parseHTML(template, {start(tag, attrs, unary, start, end)}, end(tag, start, end){ Chars (text, start, end){// Parse plain text, trigger function}, comment(text, start, end){// parse to comment, trigger function}})Copy the code
Take a simple example:
<div><p>hello world</p></div>
Copy the code
When parsing the above template, start(< div>), start(
), chars(Hello World), end(
), end() are triggered in sequence.
If the start hook is triggered, we create an element node and add it to the top of the stack.
Why use a stack to store nodes?
Because of the first-in-last-out nature of the stack, its typical use is the parenthesis matching problem. Here, there are two benefits:
- A problem with verifying element matches.
- When the stack is empty, template processing is complete.
Start hook – Creates element node
const stack = []; // Temporary storage node
let currentParent; / / the parent node
function createASTElement(tag, attrs, parent){
return {
type: 1,
tag,
attrsList: attrs,
parent,
children
}
}
parseHTML(template, {
start(tag, attrs, unary, start, end) {
let element = createASTElement(tag, attrs, currentParent);
currentParent = element;
stack.push(element)
},
})
Copy the code
End hook – Pops element node
parseHTML(template, {
end(tag, start, end) {
const element = stack[stack.length-1];
stack.length -= 1;
currentParent = stack[statkc.length-1]; }})Copy the code
Chars — Creates a text node
parseHTML(template, {
chars(text, start, end){
let element = { type: 3, text };
letchildren = currentParent.chilren; children.push(element); }})Copy the code
Comment — Creates a comment node
parseHTML(template, {
comment(text){
let element = { type: 3, text, isComment: true}
letchildren = currentParent.chilren; children.push(element); }})Copy the code
HTML parser
Operation principle
Parsing HTML is simply an HTML template string loop. Each loop takes a small piece of the HTML template string and repeats the loop until the HTML template is truncated into an empty string.
Take the previous example as an example:
`<div>
<p>{{name}}</p>
</div>`
Copy the code
- First cycle, take it out
<div>
To triggerstart
Hook function, the result of the interception
`
<p>{{name}}</p>
</div>`
Copy the code
- The second loop takes out a string and fires
chars
Hook function
`
`
Copy the code
The interception results are as follows:
`<p>{{name}}</p>
</div>`
Copy the code
- Third cycle, take it out
<p>
To triggerstart
Hook function, the result of the interception
`{{name}}</p>
</div>`
Copy the code
- The fourth cycle is taken out
{{name}}
String, triggerchars
The result of intercepting the hook function:
`</p>
</div>`
Copy the code
- Fifth cycle, take it out
</p>
To triggerend
The result of intercepting the hook function:
`
</div>`
Copy the code
- The sixth loop fetches a string:
`
`
Copy the code
Results after interception:
`</div>`
Copy the code
- Seventh cycle, take it out
</div>
To triggerend
The result of intercepting the hook function:
` `Copy the code
conclusion
In this article, you learned the basic workflow of the parser, as well as the basic principles of the HTML parser. We will continue to learn more about the implementation of the HTML parser, so stay tuned…