ktrs_parser/builder/
layers.rs1use ktrs_syntax::SyntaxKind;
6
7use super::semantic::SemanticWhitespaceAwarePsiBuilder;
8
9#[derive(Clone, Copy, Debug)]
10pub enum Layer {
11 Truncated { eof_position: i32 },
13 ForByClause { stack_size: i32 },
15}
16
17fn 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 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 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 #[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 self.psi.raw_lookup(raw_look_ahead_steps)
107 }
108
109 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}