1use ecow::EcoString;
2
3use super::{ParseError, Parser};
4use crate::ast;
5use crate::lex::TokenKind::{self, *};
6use crate::types::Type;
7
8const RANGE_PREC: u8 = 6;
9const CAST_PREC: u8 = 9;
10
11impl<'source> Parser<'source> {
12 pub fn pratt_parse(&mut self, min_prec: u8) -> ast::Expression {
22 if !self.enter_recursion() {
23 let span = self.span_from_token(self.current_token());
24 self.resync_on_error();
25 return ast::Expression::Unit {
26 ty: Type::uninferred(),
27 span,
28 };
29 }
30
31 let start = self.current_token();
32 let mut lhs = self.parse_left_hand_side();
33
34 while !self.at_eof() && !self.too_many_errors() {
35 if self.check_go_channel_send() {
36 self.leave_recursion();
37 return lhs;
38 }
39
40 if self.at_range() && RANGE_PREC > min_prec {
41 lhs = self.parse_range(Some(lhs.into()), start);
42 continue;
43 }
44
45 if self.current_token().kind == As && CAST_PREC > min_prec {
46 self.next();
47 let target_type = self.parse_annotation();
48 lhs = ast::Expression::Cast {
49 expression: lhs.into(),
50 target_type,
51 ty: Type::uninferred(),
52 span: self.span_from_tokens(start),
53 };
54 continue;
55 }
56
57 if min_prec == 0
58 && self.current_token().kind == PipeDouble
59 && self.newline_before_current()
60 {
61 break;
62 }
63
64 if let Some(prec) = self.binary_operator_precedence(self.current_token().kind)
65 && prec > min_prec
66 {
67 let operator = self.parse_binary_operator();
68 let rhs = self.pratt_parse(prec);
69 lhs = ast::Expression::Binary {
70 operator,
71 left: lhs.into(),
72 right: rhs.into(),
73 ty: Type::uninferred(),
74 span: self.span_from_tokens(start),
75 };
76 continue;
77 }
78
79 if self.is_postfix_operator(&lhs) {
80 if self.is_format_string(&lhs)
81 && (self.current_token().kind == LeftParen
82 || self.current_token().kind == LeftSquareBracket)
83 && self.newline_before_current()
84 {
85 break;
86 }
87 lhs = self.include_in_larger_expression(lhs);
88 continue;
89 }
90
91 if matches!(self.current_token().kind, Ampersand | Pipe | Caret)
92 && !self.newline_before_current()
93 {
94 let op_token = self.current_token();
95 let span = self.span_from_token(op_token);
96 let error = ParseError::new(
97 "Unsupported operator",
98 span,
99 format!("`{}` is not a supported binary operator", op_token.text),
100 )
101 .with_help("Lisette does not support bitwise operators")
102 .with_parse_code("unsupported_operator");
103 self.errors.push(error);
104 self.next();
105 let _rhs = self.pratt_parse(min_prec);
106 continue;
107 }
108
109 break;
110 }
111
112 self.leave_recursion();
113
114 lhs
115 }
116
117 fn prefix_operator_precedence(&self, kind: TokenKind) -> u8 {
118 match kind {
119 Minus | Bang | Ampersand => 15,
120 _ => {
121 debug_assert!(false, "unexpected prefix operator: {:?}", kind);
122 15
123 }
124 }
125 }
126
127 fn binary_operator_precedence(&self, kind: TokenKind) -> Option<u8> {
128 match kind {
129 LeftAngleBracket if self.is_type_args_call() => None,
130 Pipeline => Some(1),
131 PipeDouble if self.stream.peek_ahead(1).kind == Arrow => None,
132 PipeDouble => Some(3),
133 AmpersandDouble => Some(4),
134 EqualDouble | NotEqual | LeftAngleBracket | RightAngleBracket | LessThanOrEqual
135 | GreaterThanOrEqual => Some(5),
136 Plus | Minus => Some(7),
137 Star | Slash | Percent => Some(8),
138 _ => None,
139 }
140 }
141
142 fn is_postfix_operator(&self, lhs: &ast::Expression) -> bool {
143 match self.current_token().kind {
144 LeftParen | LeftSquareBracket | QuestionMark | Dot => true,
145 LeftCurlyBrace => match lhs {
146 ast::Expression::Identifier { .. } | ast::Expression::DotAccess { .. } => {
147 self.is_struct_instantiation()
148 }
149 _ => false,
150 },
151 LeftAngleBracket => self.is_type_args_call(),
152 Colon if self.stream.peek_ahead(1).kind == Colon => true,
153 _ => false,
154 }
155 }
156
157 fn is_format_string(&self, expression: &ast::Expression) -> bool {
158 matches!(
159 expression,
160 ast::Expression::Literal {
161 literal: ast::Literal::FormatString(_),
162 ..
163 }
164 )
165 }
166
167 fn parse_left_hand_side(&mut self) -> ast::Expression {
168 let start = self.current_token();
169
170 match start.kind {
171 Bang | Minus => {
172 self.next();
173
174 let operator = if start.kind == Bang {
175 ast::UnaryOperator::Not
176 } else {
177 ast::UnaryOperator::Negative
178 };
179
180 let prec = self.prefix_operator_precedence(start.kind);
181
182 ast::Expression::Unary {
183 operator,
184 expression: self.pratt_parse(prec).into(),
185 ty: Type::uninferred(),
186 span: self.span_from_tokens(start),
187 }
188 }
189
190 Ampersand => {
191 self.next();
192 if self.current_token().kind == Mut {
193 let span = ast::Span::new(
194 self.file_id,
195 start.byte_offset,
196 self.current_token().byte_offset + self.current_token().byte_length
197 - start.byte_offset,
198 );
199 self.track_error_at(
200 span,
201 "invalid syntax",
202 "Lisette has no mutable references. Use `&x` instead",
203 );
204 self.next(); }
206 let prec = self.prefix_operator_precedence(start.kind);
207 ast::Expression::Reference {
208 expression: self.pratt_parse(prec).into(),
209 ty: Type::uninferred(),
210 span: self.span_from_tokens(start),
211 }
212 }
213
214 _ => self.parse_atomic_expression(),
215 }
216 }
217
218 pub fn include_in_larger_expression(&mut self, lhs: ast::Expression) -> ast::Expression {
219 match self.current_token().kind {
220 LeftParen => self.parse_function_call(lhs, vec![]),
221 LeftSquareBracket => self.parse_index_expression(lhs),
222 LeftCurlyBrace => self.parse_struct_call(lhs),
223 QuestionMark => self.parse_try(lhs),
224 Dot => self.parse_field_access(lhs),
225 LeftAngleBracket => {
226 let type_args = self.parse_type_args();
227
228 if self.current_token().kind == Dot && self.stream.peek_ahead(1).kind == Identifier
229 {
230 let type_name = match &lhs {
231 ast::Expression::Identifier { value, .. } => value.as_str(),
232 ast::Expression::DotAccess { member, .. } => member.as_str(),
233 _ => "",
234 };
235 let method = self.stream.peek_ahead(1).text;
236 let args_str = type_args
237 .iter()
238 .map(format_annotation)
239 .collect::<Vec<_>>()
240 .join(", ");
241 let plural = type_args.len() != 1;
242 let title = if plural {
243 "Misplaced type arguments"
244 } else {
245 "Misplaced type argument"
246 };
247 let help = if !type_name.is_empty() {
248 format!(
249 "Set the type {} on the method: `{}.{}<{}>()`",
250 if plural { "arguments" } else { "argument" },
251 type_name,
252 method,
253 args_str,
254 )
255 } else {
256 format!(
257 "Set the type {} on the method: `.{}<{}>()`",
258 if plural { "arguments" } else { "argument" },
259 method,
260 args_str,
261 )
262 };
263 let Some(first) = type_args.first() else {
264 return self.parse_function_call(lhs, type_args);
265 };
266 let first_span = first.get_span();
267 let last_span = type_args.last().expect("non-empty").get_span();
268 let span = ast::Span::new(
269 self.file_id,
270 first_span.byte_offset,
271 (last_span.byte_offset + last_span.byte_length)
272 .saturating_sub(first_span.byte_offset),
273 );
274 let error = ParseError::new(title, span, "misplaced")
275 .with_parse_code("syntax_error")
276 .with_help(help);
277 self.errors.push(error);
278
279 let dot_access = self.parse_field_access(lhs);
280 return self.parse_function_call(dot_access, type_args);
281 }
282
283 self.parse_function_call(lhs, type_args)
284 }
285
286 Colon => {
287 let lhs_name = match &lhs {
288 ast::Expression::Identifier { value, .. } => value.to_string(),
289 ast::Expression::DotAccess { member, .. } => member.to_string(),
290 _ => std::string::String::new(),
291 };
292 let colon_token = self.current_token();
293 let span = ast::Span::new(self.file_id, colon_token.byte_offset, 2);
294 let after = self.stream.peek_ahead(2);
295
296 if after.kind == LeftAngleBracket {
297 let help = if !lhs_name.is_empty() {
298 format!(
299 "Lisette does not use turbofish syntax. Use `{}<T>(...)` instead",
300 lhs_name
301 )
302 } else {
303 "Lisette does not use turbofish syntax. Use `func<T>(...)` instead"
304 .to_string()
305 };
306 self.track_error_at(span, "invalid syntax", help);
307 self.next(); self.next(); let type_args = self.parse_type_args();
310 self.parse_function_call(lhs, type_args)
311 } else {
312 let help = if !lhs_name.is_empty() && after.kind == Identifier {
313 format!(
314 "Use `.` instead of `::` for enum variant access, e.g. `{}.{}`",
315 lhs_name, after.text
316 )
317 } else {
318 "Use `.` instead of `::` for enum variant access".to_string()
319 };
320 self.track_error_at(span, "invalid syntax", help);
321 self.next(); self.next(); let field_start = self.current_token();
324 let field: EcoString = self.current_token().text.into();
325 self.ensure(Identifier);
326 ast::Expression::DotAccess {
327 ty: Type::uninferred(),
328 expression: lhs.into(),
329 member: field,
330 span: self.span_from_tokens(field_start),
331 }
332 }
333 }
334
335 _ => {
336 debug_assert!(
337 false,
338 "is_postfix_operator and include_in_larger_expression are out of sync"
339 );
340 self.track_error("internal error", "Unexpected token in postfix position");
341 self.resync_on_error();
342 lhs
343 }
344 }
345 }
346
347 pub fn parse_range_end(&mut self) -> ast::Expression {
348 self.pratt_parse(RANGE_PREC)
349 }
350
351 fn check_go_channel_send(&mut self) -> bool {
352 if self.current_token().kind != LeftAngleBracket {
353 return false;
354 }
355 let next = self.stream.peek_ahead(1);
356 if next.kind != Minus {
357 return false;
358 }
359 let current = self.current_token();
360 if current.byte_offset + current.byte_length != next.byte_offset {
361 return false;
362 }
363
364 let span = ast::Span::new(
365 self.file_id,
366 self.current_token().byte_offset,
367 self.current_token().byte_length + 1,
368 );
369 self.track_error_at(
370 span,
371 "invalid syntax",
372 "Use `ch.Send(value)` inside a `select` expression",
373 );
374 self.resync_on_error();
375 true
376 }
377}
378
379fn format_annotation(ann: &ast::Annotation) -> std::string::String {
380 match ann {
381 ast::Annotation::Constructor { name, params, .. } => {
382 if params.is_empty() {
383 name.to_string()
384 } else {
385 format!(
386 "{}<{}>",
387 name,
388 params
389 .iter()
390 .map(format_annotation)
391 .collect::<Vec<_>>()
392 .join(", ")
393 )
394 }
395 }
396 ast::Annotation::Tuple { elements, .. } => {
397 format!(
398 "({})",
399 elements
400 .iter()
401 .map(format_annotation)
402 .collect::<Vec<_>>()
403 .join(", ")
404 )
405 }
406 ast::Annotation::Function {
407 params,
408 return_type,
409 ..
410 } => {
411 format!(
412 "fn({}) -> {}",
413 params
414 .iter()
415 .map(format_annotation)
416 .collect::<Vec<_>>()
417 .join(", "),
418 format_annotation(return_type)
419 )
420 }
421 ast::Annotation::Unknown | ast::Annotation::Opaque { .. } => "_".to_string(),
422 }
423}