Skip to main content

ktrs_parser/builder/
tree.rs

1//! `PsiBuilderImpl.getTreeBuilt`: `prepareLightTree` (+ `balanceWhiteSpaces`) and `bind`,
2//! producing a [`ktrs_syntax::Tree`] plus preorder error messages.
3//!
4//! Leaves whose type is lazy-parseable (collapsed `BLOCK`/`LAMBDA_EXPRESSION`, `DOC_COMMENT`, ...)
5//! are handed to the `lazy` callback, which reparses their text with a fresh builder exactly as
6//! the compiler's chameleons do and emits that builder's tree into the same [`TreeSink`], its root
7//! renamed to the leaf's kind. `false` from the callback means "plain leaf".
8
9use ktrs_syntax::{Parse, SyntaxKind};
10
11use super::binders::EdgeBinder;
12use super::psi_builder::PsiBuilder;
13use super::sink::TreeSink;
14
15/// Reparses a lazy-parseable leaf into `sink`; `false` if its kind isn't lazy (nothing emitted).
16/// Generic rather than `dyn` so the per-leaf kind check inlines into `create_leaf`.
17pub trait LazyReparse: Fn(&LazyLeaf<'_>, &mut TreeSink) -> bool {}
18impl<F: Fn(&LazyLeaf<'_>, &mut TreeSink) -> bool> LazyReparse for F {}
19
20/// A leaf about to be built, with the outer builder's (unremapped) lexemes covering it.
21pub struct LazyLeaf<'a> {
22    pub kind: SyntaxKind,
23    pub text: &'a str,
24    /// Lexemes `start..end` of `outer`; sliced only when the leaf is actually reparsed.
25    outer: &'a PsiBuilder,
26    start: usize,
27    end: usize,
28}
29
30impl LazyLeaf<'_> {
31    /// A builder over the leaf's lexemes. Equal to re-lexing `text` with the outer builder's
32    /// lexer when the leaf is a balanced `{...}` range or runs to the end of the input: the
33    /// Kotlin lexer's state at a `{` only differs inside a `${...}` template, whose brace
34    /// counting agrees with `advanceBalancedBlock`.
35    pub(crate) fn relexed_builder(&self) -> PsiBuilder {
36        let (start, end) = (self.start, self.end);
37        PsiBuilder::from_lexemes(self.text, &self.outer.lex_starts[start..=end], &self.outer.orig_types[start..end])
38    }
39}
40
41impl PsiBuilder {
42    pub fn get_tree_built(&mut self, lazy: &impl LazyReparse) -> Parse {
43        let mut sink = TreeSink::new();
44        self.build_tree_into(None, &mut sink, lazy);
45        sink.finish()
46    }
47
48    /// `getTreeBuilt` into a shared sink; the root node gets `root_kind` if given.
49    pub fn build_tree_into(&mut self, root_kind: Option<SyntaxKind>, sink: &mut TreeSink, lazy: &impl LazyReparse) {
50        assert!(!self.production.is_empty(), "Parser produced no markers");
51        self.balance_white_spaces();
52        let mut skipped_errors = std::mem::take(&mut self.skipped_errors);
53        self.duplicate_error_items(&mut skipped_errors);
54        self.bind(root_kind, &skipped_errors, sink, lazy);
55        self.skipped_errors = skipped_errors;
56    }
57
58    fn balance_white_spaces(&mut self) {
59        let mut last_index: i32 = 0;
60        // `getLexemeIndexAt(i - 1)`, carried along: item i - 1's index as this loop left it.
61        let mut prev_index = self.production.get_lexeme_index_at(0);
62        let size = self.production.size().saturating_sub(1);
63        for i in 1..size {
64            let id = self.production.list[i];
65            let done = id < 0;
66            let item = self.production.marker(id);
67            assert!(done || item.is_error_item || item.is_done(), "Unbalanced tree: marker not done");
68
69            let binder = if item.is_error_item { EdgeBinder::DefaultRight } else { item.get_binder(done) };
70            let mut lexeme_index = item.get_lexeme_index(done);
71
72            // The default binders always land on the run's end (left) or start (right), so they
73            // skip scanning the other side; the result equals the general path's.
74            if binder == EdgeBinder::DefaultLeft {
75                lexeme_index = self.shift_over_whitespace_forward(lexeme_index as usize) as i32;
76                self.production.marker_mut(id).set_lexeme_index(lexeme_index, done);
77                (last_index, prev_index) = (lexeme_index, lexeme_index);
78                continue;
79            }
80            let prev_production_lex_index = prev_index;
81            let mut ws_start_index = lexeme_index.max(last_index);
82            while ws_start_index > prev_production_lex_index
83                && self.is_whitespace_or_comment(self.lex_types[ws_start_index as usize - 1])
84            {
85                ws_start_index -= 1;
86            }
87            if binder == EdgeBinder::DefaultRight {
88                self.production.marker_mut(id).set_lexeme_index(ws_start_index, done);
89                (last_index, prev_index) = (ws_start_index, ws_start_index);
90                continue;
91            }
92            let ws_end_index = self.shift_over_whitespace_forward(lexeme_index as usize) as i32;
93
94            if ws_start_index != ws_end_index {
95                // Production lexemes are monotonic, so the run is never inverted.
96                debug_assert!(ws_start_index < ws_end_index);
97                let (start, end) = (ws_start_index as usize, ws_end_index as usize);
98                let at_end = ws_start_index == 0 || end == self.lexeme_count();
99                let getter = |i: usize| self.token_text(start + i);
100                let edge = binder.get_edge_position(&self.lex_types[start..end], at_end, &getter);
101                lexeme_index = ws_start_index + edge as i32;
102                self.production.marker_mut(id).set_lexeme_index(lexeme_index, done);
103            } else if lexeme_index < ws_start_index {
104                lexeme_index = ws_start_index;
105                self.production.marker_mut(id).set_lexeme_index(ws_start_index, done);
106            }
107
108            last_index = lexeme_index;
109            prev_index = lexeme_index;
110        }
111    }
112
113    /// `prepareLightTree` keeps only the first (deepest) error item per lexeme, in production order.
114    fn duplicate_error_items(&self, skipped: &mut Vec<bool>) {
115        skipped.clear();
116        // `bind` only reads the flags of error items.
117        if !self.production.has_error_items() {
118            return;
119        }
120        skipped.resize(self.production.size(), false);
121        let mut last_error_index = -1;
122        for (i, &id) in self.production.list.iter().enumerate().skip(1) {
123            if id > 0 && self.production.marker(id).is_error_item {
124                let cur_token = self.production.marker(id).lexeme;
125                if cur_token != last_error_index {
126                    last_error_index = cur_token;
127                } else {
128                    skipped[i] = true;
129                }
130            }
131        }
132    }
133
134    /// Walks the production in order; equivalent to `bind` over the light tree.
135    fn bind(&self, root_kind: Option<SyntaxKind>, skipped_errors: &[bool], out: &mut TreeSink, lazy: &impl LazyReparse) {
136        let list = &self.production.list;
137        let root = self.production.marker(list[0]);
138        out.start_node(root_kind.unwrap_or_else(|| kind_of(root.kind)));
139        let mut depth = 1;
140        let mut lex_index = root.lexeme.max(0) as usize;
141
142        let mut i = 1;
143        while i < list.len() {
144            let id = list[i];
145            let item = self.production.marker(id);
146            if id < 0 {
147                lex_index = self.insert_leaves(lex_index, item.done_lexeme, out, lazy);
148                // Tokens after the root's done are dropped, as upstream (which LOG.errors).
149                if id == -list[0] {
150                    break;
151                }
152                out.finish_node();
153                depth -= 1;
154            } else if item.is_error_item {
155                if !skipped_errors[i] {
156                    lex_index = self.insert_leaves(lex_index, item.lexeme, out, lazy);
157                    out.errors.push(self.production.message(id).unwrap_or_default().to_owned());
158                    out.start_node(SyntaxKind::ERROR_ELEMENT);
159                    out.finish_node();
160                }
161            } else {
162                lex_index = self.insert_leaves(lex_index, item.lexeme, out, lazy);
163                if item.collapsed {
164                    lex_index = self.collapse_leaves(item.lexeme, item.done_lexeme, kind_of(item.kind), out, lazy);
165                    i = list[i..].iter().position(|&x| x == -id).map_or(list.len(), |p| i + p);
166                } else {
167                    let kind = kind_of(item.kind);
168                    if kind == SyntaxKind::ERROR_ELEMENT {
169                        out.errors.push(self.production.message(id).expect("error marker without message").to_owned());
170                    }
171                    out.start_node(kind);
172                    depth += 1;
173                }
174            }
175            i += 1;
176        }
177        // Unbalanced markers are a parser bug upstream (LOG.error); close whatever is still open.
178        for _ in 0..depth {
179            out.finish_node();
180        }
181    }
182
183    fn insert_leaves(&self, cur_token: usize, last_idx: i32, out: &mut TreeSink, lazy: &impl LazyReparse) -> usize {
184        let last_idx = (last_idx.max(0) as usize).min(self.lexeme_count());
185        if cur_token >= last_idx {
186            return cur_token;
187        }
188        let kinds = &self.lex_types[cur_token..last_idx];
189        let starts = &self.lex_starts[cur_token..=last_idx];
190        for (i, (&kind, bounds)) in kinds.iter().zip(starts.windows(2)).enumerate() {
191            // Empty tokens are skipped (no Kotlin token type is an ILeafElementType).
192            if bounds[0] < bounds[1] {
193                let text = &self.text[bounds[0] as usize..bounds[1] as usize];
194                self.create_leaf(kind, cur_token + i, cur_token + i + 1, text, out, lazy);
195            }
196        }
197        last_idx
198    }
199
200    fn collapse_leaves(&self, start: i32, end: i32, kind: SyntaxKind, out: &mut TreeSink, lazy: &impl LazyReparse) -> usize {
201        let (start, end) = (start as usize, end as usize);
202        let text = &self.text[self.lex_starts[start] as usize..self.lex_starts[end] as usize];
203        self.create_leaf(kind, start, end, text, out, lazy);
204        end
205    }
206
207    /// A leaf of `kind` over lexemes `start..end`, whose text is `text`.
208    fn create_leaf(
209        &self,
210        kind: SyntaxKind,
211        start: usize,
212        end: usize,
213        text: &str,
214        out: &mut TreeSink,
215        lazy: &impl LazyReparse,
216    ) {
217        let leaf = LazyLeaf { kind, text, outer: self, start, end };
218        if !lazy(&leaf, out) {
219            out.token(kind, leaf.text);
220        }
221    }
222
223    pub(crate) fn token_text(&self, lexeme: usize) -> &str {
224        &self.text[self.lex_starts[lexeme] as usize..self.lex_starts[lexeme + 1] as usize]
225    }
226}
227
228fn kind_of(kind: Option<SyntaxKind>) -> SyntaxKind {
229    kind.expect("Unbalanced tree. Most probably caused by unbalanced markers.")
230}