遍历AST语法树

我们需要遍历ast语法树,访问树中节点进行语法树的转化


function transformElement(node){
    console.log('元素处理',node)
}
function transformText(node){
    console.log('文本处理',node)
}
function transformExpression(node){
    console.log('表达式')
}
function traverseNode(node,context){
    context.currentNode = node;
    const transforms = context.nodeTransforms;
    for(let i = 0; i < transforms.length;i++){
        transforms[i](node,context); // 调用转化方法进行转化
        if(!context.currentNode) return
    }
    switch(node.type){
        case NodeTypes.ELEMENT:
        case NodeTypes.ROOT:
            for(let i = 0; i < node.children.length;i++){
                context.parent = node;
                traverseNode(node.children[i],context);
            }
            
    }
}

function createTransformContext(root){
    const context = {
        currentNode:root, // 当前转化节点 
        parent:null,   // 当前转化节点的父节点
        nodeTransforms:[ // 转化方法
            transformElement,
            transformText,
            transformExpression
        ],
        helpers: new Map(), // 创建帮助映射表,记录调用方法次数
        helper(name){
            const count = context.helpers.get(name) || 0;
            context.helpers.set(name,count+1)
        }
    }
    return context
}

function transform(root){
    // 创建转化的上下文, 记录转化方法及当前转化节点
    let context = createTransformContext(root)
    // 递归遍历
    traverseNode(root,context)
}
export function compile(template){
    const ast = baseParse(template);
    transform(ast);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

退出函数

表达式不需要退出函数,直接处理即可。元素需要在遍历完所有子节点在进行处理

function transformExpression(node){
    if(node.type == NodeTypes.INTERPOLATION){
        console.log('表达式')
    }
}
function transformElement(node){
    if(node.type === NodeTypes.ELEMENT ){
        return function postTransformElement(){ // 元素处理的退出函数
            // 如果这个元素
            console.log('元素',node)
        }
    }
}
function transformText(node){
    if(node.type === NodeTypes.ELEMENT || node.type === NodeTypes.ROOT){
        return ()=>{
            console.log('元素/root',node)
        }   
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function traverseNode(node,context){
  	// ...
    for(let i = 0; i < transforms.length;i++){
        let onExit = transforms[i](node,context); // 调用转化方法进行转化
        if(onExit){
            exitsFns.push(onExit)
        }
        if(!context.currentNode) return
    }
    // ...
    // 最终context.currentNode 是最里面的
    context.currentNode = node; // 修正currentNode;
    let i = exitsFns.length
    while (i--) {
        exitsFns[i]()
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

本周更新完毕。。。。。。。