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::{MissedTokens, 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        let root = sink.len();
55        self.bind(root_kind, &skipped_errors, sink, lazy);
56        self.skipped_errors = skipped_errors;
57        if self.current_lexeme < self.lexeme_count() {
58            let tokens = self.lex_types[self.current_lexeme..].iter().map(|kind| kind.debug_name()).collect();
59            sink.missed_tokens.push(MissedTokens { element: root, tokens, text: self.text.to_string() });
60        }
61    }
62
63    fn balance_white_spaces(&mut self) {
64        let mut last_index: i32 = 0;
65        // `getLexemeIndexAt(i - 1)`, carried along: item i - 1's index as this loop left it.
66        let mut prev_index = self.production.get_lexeme_index_at(0);
67        let size = self.production.size().saturating_sub(1);
68        for i in 1..size {
69            let id = self.production.list[i];
70            let done = id < 0;
71            let item = self.production.marker(id);
72            assert!(done || item.is_error_item || item.is_done(), "Unbalanced tree: marker not done");
73
74            let binder = if item.is_error_item { EdgeBinder::DefaultRight } else { item.get_binder(done) };
75            let mut lexeme_index = item.get_lexeme_index(done);
76
77            // The default binders always land on the run's end (left) or start (right), so they
78            // skip scanning the other side; the result equals the general path's.
79            if binder == EdgeBinder::DefaultLeft {
80                lexeme_index = self.shift_over_whitespace_forward(lexeme_index as usize) as i32;
81                self.production.marker_mut(id).set_lexeme_index(lexeme_index, done);
82                (last_index, prev_index) = (lexeme_index, lexeme_index);
83                continue;
84            }
85            let prev_production_lex_index = prev_index;
86            let mut ws_start_index = lexeme_index.max(last_index);
87            while ws_start_index > prev_production_lex_index
88                && self.is_whitespace_or_comment(self.lex_types[ws_start_index as usize - 1])
89            {
90                ws_start_index -= 1;
91            }
92            if binder == EdgeBinder::DefaultRight {
93                self.production.marker_mut(id).set_lexeme_index(ws_start_index, done);
94                (last_index, prev_index) = (ws_start_index, ws_start_index);
95                continue;
96            }
97            let ws_end_index = self.shift_over_whitespace_forward(lexeme_index as usize) as i32;
98
99            if ws_start_index != ws_end_index {
100                // Production lexemes are monotonic, so the run is never inverted.
101                debug_assert!(ws_start_index < ws_end_index);
102                let (start, end) = (ws_start_index as usize, ws_end_index as usize);
103                let at_end = ws_start_index == 0 || end == self.lexeme_count();
104                let getter = |i: usize| self.token_text(start + i);
105                let edge = binder.get_edge_position(&self.lex_types[start..end], at_end, &getter);
106                lexeme_index = ws_start_index + edge as i32;
107                self.production.marker_mut(id).set_lexeme_index(lexeme_index, done);
108            } else if lexeme_index < ws_start_index {
109                lexeme_index = ws_start_index;
110                self.production.marker_mut(id).set_lexeme_index(ws_start_index, done);
111            }
112
113            last_index = lexeme_index;
114            prev_index = lexeme_index;
115        }
116    }
117
118    /// `prepareLightTree` keeps only the first (deepest) error item per lexeme, in production order.
119    fn duplicate_error_items(&self, skipped: &mut Vec<bool>) {
120        skipped.clear();
121        // `bind` only reads the flags of error items.
122        if !self.production.has_error_items() {
123            return;
124        }
125        skipped.resize(self.production.size(), false);
126        let mut last_error_index = -1;
127        for (i, &id) in self.production.list.iter().enumerate().skip(1) {
128            if id > 0 && self.production.marker(id).is_error_item {
129                let cur_token = self.production.marker(id).lexeme;
130                if cur_token != last_error_index {
131                    last_error_index = cur_token;
132                } else {
133                    skipped[i] = true;
134                }
135            }
136        }
137    }
138
139    /// Walks the production in order; equivalent to `bind` over the light tree.
140    fn bind(&self, root_kind: Option<SyntaxKind>, skipped_errors: &[bool], out: &mut TreeSink, lazy: &impl LazyReparse) {
141        let list = &self.production.list;
142        let root = self.production.marker(list[0]);
143        out.start_node(root_kind.unwrap_or_else(|| kind_of(root.kind)));
144        let mut depth = 1;
145        let mut lex_index = root.lexeme.max(0) as usize;
146
147        let mut i = 1;
148        while i < list.len() {
149            let id = list[i];
150            let item = self.production.marker(id);
151            if id < 0 {
152                lex_index = self.insert_leaves(lex_index, item.done_lexeme, out, lazy);
153                // Tokens after the root's done are dropped, as upstream (which LOG.errors: `MissedTokens`).
154                if id == -list[0] {
155                    break;
156                }
157                out.finish_node();
158                depth -= 1;
159            } else if item.is_error_item {
160                if !skipped_errors[i] {
161                    lex_index = self.insert_leaves(lex_index, item.lexeme, out, lazy);
162                    out.errors.push(self.production.message(id).unwrap_or_default().to_owned());
163                    out.start_node(SyntaxKind::ERROR_ELEMENT);
164                    out.finish_node();
165                }
166            } else {
167                lex_index = self.insert_leaves(lex_index, item.lexeme, out, lazy);
168                if item.collapsed {
169                    lex_index = self.collapse_leaves(item.lexeme, item.done_lexeme, kind_of(item.kind), out, lazy);
170                    i = list[i..].iter().position(|&x| x == -id).map_or(list.len(), |p| i + p);
171                } else {
172                    let kind = kind_of(item.kind);
173                    if kind == SyntaxKind::ERROR_ELEMENT {
174                        out.errors.push(self.production.message(id).expect("error marker without message").to_owned());
175                    }
176                    out.start_node(kind);
177                    depth += 1;
178                }
179            }
180            i += 1;
181        }
182        // Unbalanced markers are a parser bug upstream (LOG.error); close whatever is still open.
183        for _ in 0..depth {
184            out.finish_node();
185        }
186    }
187
188    fn insert_leaves(&self, cur_token: usize, last_idx: i32, out: &mut TreeSink, lazy: &impl LazyReparse) -> usize {
189        let last_idx = (last_idx.max(0) as usize).min(self.lexeme_count());
190        if cur_token >= last_idx {
191            return cur_token;
192        }
193        let kinds = &self.lex_types[cur_token..last_idx];
194        let starts = &self.lex_starts[cur_token..=last_idx];
195        for (i, (&kind, bounds)) in kinds.iter().zip(starts.windows(2)).enumerate() {
196            // Empty tokens are skipped (no Kotlin token type is an ILeafElementType).
197            if bounds[0] < bounds[1] {
198                let text = &self.text[bounds[0] as usize..bounds[1] as usize];
199                self.create_leaf(kind, cur_token + i, cur_token + i + 1, text, out, lazy);
200            }
201        }
202        last_idx
203    }
204
205    fn collapse_leaves(&self, start: i32, end: i32, kind: SyntaxKind, out: &mut TreeSink, lazy: &impl LazyReparse) -> usize {
206        let (start, end) = (start as usize, end as usize);
207        let text = &self.text[self.lex_starts[start] as usize..self.lex_starts[end] as usize];
208        self.create_leaf(kind, start, end, text, out, lazy);
209        end
210    }
211
212    /// A leaf of `kind` over lexemes `start..end`, whose text is `text`.
213    fn create_leaf(
214        &self,
215        kind: SyntaxKind,
216        start: usize,
217        end: usize,
218        text: &str,
219        out: &mut TreeSink,
220        lazy: &impl LazyReparse,
221    ) {
222        let leaf = LazyLeaf { kind, text, outer: self, start, end };
223        if !lazy(&leaf, out) {
224            out.token(kind, leaf.text);
225        }
226    }
227
228    pub(crate) fn token_text(&self, lexeme: usize) -> &str {
229        &self.text[self.lex_starts[lexeme] as usize..self.lex_starts[lexeme + 1] as usize]
230    }
231}
232
233fn kind_of(kind: Option<SyntaxKind>) -> SyntaxKind {
234    kind.expect("Unbalanced tree. Most probably caused by unbalanced markers.")
235}