1use super::*;
2
3impl Parser {
4 fn is_upper_camel_segment(name: &str) -> bool {
5 name.chars().next().is_some_and(|c| c.is_uppercase())
6 }
7
8 fn is_constructor_path(path: &str) -> bool {
9 path.rsplit('.')
10 .next()
11 .is_some_and(Self::is_upper_camel_segment)
12 }
13
14 fn reject_zero_arg_constructor_call(&self, path: &str) -> Result<(), ParseError> {
15 if Self::is_constructor_path(path) && self.peek(1).kind == TokenKind::RParen {
16 return Err(self.error(format!(
17 "Zero-argument constructor call '{}()' is not allowed. Use '{}' (no parentheses).",
18 path, path
19 )));
20 }
21 Ok(())
22 }
23
24 fn spanned(&self, expr: Expr, line: usize) -> Spanned<Expr> {
26 Spanned::new(expr, line)
27 }
28
29 pub fn parse_expr(&mut self) -> Result<Spanned<Expr>, ParseError> {
30 self.enter_recursion()?;
38 let result = self.parse_comparison();
39 self.exit_recursion();
40 result
41 }
42
43 pub(super) fn parse_comparison(&mut self) -> Result<Spanned<Expr>, ParseError> {
44 let mut left = self.parse_additive()?;
45
46 loop {
47 let line = self.current().line;
48 let op = match &self.current().kind {
49 TokenKind::Eq => BinOp::Eq,
50 TokenKind::Neq => BinOp::Neq,
51 TokenKind::Lt => BinOp::Lt,
52 TokenKind::Gt => BinOp::Gt,
53 TokenKind::Lte => BinOp::Lte,
54 TokenKind::Gte => BinOp::Gte,
55 _ => break,
56 };
57 self.advance();
58 let right = self.parse_additive()?;
59 left = self.spanned(Expr::BinOp(op, Box::new(left), Box::new(right)), line);
60 }
61
62 Ok(left)
63 }
64
65 pub(super) fn parse_additive(&mut self) -> Result<Spanned<Expr>, ParseError> {
66 let mut left = self.parse_multiplicative()?;
67
68 loop {
69 let line = self.current().line;
70 let op = match &self.current().kind {
71 TokenKind::Plus => BinOp::Add,
72 TokenKind::Minus => BinOp::Sub,
73 _ => break,
74 };
75 self.advance();
76 let right = self.parse_multiplicative()?;
77 left = self.spanned(Expr::BinOp(op, Box::new(left), Box::new(right)), line);
78 }
79
80 Ok(left)
81 }
82
83 pub(super) fn parse_multiplicative(&mut self) -> Result<Spanned<Expr>, ParseError> {
84 let mut left = self.parse_unary()?;
85
86 loop {
87 let line = self.current().line;
88 let op = match &self.current().kind {
89 TokenKind::Star => BinOp::Mul,
90 TokenKind::Slash => BinOp::Div,
91 _ => break,
92 };
93 self.advance();
94 let right = self.parse_unary()?;
95 left = self.spanned(Expr::BinOp(op, Box::new(left), Box::new(right)), line);
96 }
97
98 Ok(left)
99 }
100
101 pub(super) fn parse_unary(&mut self) -> Result<Spanned<Expr>, ParseError> {
102 let mut neg_depth: u32 = 0;
108 let mut first_line = self.current().line;
109 while self.check_exact(&TokenKind::Minus) {
110 if neg_depth == 0 {
111 first_line = self.current().line;
112 }
113 self.advance();
114 neg_depth = neg_depth.saturating_add(1);
115 if neg_depth > super::MAX_PARSE_DEPTH {
116 return Err(self.error(format!(
117 "Unary minus chained too deeply (max {} levels). Refactor with named bindings.",
118 super::MAX_PARSE_DEPTH
119 )));
120 }
121 }
122 let mut operand = self.parse_postfix()?;
123 for _ in 0..neg_depth {
124 operand = self.spanned(Expr::Neg(Box::new(operand)), first_line);
125 }
126 Ok(operand)
127 }
128
129 pub(super) fn parse_postfix(&mut self) -> Result<Spanned<Expr>, ParseError> {
130 let mut expr = self.parse_call_or_atom()?;
131 let mut postfix_depth: u32 = 0;
141
142 loop {
143 if self.check_exact(&TokenKind::Question) && self.peek(1).kind == TokenKind::Bang {
144 let line = self.current().line;
146 if let Expr::Tuple(elements) = expr.node {
147 self.advance(); self.advance(); expr = self.spanned(Expr::IndependentProduct(elements, true), line);
150 } else {
151 return Err(self.error(
152 "Operator '?!' can only be applied to a tuple expression, e.g. (a, b)?!"
153 .to_string(),
154 ));
155 }
156 } else if self.check_exact(&TokenKind::Bang)
157 && !matches!(self.peek(1).kind, TokenKind::LBracket)
158 {
159 let line = self.current().line;
162 if let Expr::Tuple(elements) = expr.node {
163 self.advance(); expr = self.spanned(Expr::IndependentProduct(elements, false), line);
165 } else {
166 break; }
168 } else if self.check_exact(&TokenKind::Question) {
169 let line = self.current().line;
170 self.advance();
171 expr = self.spanned(Expr::ErrorProp(Box::new(expr)), line);
172 } else if self.check_exact(&TokenKind::Dot) {
173 let dot_line = self.current().line;
174 self.advance();
175 let field_tok = self.expect_kind(
176 &TokenKind::Ident(String::new()),
177 "Expected field name after '.'",
178 )?;
179 let field = match field_tok.kind {
180 TokenKind::Ident(s) => s,
181 _ => unreachable!(),
182 };
183 expr = self.spanned(Expr::Attr(Box::new(expr), field), dot_line);
184 if self.check_exact(&TokenKind::LParen) {
185 if let Some(path) = Self::dotted_name(&expr)
187 && path.ends_with(".update")
188 {
189 let prefix = &path[..path.len() - ".update".len()];
190 if !prefix.is_empty()
191 && prefix.chars().next().is_some_and(|c| c.is_uppercase())
192 {
193 let update_line = self.current().line;
194 self.advance(); let base = self.parse_expr()?;
196 let updates = if self.check_exact(&TokenKind::Comma) {
197 self.advance();
198 self.skip_formatting();
199 self.parse_record_create_fields()?
200 } else {
201 Vec::new()
202 };
203 self.expect_exact(&TokenKind::RParen)?;
204 expr = self.spanned(
205 Expr::RecordUpdate {
206 type_name: prefix.to_string(),
207 base: Box::new(base),
208 updates,
209 },
210 update_line,
211 );
212 continue;
213 }
214 }
215 if let Some(path) = Self::dotted_name(&expr) {
216 self.reject_zero_arg_constructor_call(&path)?;
217 }
218 let named_arg_start = matches!(&self.peek(1).kind, TokenKind::Ident(_))
219 && self.peek(2).kind == TokenKind::Assign;
220 if named_arg_start && let Some(path) = Self::dotted_name(&expr) {
221 let ctor_line = self.current().line;
223 self.advance();
224 let fields = self.parse_record_create_fields()?;
225 self.expect_exact(&TokenKind::RParen)?;
226 expr = self.spanned(
227 Expr::RecordCreate {
228 type_name: path,
229 fields,
230 },
231 ctor_line,
232 );
233 } else {
234 let call_line = self.current().line;
235 self.advance();
236 let args = self.parse_args()?;
237 self.expect_exact(&TokenKind::RParen)?;
238 expr = self.spanned(Expr::FnCall(Box::new(expr), args), call_line);
239 }
240 }
241 } else {
242 break;
243 }
244 postfix_depth = postfix_depth.saturating_add(1);
245 if postfix_depth > super::MAX_PARSE_DEPTH {
246 return Err(self.error(format!(
247 "Postfix chain too long (max {} steps). Refactor with named bindings; downstream walkers (typecheck, resolve, codegen) recurse into each step and exhaust the test-runner stack on longer chains.",
248 super::MAX_PARSE_DEPTH
249 )));
250 }
251 }
252
253 Ok(expr)
254 }
255
256 pub(super) fn dotted_name(expr: &Spanned<Expr>) -> Option<String> {
257 let mut segments: Vec<&str> = Vec::new();
266 let mut cur = expr;
267 loop {
268 match &cur.node {
269 Expr::Ident(name) => {
270 segments.push(name.as_str());
271 break;
272 }
273 Expr::Attr(inner, field) => {
274 segments.push(field.as_str());
275 cur = inner;
276 }
277 _ => return None,
278 }
279 }
280 segments.reverse();
281 Some(segments.join("."))
282 }
283
284 pub(super) fn parse_call_or_atom(&mut self) -> Result<Spanned<Expr>, ParseError> {
285 let atom = self.parse_atom()?;
286
287 if self.check_exact(&TokenKind::LParen) {
288 if let Some(path) = Self::dotted_name(&atom) {
289 self.reject_zero_arg_constructor_call(&path)?;
290 }
291
292 let is_record_create = if let Expr::Ident(ref name) = atom.node {
296 name.chars().next().is_some_and(|c| c.is_uppercase())
297 && matches!(&self.peek_skip_formatting(1).kind, TokenKind::Ident(_))
298 && self.peek_skip_formatting(2).kind == TokenKind::Assign
299 } else {
300 false
301 };
302 let named_arg_start = matches!(&self.peek_skip_formatting(1).kind, TokenKind::Ident(_))
303 && self.peek_skip_formatting(2).kind == TokenKind::Assign;
304
305 if is_record_create && let Expr::Ident(type_name) = atom.node {
306 let line = atom.line;
307 self.advance(); let fields = self.parse_record_create_fields()?;
309 self.expect_exact(&TokenKind::RParen)?;
310 return Ok(self.spanned(Expr::RecordCreate { type_name, fields }, line));
311 }
312
313 if named_arg_start && let Some(path) = Self::dotted_name(&atom) {
315 let line = atom.line;
316 self.advance();
317 let fields = self.parse_record_create_fields()?;
318 self.expect_exact(&TokenKind::RParen)?;
319 return Ok(self.spanned(
320 Expr::RecordCreate {
321 type_name: path,
322 fields,
323 },
324 line,
325 ));
326 }
327
328 let call_line = self.current().line;
329 self.advance();
330 let args = self.parse_args()?;
331 self.expect_exact(&TokenKind::RParen)?;
332 return Ok(self.spanned(Expr::FnCall(Box::new(atom), args), call_line));
333 }
334
335 Ok(atom)
336 }
337
338 pub(super) fn parse_record_create_fields(
340 &mut self,
341 ) -> Result<Vec<(String, Spanned<Expr>)>, ParseError> {
342 let mut fields = Vec::new();
343 self.skip_formatting();
344
345 while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
346 if self.check_exact(&TokenKind::Comma) {
347 self.advance();
348 self.skip_formatting();
349 continue;
350 }
351 let name_tok =
352 self.expect_kind(&TokenKind::Ident(String::new()), "Expected field name")?;
353 let field_name = match name_tok.kind {
354 TokenKind::Ident(s) => s,
355 _ => unreachable!(),
356 };
357 self.expect_exact(&TokenKind::Assign)?;
358 let value = self.parse_expr()?;
359 fields.push((field_name, value));
360 self.skip_formatting();
361 }
362
363 Ok(fields)
364 }
365
366 pub(super) fn parse_args(&mut self) -> Result<Vec<Spanned<Expr>>, ParseError> {
367 let mut args = Vec::new();
368 self.skip_formatting();
369
370 while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
371 if self.check_exact(&TokenKind::Comma) {
372 self.advance();
373 self.skip_formatting();
374 continue;
375 }
376 args.push(self.parse_expr()?);
377 self.skip_formatting();
378 }
379
380 Ok(args)
381 }
382
383 pub(super) fn parse_map_literal(&mut self) -> Result<Expr, ParseError> {
384 self.expect_exact(&TokenKind::LBrace)?;
385 let mut entries = Vec::new();
386 self.skip_formatting();
387
388 while !self.check_exact(&TokenKind::RBrace) && !self.is_eof() {
389 if self.check_exact(&TokenKind::Comma) {
390 self.advance();
391 self.skip_formatting();
392 continue;
393 }
394
395 let key = self.parse_expr()?;
396 self.skip_formatting();
397 if !self.check_exact(&TokenKind::FatArrow) {
398 return Err(
399 self.error("Expected '=>' between key and value in map literal".to_string())
400 );
401 }
402 self.advance(); self.skip_formatting();
404 let value = self.parse_expr()?;
405 entries.push((key, value));
406 self.skip_formatting();
407
408 if self.check_exact(&TokenKind::Comma) {
409 self.advance();
410 self.skip_formatting();
411 }
412 }
413
414 self.expect_exact(&TokenKind::RBrace)?;
415 Ok(Expr::MapLiteral(entries))
416 }
417
418 pub(super) fn parse_atom(&mut self) -> Result<Spanned<Expr>, ParseError> {
419 let line = self.current().line;
420 match self.current().kind.clone() {
421 TokenKind::Int(i) => {
422 self.advance();
423 Ok(self.spanned(Expr::Literal(Literal::Int(i)), line))
424 }
425 TokenKind::Float(f) => {
426 self.advance();
427 Ok(self.spanned(Expr::Literal(Literal::Float(f)), line))
428 }
429 TokenKind::Str(s) => {
430 self.advance();
431 Ok(self.spanned(Expr::Literal(Literal::Str(s)), line))
432 }
433 TokenKind::InterpStr(parts) => {
434 self.advance();
435 let mut str_parts = Vec::new();
436 for (is_expr, s) in parts {
437 if is_expr {
438 if s.trim().is_empty() {
440 str_parts.push(StrPart::Literal(String::new()));
441 } else {
442 let mut lexer = crate::lexer::Lexer::new(&s);
443 let tokens = lexer.tokenize().map_err(|e| ParseError::Error {
444 msg: format!("Error in interpolation: {}", e),
445 line: self.current().line,
446 col: self.current().col,
447 })?;
448 let mut sub_parser = Parser::new(tokens);
449 let expr = sub_parser.parse_expr().map_err(|e| ParseError::Error {
450 msg: format!("Error in interpolation: {}", e),
451 line: self.current().line,
452 col: self.current().col,
453 })?;
454 str_parts.push(StrPart::Parsed(Box::new(expr)));
455 }
456 } else {
457 str_parts.push(StrPart::Literal(s));
458 }
459 }
460 Ok(self.spanned(Expr::InterpolatedStr(str_parts), line))
461 }
462 TokenKind::Bool(b) => {
463 self.advance();
464 Ok(self.spanned(Expr::Literal(Literal::Bool(b)), line))
465 }
466 TokenKind::Match => {
467 let m = self.parse_match()?;
468 Ok(self.spanned(m, line))
469 }
470 TokenKind::LParen => {
471 self.advance();
472 let first = self.parse_expr()?;
473 if self.check_exact(&TokenKind::Comma) {
474 let mut items = vec![first];
475 while self.check_exact(&TokenKind::Comma) {
476 self.advance();
477 items.push(self.parse_expr()?);
478 }
479 self.expect_exact(&TokenKind::RParen)?;
480 Ok(self.spanned(Expr::Tuple(items), line))
481 } else {
482 self.expect_exact(&TokenKind::RParen)?;
483 Ok(first)
484 }
485 }
486 TokenKind::Ident(s) => {
487 self.advance();
488 if s == "Unit" {
489 Ok(self.spanned(Expr::Literal(Literal::Unit), line))
490 } else {
491 Ok(self.spanned(Expr::Ident(s), line))
492 }
493 }
494 TokenKind::LBracket => {
495 self.advance(); let mut elements = Vec::new();
497 self.skip_formatting();
498 while !self.check_exact(&TokenKind::RBracket) && !self.is_eof() {
499 if self.check_exact(&TokenKind::Comma) {
500 self.advance();
501 self.skip_formatting();
502 continue;
503 }
504 elements.push(self.parse_expr()?);
505 self.skip_formatting();
506 }
507 self.expect_exact(&TokenKind::RBracket)?;
508 Ok(self.spanned(Expr::List(elements), line))
509 }
510 TokenKind::LBrace => {
511 let map = self.parse_map_literal()?;
512 Ok(self.spanned(map, line))
513 }
514 TokenKind::Fn => Err(self.error(
515 "Anonymous functions are not supported in Aver. Define a top-level function and pass its name."
516 .to_string(),
517 )),
518 _ => Err(self.error(format!(
519 "Expected expression (identifier, literal, '[', or '{{'), found {}",
520 self.current().kind
521 ))),
522 }
523 }
524}