ktrs_parser/builder/
semantic.rs1use ktrs_syntax::SyntaxKind::{self, *};
9
10use super::layers::Layer;
11use super::marker::{Marker, MarkerHost};
12use super::psi_builder::PsiBuilder;
13
14pub struct SemanticWhitespaceAwarePsiBuilder {
15 pub psi: PsiBuilder,
16 join_complex_tokens: BoolStack,
17 newlines_enabled: BoolStack,
18 pub(super) layers: Vec<Layer>,
19 tt_lexeme: usize,
23 tt: Option<SyntaxKind>,
24}
25
26struct BoolStack {
28 top: Option<bool>,
29 below: Vec<bool>,
30}
31
32impl BoolStack {
33 fn new(initial: bool) -> BoolStack {
34 BoolStack { top: Some(initial), below: Vec::new() }
35 }
36
37 fn push(&mut self, value: bool) {
38 if let Some(top) = self.top.replace(value) {
39 self.below.push(top);
40 }
41 }
42
43 fn pop(&mut self) {
44 self.top = self.below.pop();
45 }
46
47 fn peek(&self) -> bool {
48 self.top.expect("empty stack")
49 }
50
51 fn len(&self) -> usize {
52 self.below.len() + usize::from(self.top.is_some())
53 }
54}
55
56impl MarkerHost for SemanticWhitespaceAwarePsiBuilder {
57 fn psi_builder(&mut self) -> &mut PsiBuilder {
58 &mut self.psi
59 }
60}
61
62fn is_complex_token(kind: Option<SyntaxKind>) -> bool {
64 matches!(kind, Some(SAFE_ACCESS | ELVIS | EXCLEXCL))
65}
66
67impl SemanticWhitespaceAwarePsiBuilder {
68 pub fn new(psi: PsiBuilder) -> Self {
69 SemanticWhitespaceAwarePsiBuilder {
70 psi,
71 join_complex_tokens: BoolStack::new(true),
72 newlines_enabled: BoolStack::new(true),
73 layers: Vec::new(),
74 tt_lexeme: usize::MAX,
75 tt: None,
76 }
77 }
78
79 pub fn is_whitespace_or_comment(&self, kind: SyntaxKind) -> bool {
80 self.psi.is_whitespace_or_comment(kind)
81 }
82
83 pub fn newline_before_current_token(&mut self) -> bool {
84 if !self.newlines_enabled.peek() {
85 return false;
86 }
87
88 if self.psi.eof() {
89 return true;
90 }
91
92 let psi = &self.psi;
95 let mut prev = psi.current_lexeme;
96 while prev > 0 {
97 prev -= 1;
98 match psi.lex_types[prev] {
99 BLOCK_COMMENT | DOC_COMMENT | EOL_COMMENT | SHEBANG_COMMENT => continue,
100 WHITE_SPACE => {
101 if psi.token_text(prev).as_bytes().contains(&b'\n') {
102 return true;
103 }
104 }
105 _ => break,
106 }
107 }
108
109 false
110 }
111
112 pub fn disable_newlines(&mut self) {
113 self.newlines_enabled.push(false);
114 self.count_newlines_call(1);
115 }
116
117 pub fn enable_newlines(&mut self) {
118 self.newlines_enabled.push(true);
119 self.count_newlines_call(1);
120 }
121
122 pub fn restore_newlines_state(&mut self) {
123 assert!(self.newlines_enabled.len() > 1);
124 self.newlines_enabled.pop();
125 self.count_newlines_call(-1);
126 }
127
128 fn join_complex_tokens(&self) -> bool {
129 self.join_complex_tokens.peek()
130 }
131
132 pub fn restore_joining_complex_tokens_state(&mut self) {
133 self.join_complex_tokens.pop();
134 self.tt_lexeme = usize::MAX;
135 }
136
137 pub fn enable_joining_complex_tokens(&mut self) {
138 self.join_complex_tokens.push(true);
139 self.tt_lexeme = usize::MAX;
140 }
141
142 pub fn disable_joining_complex_tokens(&mut self) {
143 self.join_complex_tokens.push(false);
144 self.tt_lexeme = usize::MAX;
145 }
146
147 #[inline]
150 pub(super) fn impl_get_token_type(&mut self) -> Option<SyntaxKind> {
151 if self.tt_lexeme == self.psi.current_lexeme {
152 return self.tt;
153 }
154 self.impl_get_token_type_uncached()
155 }
156
157 #[inline(never)]
158 fn impl_get_token_type_uncached(&mut self) -> Option<SyntaxKind> {
159 let raw = self.psi.get_token_type();
160 let tt = if self.join_complex_tokens() { self.get_joined_token_type(raw, 1) } else { raw };
161 (self.tt_lexeme, self.tt) = (self.psi.current_lexeme, tt);
162 tt
163 }
164
165 #[inline]
166 fn get_joined_token_type(&self, raw_token_type: Option<SyntaxKind>, raw_lookup_steps: i32) -> Option<SyntaxKind> {
167 match raw_token_type {
168 Some(QUEST) => match self.psi.raw_lookup(raw_lookup_steps) {
169 Some(DOT) => return Some(SAFE_ACCESS),
170 Some(COLON) => return Some(ELVIS),
171 _ => {}
172 },
173 Some(EXCL) if self.psi.raw_lookup(raw_lookup_steps) == Some(EXCL) => return Some(EXCLEXCL),
174 _ => {}
175 }
176 raw_token_type
177 }
178
179 pub fn advance_lexer(&mut self) {
180 if !self.join_complex_tokens() {
181 self.psi.advance_lexer();
182 return;
183 }
184 let token_type = self.impl_get_token_type();
185 if is_complex_token(token_type) {
186 let mark = self.psi.mark();
187 self.psi.advance_lexer();
188 self.psi.advance_lexer();
189 mark.collapse(&mut self.psi, token_type.unwrap());
190 } else {
191 self.psi.advance_lexer();
192 }
193 }
194
195 pub(super) fn impl_get_token_text(&mut self) -> Option<&str> {
197 if self.join_complex_tokens() {
198 match self.impl_get_token_type() {
199 Some(ELVIS) => return Some("?:"),
200 Some(SAFE_ACCESS) => return Some("?."),
201 _ => {}
202 }
203 }
204 self.psi.get_token_text()
205 }
206
207 pub(super) fn impl_look_ahead(&mut self, steps: i32) -> Option<SyntaxKind> {
209 if !self.join_complex_tokens() {
210 return self.psi.look_ahead(steps);
211 }
212
213 if is_complex_token(self.impl_get_token_type()) {
214 return self.psi.look_ahead(steps + 1);
215 }
216 let raw = self.psi.look_ahead(steps);
217 self.get_joined_token_type(raw, 2)
219 }
220
221 pub fn mark(&mut self) -> Marker {
224 self.psi.mark()
225 }
226
227 pub fn error(&mut self, message: &str) {
228 self.psi.error(message);
229 }
230
231 pub fn raw_lookup(&self, steps: i32) -> Option<SyntaxKind> {
232 self.psi.raw_lookup(steps)
233 }
234
235 pub fn raw_token_type_start(&self, steps: i32) -> i32 {
236 self.psi.raw_token_type_start(steps)
237 }
238
239 pub fn raw_token_index(&self) -> i32 {
240 self.psi.raw_token_index()
241 }
242
243 pub fn get_current_offset(&mut self) -> i32 {
244 self.psi.get_current_offset()
245 }
246
247 pub fn remap_current_token(&mut self, kind: SyntaxKind) {
248 self.psi.remap_current_token(kind);
249 self.tt_lexeme = usize::MAX;
250 }
251
252 pub fn get_original_text(&self) -> &str {
253 self.psi.get_original_text()
254 }
255}