Vue編譯器AST抽象語法樹源碼分析
引言
接上篇 Vue編譯器源碼分析compile 解析
baseCompile主要核心代碼
// `createCompilerCreator` allows creating compilers that use alternative // parser/optimizer/codegen, e.g the SSR optimizing compiler. // Here we just export a default compiler using the default parts. var createCompiler = createCompilerCreator(function baseCompile( template, options ) { var ast = parse(template.trim(), options); if (options.optimize !== false) { } var code = generate(ast, options); return { ast: ast, render: code.render, staticRenderFns: code.staticRenderFns } });
可以看到 baseCompile 的代碼非常的簡短主要核心代碼。
- var ast =parse(template.trim(), options); parse 會用正則等方式解析 template 模板中的指令、class、style等數據,形成AST。
- optimize(ast, options); optimize 的主要作用是標記 static 靜態節點,這是 Vue 在編譯過程中的一處優化,後面當 update 更新界面時,會有一個 patch 的過程, diff 算法會直接跳過靜態節點,從而減少瞭比較的過程,優化瞭 patch 的性能。
- var code =generate(ast, options); 生成目標平臺所需的代碼,將 AST 轉化成 render function 字符串的過程,得到結果是 render 的字符串以及 staticRenderFns 字符串。
最終 baseCompile 的返回值
{ ast: ast, render: code.render, staticRenderFns: code.staticRenderFns }
最終返回瞭抽象語法樹( ast ),渲染函數( render ),靜態渲染函數( staticRenderFns ),且render 的值為code.render ,staticRenderFns 的值為code.staticRenderFns ,也就是說通過 generate 處理 ast 之後得到的返回值 code 是一個對象 …
接下來讓我們把目光聚焦在 Vue 的 parser,它是如何將字符串模板解析為抽象語法樹(AST
)的。
var ast = parse(template.trim(), options);
在講解parse之前你需要對編譯過程以及其中的技術點有個宏觀、概要的瞭解。
引用自維基百科:
它主要的目的是將便於人編寫、閱讀、維護的高級計算機語言所寫作的源代碼程序,翻譯為計算機能解讀、運行的低階機器語言的程序。源代碼一般為高階語言(High-level language),如Pascal、C、C++、C# 、Java等,而目標語言則是匯編語言或目標機器的目標代碼(Object code)。
編譯器的技術分為詞法分析、語法分析和語義分析三個部分,通常編譯器的第一項工作叫做詞法分析。就像閱讀文章一樣,文章是由一個個的中文單詞組成的。程序處理也一樣,隻不過這裡不叫單詞,而是叫做“詞法記號”,英文叫 Token。
<div id="app" v-if="ret">{{ message }}</div>
編譯器會識別出 div a span 這些標簽,id class style v-if v-for 這樣的屬性、指令,還有花括號符號這樣的插值操作…等。這些都是 Token。
如何寫一個程序來識別 Token
那麼,如何寫一個程序來識別 Token 呢?
其實,我們可以手寫程序制定一些規則來區分每個不同的 Token,這些規則用“正則文法”表達,符合正則文法的表達式稱為“正則表達式”。通過他們來完成具體的詞法分析工作。
編譯器下一個階段的工作是語法分析。詞法分析是識別一個個的單詞,而語法分析就是在詞法分析的基礎上識別出程序的語法結構。這個結構是一個樹狀結構,是計算機容易理解和執行的。
程序也要定義良好的語法結構,它的語法分析過程,就是構造這麼一棵樹。一個程序就是一棵樹,這棵樹叫做抽象語法樹(Abstract Syntax Tree,AST)。樹的每個節點(子樹)是一個語法單元,這個單元的構成規則就叫“語法”。
而我們這裡要講的 parser 就是在編譯器對源代碼處理的第一步,parser 把某種特定格式的文本(字符串)轉換成某種數據結構的程序(對象),並且這個數據結構是編譯器能夠理解的,因為編譯器的後續步驟,比如上面提到的 句法分析,類型檢查/推導,代碼優化,代碼生成 等等都依賴於該數據結構。
註:parse & parser 這兩個單詞,不要混淆,parse 是動詞,代表“解析”的過程,parser 是名詞,代表“解析器”。
Vue 的編譯器也不例外, 在詞法分析階段 Vue 會把字符串模板解析成一個個的令牌(token),該令牌將用於句法分析階段,在句法分析階段會根據令牌生成一棵 AST,最後再根據該 AST生成最終的渲染函數,這樣就完成瞭代碼的生成。
var ast = parse(template.trim(), options);
parse 函數解析模板字符串
回歸到剛剛的代碼,已知 parse 函數就是用來解析模板字符串的,最終生成AST。
function parse(template, options) { // 省略... parseHTML(template, { warn, expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, canBeLeftOpenTag: options.canBeLeftOpenTag, shouldDecodeNewlines: options.shouldDecodeNewlines, shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref, shouldKeepComment: options.comments, start (tag, attrs, unary) { // 省略... }, end () { // 省略... }, chars (text: string) { // 省略... }, comment (text: string) { // 省略... } }) return root }
需要註意到在parse 函數內部主要通過調用parseHTML 函數對模板字符串進行解析,實際上parseHTML 函數的作用就是用來做詞法分析的,而parse函數的作用則是在詞法分析的基礎上做句法分析從而生成一棵AST。本節我們主要分析一下Vue是如何對模板字符串進行詞法分析的,也就是parseHTML 函數的實現。
接下來我們章節會分為兩個方向
一:parseHTML 函數源碼解析
二:Vue編譯器token解析規則-正則分析
以上就是Vue編譯器AST抽象語法樹源碼分析的詳細內容,更多關於Vue編譯器AST抽象語法樹的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- vue原理Compile從新建實例到結束流程源碼
- vue parseHTML 函數拿到返回值後的處理源碼解析
- vue2從template到render模板編譯入口詳解
- vue parseHTML函數源碼解析 AST預備知識
- vue parseHTML 函數源碼解析