抽象语法树AST(Abstract Syntax Tree)
什么是抽象语法树
本质上就是一个js对象,描述模板语法的js对象(附上尚硅谷老师的课件截图)
有何作用
编译程序直接将vue模板语法编译成html语法是非常困难的,先将模板语法,转化为AST,再转换为HTML语法,会让编译工作变得更简单。
AST算法
主要思想:指针遍历,堆栈结构
//开始标签的正则
let startRegExp = /^\<([a-z]+[1-6]?)(\s[^\<]+)?\>/
//结束标签的正则
let endRegExp = /^\<\/([a-z]+[1-6]?)\>/
//只检测开始标签与结束标签之间的文字,不检测结束标签与开始标签之间的文字
let wordRegExp = /^([^\<]+)\<\/[a-z]+[1-6]?\>/
//指针未遍历到的模板字符串
let rest
//将遍历到的开始标签压栈,遇到结束标签出栈
let stack1 = []
//整理数据的栈
let stack2 = []
// 解析模板生成ast语法树
parse(templateString){
rest = templateString
let i = 0
while(i<templateString.length){
rest = templateString.substring(i)
if(startRegExp.test(rest)){ //①. 检测到开始标签
let tagAll = rest.match(startRegExp)
let tag = tagAll[1]
let attrStr = tagAll[2]
stack1.push(tag)
// console.log(attrStr)
//属性对象
let attrs = parseAttrs(attrStr)
往栈2 中推入一个与刚压入stack1中该标签对应的数据对象,自带一个children的空数组
stack2.push({tag,type:1,children:[],attrs})
i += tag.length+2
}else if(endRegExp.test(rest)){ //②. 检测到结束标签
let tag = rest.match(endRegExp)[1]
stack1.pop()
let pop2 = stack2.pop()
if(stack2.length >= 1){
//若stack中不止一个数据项,则将刚出栈的对象的数据,将其压入前一个数据项的children数组中
stack2[stack2.length-1].children.push(pop2)
}else{
//将最后一个数据项重新压入栈中,就是整理好的AST
stack2.push(pop2)
}
i += tag.length+3
}else if(wordRegExp.test(rest)){ //③. 检测到文本
let word = rest.match(wordRegExp)[1]
if(!/^\s+$/.test(word)){
// 捕获到的文本不是空格
if(stack2.length > 1){
stack2[stack2.length-1].children.push({text:word,type:3})
}
}
i += word.length
}else{
i++
}
}
return stack2[0]
}
//解析属性:只考虑属性间使用一个空格,且均使用双引号
function(attrStr){
// 如果传进来的是空串或者undefined
if(attrStr === undefined || /^\s*$/.test(attrStr)) return []
// 去除首尾空格
attrStr = attrStr.trim()
// 是否在引号内部
let isInner = false
let point = 0
let resArr = []
for(let i=0;i<attrStr.length;i++){
let attr = attrStr[i]
if(attr == '"'){
isInner = !isInner
}else if(attr == ' '){
if(!isInner){
resArr.push(attrStr.substring(point,i).trim())
point = i
}
}
}
resArr.push(attrStr.substring(point).trim())
resArr = resArr.map(item => {
let arr = item.match(/(.+)="(.+)"/)
return {attrs:arr[1],value:arr[2]}
})
return resArr
}