emmylua_parser/syntax/tree/
lua_tree_builder.rs

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use rowan::{GreenNode, NodeCache};

use crate::{
    kind::{LuaSyntaxKind, LuaTokenKind},
    parser::MarkEvent,
    text::SourceRange,
};

use super::lua_green_builder::LuaGreenNodeBuilder;

#[derive(Debug)]
pub struct LuaTreeBuilder<'a> {
    text: &'a str,
    events: Vec<MarkEvent>,
    green_builder: LuaGreenNodeBuilder<'a>,
}

impl<'a> LuaTreeBuilder<'a> {
    pub fn new(
        text: &'a str,
        events: Vec<MarkEvent>,
        node_cache: Option<&'a mut NodeCache>,
    ) -> Self {
        match node_cache {
            Some(cache) => LuaTreeBuilder {
                text,
                events,
                green_builder: LuaGreenNodeBuilder::with_cache(cache),
            },
            None => LuaTreeBuilder {
                text,
                events,
                green_builder: LuaGreenNodeBuilder::new(),
            },
        }
    }

    pub fn build(&mut self) {
        self.start_node(LuaSyntaxKind::Chunk);
        let mut parents: Vec<LuaSyntaxKind> = Vec::new();
        for i in 0..self.events.len() {
            match std::mem::replace(&mut self.events[i], MarkEvent::none()) {
                MarkEvent::NodeStart {
                    kind: LuaSyntaxKind::None,
                    ..
                } | MarkEvent::Trivia => {}
                MarkEvent::NodeStart { kind, parent } => {
                    parents.push(kind);
                    let mut parent_position = parent;
                    while parent_position > 0 {
                        match std::mem::replace(
                            &mut self.events[parent_position],
                            MarkEvent::none(),
                        ) {
                            MarkEvent::NodeStart { kind, parent } => {
                                parents.push(kind);
                                parent_position = parent;
                            }
                            _ => unreachable!(),
                        }
                    }

                    for kind in parents.drain(..).rev() {
                        self.start_node(kind);
                    }
                }
                MarkEvent::NodeEnd => {
                    self.finish_node();
                }
                MarkEvent::EatToken { kind, range } => {
                    self.token(kind, range);
                }
            }
        }

        self.finish_node();
    }

    fn token(&mut self, kind: LuaTokenKind, range: SourceRange) {
        self.green_builder.token(kind, range);
    }

    fn start_node(&mut self, kind: LuaSyntaxKind) {
        self.green_builder.start_node(kind);
    }

    fn finish_node(&mut self) {
        self.green_builder.finish_node();
    }

    pub fn finish(self) -> GreenNode {
        let root = self.green_builder.finish(&self.text);
        root
    }
}