ktrs_parser/parsing/
abstract_kotlin_parsing.rs1use ktrs_syntax::SyntaxKind::{self, *};
4
5use super::Parser;
6use crate::builder::{EdgeBinder, Layer, Marker};
7use crate::kt_tokens::{self, WHITE_SPACE_OR_COMMENT_BIT_SET};
8use crate::token_set::TokenSet;
9
10impl Parser {
11 pub(crate) fn get_last_token(&mut self) -> Option<SyntaxKind> {
12 let mut i = 1;
13 let current_offset = self.my_builder.get_current_offset();
14 while i <= current_offset && WHITE_SPACE_OR_COMMENT_BIT_SET.contains(self.my_builder.raw_lookup(-i)) {
15 i += 1;
16 }
17 self.my_builder.raw_lookup(-i)
18 }
19
20 pub(crate) fn expect_2(&mut self, expectation: SyntaxKind, message: &str) -> bool {
21 self.expect_3(expectation, message, None)
22 }
23
24 pub(crate) fn mark(&mut self) -> Marker {
25 self.my_builder.mark()
26 }
27
28 pub(crate) fn error(&mut self, message: &str) {
29 self.my_builder.error(message);
30 }
31
32 pub(crate) fn expect_3(&mut self, expectation: SyntaxKind, message: &str, recovery_set: Option<TokenSet>) -> bool {
33 if self.expect(expectation) {
34 return true;
35 }
36
37 self.error_with_recovery(message, recovery_set);
38
39 false
40 }
41
42 pub(crate) fn expect(&mut self, expectation: SyntaxKind) -> bool {
43 if self.at(expectation) {
44 self.advance(); return true;
46 }
47
48 if expectation == IDENTIFIER && self.my_builder.get_token_text() == Some("`") {
49 self.advance();
50 }
51
52 false
53 }
54
55 pub(crate) fn expect_no_advance(&mut self, expectation: SyntaxKind, message: &str) {
56 if self.at(expectation) {
57 self.advance(); return;
59 }
60
61 self.error(message);
62 }
63
64 pub(crate) fn error_with_recovery(&mut self, message: &str, recovery_set: Option<TokenSet>) {
65 let tt = self.tt();
66 let recover = match recovery_set {
67 None => true,
68 Some(set) => {
69 set.contains(tt)
70 || tt == Some(LBRACE)
71 || tt == Some(RBRACE)
72 || (set.contains(EOL_OR_SEMICOLON)
73 && (self.eof() || tt == Some(SEMICOLON) || self.my_builder.newline_before_current_token()))
74 }
75 };
76 if recover {
77 self.error(message);
78 } else {
79 self.error_and_advance(message);
80 }
81 }
82
83 pub(crate) fn error_and_advance(&mut self, message: &str) {
84 self.error_and_advance_2(message, 1);
85 }
86
87 pub(crate) fn error_and_advance_2(&mut self, message: &str, advance_token_count: i32) {
88 let err = self.mark();
89 self.advance_1(advance_token_count);
90 err.error(self, message);
91 }
92
93 pub(crate) fn eof(&mut self) -> bool {
94 self.my_builder.eof()
95 }
96
97 pub(crate) fn advance(&mut self) {
98 self.my_builder.advance_lexer();
99 }
100
101 pub(crate) fn advance_1(&mut self, advance_token_count: i32) {
102 for _ in 0..advance_token_count {
103 self.advance(); }
105 }
106
107 pub(crate) fn advance_at(&mut self, current: SyntaxKind) {
108 debug_assert!(self._at(current));
109 self.my_builder.advance_lexer();
110 }
111
112 pub(crate) fn get_token_id(&mut self) -> Option<SyntaxKind> {
114 self.tt()
115 }
116
117 #[inline]
118 pub(crate) fn tt(&mut self) -> Option<SyntaxKind> {
119 self.my_builder.get_token_type()
120 }
121
122 #[inline]
124 pub(crate) fn _at(&mut self, expectation: SyntaxKind) -> bool {
125 let token = self.tt();
126 self.token_matches(token, expectation)
127 }
128
129 #[inline]
130 fn token_matches(&mut self, token: Option<SyntaxKind>, expectation: SyntaxKind) -> bool {
131 if token == Some(expectation) {
132 return true;
133 }
134 if expectation == EOL_OR_SEMICOLON {
135 if self.eof() {
136 return true;
137 }
138 if token == Some(SEMICOLON) {
139 return true;
140 }
141 if self.my_builder.newline_before_current_token() {
142 return true;
143 }
144 }
145 false
146 }
147
148 #[inline]
149 pub(crate) fn at(&mut self, expectation: SyntaxKind) -> bool {
150 let token = self.tt();
151 if token == Some(expectation) {
152 return true;
153 }
154 if expectation != EOL_OR_SEMICOLON && expectation != IDENTIFIER && !kt_tokens::is_soft_keyword(expectation) {
156 return false;
157 }
158 self.at_rest(token, expectation)
159 }
160
161 #[inline(never)]
163 fn at_rest(&mut self, token: Option<SyntaxKind>, expectation: SyntaxKind) -> bool {
164 if self.token_matches(token, expectation) {
166 return true;
167 }
168 if token == Some(IDENTIFIER)
169 && kt_tokens::is_soft_keyword(expectation)
170 && expectation.keyword_text() == self.my_builder.get_token_text()
171 {
172 self.my_builder.remap_current_token(expectation);
173 return true;
174 }
175 if expectation == IDENTIFIER && token.is_some_and(kt_tokens::is_soft_keyword) {
176 self.my_builder.remap_current_token(IDENTIFIER);
177 return true;
178 }
179 false
180 }
181
182 pub(crate) fn _at_set(&mut self, set: TokenSet) -> bool {
184 let token = self.tt();
185 self.token_matches_set(token, set)
186 }
187
188 fn token_matches_set(&mut self, token: Option<SyntaxKind>, set: TokenSet) -> bool {
189 if set.contains(token) {
190 return true;
191 }
192 if set.contains(EOL_OR_SEMICOLON) {
193 if self.eof() {
194 return true;
195 }
196 if token == Some(SEMICOLON) {
197 return true;
198 }
199 if self.my_builder.newline_before_current_token() {
200 return true;
201 }
202 }
203 false
204 }
205
206 #[inline]
207 pub(crate) fn at_set(&mut self, set: TokenSet) -> bool {
208 let token = self.tt();
209 if set.contains(token) {
210 return true;
211 }
212 if !set.contains(EOL_OR_SEMICOLON) && !set.contains(IDENTIFIER) && !set.intersects(kt_tokens::SOFT_KEYWORDS) {
214 return false;
215 }
216 self.at_set_rest(token, set)
217 }
218
219 #[inline(never)]
221 fn at_set_rest(&mut self, token: Option<SyntaxKind>, set: TokenSet) -> bool {
222 if self.token_matches_set(token, set) {
224 return true;
225 }
226 if token == Some(IDENTIFIER) {
227 if !set.intersects(kt_tokens::SOFT_KEYWORDS) {
229 return false;
230 }
231 let keyword_token = kt_tokens::soft_keyword_by_text(self.my_builder.get_token_text());
232 if let Some(keyword_token) = keyword_token.filter(|&k| set.contains(k)) {
233 self.my_builder.remap_current_token(keyword_token);
234 return true;
235 }
236 } else {
237 if set.contains(IDENTIFIER) && token.is_some_and(kt_tokens::is_soft_keyword) {
239 self.my_builder.remap_current_token(IDENTIFIER);
240 return true;
241 }
242 }
243 false
244 }
245
246 pub(crate) fn lookahead(&mut self, k: i32) -> Option<SyntaxKind> {
247 self.my_builder.look_ahead(k)
248 }
249
250 pub(crate) fn consume_if(&mut self, token: SyntaxKind) -> bool {
251 if self.at(token) {
252 self.advance(); return true;
254 }
255 false
256 }
257
258 pub(crate) fn skip_until(&mut self, token_set: TokenSet) {
260 let stop_at_eol_or_semi = token_set.contains(EOL_OR_SEMICOLON);
261 while !self.eof() {
262 let tt = self.tt();
263 if token_set.contains(tt) || (stop_at_eol_or_semi && self.at(EOL_OR_SEMICOLON)) {
264 break;
265 }
266 self.advance();
267 }
268 }
269
270 pub(crate) fn error_until(&mut self, message: &str, token_set: TokenSet) {
271 debug_assert!(token_set.contains(LBRACE), "Cannot include LBRACE into error element!");
272 debug_assert!(token_set.contains(RBRACE), "Cannot include RBRACE into error element!");
273 let error = self.mark();
274 self.skip_until(token_set);
275 error.error(self, message);
276 }
277
278 pub(crate) fn error_if(&mut self, marker: Marker, condition: bool, message: &str) {
279 if condition {
280 marker.error(self, message);
281 } else {
282 marker.drop(self);
283 }
284 }
285
286 pub(crate) fn eol(&mut self) -> bool {
289 self.my_builder.newline_before_current_token() || self.eof()
290 }
291
292 pub(crate) fn close_declaration_with_comment_binders(
293 &mut self,
294 marker: Marker,
295 element_type: SyntaxKind,
296 preceding_non_doc_comments: bool,
297 ) {
298 marker.done(self, element_type);
299 let preceding =
300 if preceding_non_doc_comments { EdgeBinder::PrecedingComments } else { EdgeBinder::PrecedingDocComments };
301 marker.set_custom_edge_token_binders(self, Some(preceding), Some(EdgeBinder::TrailingComments));
302 }
303
304 pub(crate) fn create_truncated_builder<R>(&mut self, eof_position: i32, f: impl FnOnce(&mut Parser) -> R) -> R {
308 self.my_builder.push_layer(Layer::Truncated { eof_position });
309 self.with_context(true, None, f)
310 }
311
312 pub fn current_context(&mut self) -> String {
314 let offset = self.my_builder.get_current_offset() as usize;
315 let text = self.my_builder.get_original_text();
316 let start = floor_char_boundary(text, offset.saturating_sub(20));
317 let end = floor_char_boundary(text, (offset + 20).min(text.len()));
318 format!("{}<caret>{}", &text[start..offset], &text[offset..end])
319 }
320}
321
322fn floor_char_boundary(text: &str, mut index: usize) -> usize {
323 while !text.is_char_boundary(index) {
324 index -= 1;
325 }
326 index
327}
328