Skip to main content

ktrs_parser/builder/
layers.rs

1//! The adapter chain above `SemanticWhitespaceAwarePsiBuilderImpl`:
2//! `TruncatedSemanticWhitespaceAwarePsiBuilder` and `SemanticWhitespaceAwarePsiBuilderForByClause`
3//! as a stack of [`Layer`]s. The methods here are what parser code sees (the top of the chain).
4
5use ktrs_syntax::SyntaxKind;
6
7use super::semantic::SemanticWhitespaceAwarePsiBuilder;
8
9#[derive(Clone, Copy, Debug)]
10pub enum Layer {
11    /// `TruncatedSemanticWhitespaceAwarePsiBuilder(builder, eofPosition)`.
12    Truncated { eof_position: i32 },
13    /// `SemanticWhitespaceAwarePsiBuilderForByClause`; `stack_size` is its `getStackSize()`.
14    ForByClause { stack_size: i32 },
15}
16
17/// `isOffsetBeyondEof`.
18fn is_offset_beyond_eof(eof_position: i32, offset_from_current: i32) -> bool {
19    eof_position >= 0 && offset_from_current >= eof_position
20}
21
22impl SemanticWhitespaceAwarePsiBuilder {
23    pub fn push_layer(&mut self, layer: Layer) -> usize {
24        self.layers.push(layer);
25        self.layers.len() - 1
26    }
27
28    pub fn pop_layer(&mut self) {
29        self.layers.pop();
30    }
31
32    /// `getStackSize()` of the `ForByClause` layer at `index`.
33    pub fn for_by_clause_stack_size(&self, index: usize) -> i32 {
34        match self.layers[index] {
35            Layer::ForByClause { stack_size } => stack_size,
36            Layer::Truncated { .. } => unreachable!("layer {index} is not a by-clause layer"),
37        }
38    }
39
40    /// Every by-clause adapter on the delegation chain sees newline-state calls and counts them.
41    pub(super) fn count_newlines_call(&mut self, delta: i32) {
42        for layer in &mut self.layers {
43            if let Layer::ForByClause { stack_size } = layer {
44                *stack_size += delta;
45            }
46        }
47    }
48
49    fn top_truncated_eof_position(&self) -> Option<i32> {
50        self.layers.iter().rev().find_map(|l| match *l {
51            Layer::Truncated { eof_position } => Some(eof_position),
52            Layer::ForByClause { .. } => None,
53        })
54    }
55
56    pub fn eof(&mut self) -> bool {
57        let base = self.psi.eof();
58        if base || self.layers.is_empty() {
59            return base;
60        }
61        let offset = self.psi.get_current_offset();
62        self.layers.iter().any(|l| match *l {
63            Layer::Truncated { eof_position } => is_offset_beyond_eof(eof_position, offset),
64            Layer::ForByClause { .. } => false,
65        })
66    }
67
68    /// Inlined into every `at`: with no layers (the common case) it is the memo check.
69    #[inline]
70    pub fn get_token_type(&mut self) -> Option<SyntaxKind> {
71        if !self.layers.is_empty() {
72            return self.layered_get_token_type();
73        }
74        self.impl_get_token_type()
75    }
76
77    #[inline(never)]
78    fn layered_get_token_type(&mut self) -> Option<SyntaxKind> {
79        if self.top_truncated_eof_position().is_some() && self.eof() {
80            return None;
81        }
82        self.impl_get_token_type()
83    }
84
85    pub fn get_token_text(&mut self) -> Option<&str> {
86        if self.top_truncated_eof_position().is_some() && self.eof() {
87            return None;
88        }
89        self.impl_get_token_text()
90    }
91
92    pub fn look_ahead(&mut self, steps: i32) -> Option<SyntaxKind> {
93        let Some(eof_position) = self.top_truncated_eof_position() else {
94            return self.impl_look_ahead(steps);
95        };
96        if self.eof() {
97            return None;
98        }
99
100        let raw_look_ahead_steps = self.raw_look_ahead(steps);
101        if is_offset_beyond_eof(eof_position, self.psi.raw_token_type_start(raw_look_ahead_steps)) {
102            return None;
103        }
104
105        // Truncated lookahead is raw: complex tokens are not joined.
106        self.psi.raw_lookup(raw_look_ahead_steps)
107    }
108
109    /// `TruncatedSemanticWhitespaceAwarePsiBuilder.rawLookAhead`.
110    fn raw_look_ahead(&self, steps: i32) -> i32 {
111        let mut cur = 0;
112        let mut steps = steps;
113        while steps > 0 {
114            cur += 1;
115
116            let mut raw_token_type = self.psi.raw_lookup(cur);
117            while raw_token_type.is_some_and(|t| self.is_whitespace_or_comment(t)) {
118                cur += 1;
119                raw_token_type = self.psi.raw_lookup(cur);
120            }
121
122            steps -= 1;
123        }
124        cur
125    }
126}