CompilerWhat is it? The simple point is to convert the source ** into the target **, and the detailed point is to translate the source ** program written in a high-level computer language that is easy for people to write, read, and maintain, into a program in a low-level machine language that is interpreted and run by the computer.
Vue's compiler is roughly divided into three phases, namely lexical analysis > syntactic analysis > generation. The lexical analysis stage is roughly to parse the string template into tokens, syntactic analysis generates AST on the basis of lexical analysis, and **generation generates the final according to AST**. In this article, we will briefly analyze the process of lexical analysis.
At the source (src compiler index.)js) by such a sentence **, containsparse
ast
Keywords, you knowparse
The function is used to parse the template string and generate itast
Target.
const ast = parse(template.trim(),options)
Foundparse
function, found to be called internallyparsehtml
, actuallyparsehtml
The function is used for lexical analysis. Whileparse
Functions are ultimately generated on the basis of lexical analysisast
/** convert html string to ast.* export function parse ( parse function is used to do syntactic analysis on the basis of lexical analysis to generate an ast. template: string, options: compileroptions): astelement | void .
Then let's go and seeparsehtml
How to read the character stream and parse the template string step by step.
export function parsehtml (html, options) if (textend < 0) if (options.chars &&text) else because the while loop will call advance to update the html If the above processing is equal to the two, it means that the html has not changed after passing through the ** of the loop, and the html string at this time is treated as plain text The entire string is treated as text if (html === last).") break } to call the parseendtag function parseendtag() advance function to remove the parse string function advance (n) parsestarttag function parsestarttag function parsestarttag () handlestarttag function to handle parsestarttag results function handlestarttag (match) parseendtag function parseendtag (tagname, start, end) }
From the above **, it can be seen that when the array is empty or the label is plain text tag (style, script, textarea), it is obtained
There are three types of situations where the first occurrence in a string occurs.
1. In textend === 0(appears in the first position), using the comment node and the start tag as an example, to briefly explain how to deal with the case of textend === 0 internally.
Annotation node.
if (comment.test(html)) advance(commentend + 3) call the advance function to pass in the end position of the parsed string, remove the html that has already been processed, update the html variable to the remaining unprocessed string, update the indexd value to commentend + 3 (where the html string was read) continue to jump out of this loop Start the next loop and start the parse again Process. }
Start tab.
const starttagmatch = parsestarttag() calls the parsestarttag function, and obtains its return value, if there is a return value, it means that the start tag parsing is successful, it is indeed a start tag if (starttagmatch) continue}function parsestarttag ()advance(start[0].length) Here pass in the length of the tagname tag and call the advance function let end, attr while The condition for the loop to execute is that it does not match the end part of the start tag, and it matches the property while (!) in the start tagend = html.match(starttagclose)) attr = html.match(attribute))) if (end) handlestarttag (match) if (canbeleftopentag(tagname) &lasttag === tagname) const unary = isunarytag(tagname) |unaryslash determines whether the start tag is a unary tag const l = matchattrs.The length const attrs = new array(l) for loop is used to format matchattrs array and store the formatted data in the constant attrs for (let i = 0; i < l; i++)if (args[4] === '') if (args[5] === '') const value = args[3] |args[4] |args[5] |''attrs[i] = attrs is an array } if (!unary) ) lasttag = tagname lasttag variable holds the element at the top of the stack update lasttag variable } if (options.).start)
2. In the case of textend >= 0.
This paragraph handles strings where the first character is < but the label is not successfully matched, or where the first character is not <, let text, rest, nextif (textend >= 0) text = htmlsubstring(0, textend) now guarantees that text is plain text advance(textend)}if (options.).chars &&text)
3. In the case of textend <= 0, the entire HTML string is processed as text.
if (textend < 0)
The above analysis is for the case where the most recent label is a non-plain text label, so how do you deal with plain text labels? Plain text tags include script tags, style tags, and textarea tags.
let endtaglength = 0 is used to hold plain text labels, and the character length of closed labels const stackedtag = lasttagtolowercase()const restackedtag = recache[stackedtag] |recache[stackedtag] = new regexp('([\s\\s]*?', 'i'The purpose of restackedtag is to match the content of the plain text tag and the end tag ** Use regular restackedtag to match the string html and replace it with an empty string, the constant rest will save the remaining characters const rest = htmlreplace(restackedtag, function (all, text, endtag) if (shouldignorefirstnewline(stackedtag, text)) if (options.chars) return ''Replace the regex with the content that matches the''})index += html.length - rest.length;The closing tag position is htmllength - remaining string length html = rest update html to start a new while loop parseendtag(stackedtag, index - endtaglength, index).
After reading the above paragraphs, I found outparseendtag
The function hasn't been analyzed yet, so according to the name, it should be handled with the end tag.
There are three ways to call parseendtag() to handle the remaining unprocessed tags of the stack. parseendtag(tagname) parseendtag (tagname, start, end) function parseendtag (tagname, start, end) find the closest opened tag of the same type stack flashback finds the start tag corresponding to the end tag if ( tagname) else if (pos >= 0) >has no matching end tag.` if (options.end) // remove the open elements from the stack stack.length = pos when tagname is passed in to delete the element after pos when tagname is passed in pos 0 is equivalent to emptying stack lasttag = pos &&&stack[pos - 1].tag update top of stack element } else if (lowercasedtagname ===.)'br') else if (lowercasedtagname === 'p') if (options.end) pos< 0 case where other missing start tags are encountered, and the end tag is ignored}
In the process of lexical analysis, it can be achieved by reading the character stream and parsing the string bit by bit with the regular code, until the entire string has been parsed. And whenever a particular token is encountered, the corresponding hook function is called, and the useful parameters are passed through. Againparse
Functions are generated based on these parametersast