1use super::*;
2
3impl Parser {
4 fn is_upper_camel_segment(name: &str) -> bool {
5 name.chars().next().map_or(false, |c| c.is_uppercase())
6 }
7
8 fn is_constructor_path(path: &str) -> bool {
9 path.rsplit('.')
10 .next()
11 .map_or(false, 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 pub fn parse_expr(&mut self) -> Result<Expr, ParseError> {
25 self.parse_pipe()
26 }
27
28 pub(super) fn parse_pipe(&mut self) -> Result<Expr, ParseError> {
32 let mut left = self.parse_comparison()?;
33
34 while self.check_exact(&TokenKind::Pipe) {
35 self.advance();
36 let right = self.parse_call_or_atom()?;
37 if matches!(right, Expr::FnCall(_, _)) {
38 return Err(self.error(
39 "Pipe right side must be a function reference (for example `f` or `Ns.f`), not a call (`f(...)`)."
40 .to_string(),
41 ));
42 }
43 left = Expr::Pipe(Box::new(left), Box::new(right));
44 }
45
46 Ok(left)
47 }
48
49 pub(super) fn parse_comparison(&mut self) -> Result<Expr, ParseError> {
50 let mut left = self.parse_additive()?;
51
52 loop {
53 let op = match &self.current().kind {
54 TokenKind::Eq => BinOp::Eq,
55 TokenKind::Neq => BinOp::Neq,
56 TokenKind::Lt => BinOp::Lt,
57 TokenKind::Gt => BinOp::Gt,
58 TokenKind::Lte => BinOp::Lte,
59 TokenKind::Gte => BinOp::Gte,
60 _ => break,
61 };
62 self.advance();
63 let right = self.parse_additive()?;
64 left = Expr::BinOp(op, Box::new(left), Box::new(right));
65 }
66
67 Ok(left)
68 }
69
70 pub(super) fn parse_additive(&mut self) -> Result<Expr, ParseError> {
71 let mut left = self.parse_multiplicative()?;
72
73 loop {
74 let op = match &self.current().kind {
75 TokenKind::Plus => BinOp::Add,
76 TokenKind::Minus => BinOp::Sub,
77 _ => break,
78 };
79 self.advance();
80 let right = self.parse_multiplicative()?;
81 left = Expr::BinOp(op, Box::new(left), Box::new(right));
82 }
83
84 Ok(left)
85 }
86
87 pub(super) fn parse_multiplicative(&mut self) -> Result<Expr, ParseError> {
88 let mut left = self.parse_unary()?;
89
90 loop {
91 let op = match &self.current().kind {
92 TokenKind::Star => BinOp::Mul,
93 TokenKind::Slash => BinOp::Div,
94 _ => break,
95 };
96 self.advance();
97 let right = self.parse_unary()?;
98 left = Expr::BinOp(op, Box::new(left), Box::new(right));
99 }
100
101 Ok(left)
102 }
103
104 pub(super) fn parse_unary(&mut self) -> Result<Expr, ParseError> {
105 if self.check_exact(&TokenKind::Minus) {
106 self.advance();
107 let operand = self.parse_postfix()?;
108 return Ok(Expr::BinOp(
109 BinOp::Sub,
110 Box::new(Expr::Literal(Literal::Int(0))),
111 Box::new(operand),
112 ));
113 }
114 self.parse_postfix()
115 }
116
117 pub(super) fn parse_postfix(&mut self) -> Result<Expr, ParseError> {
118 let mut expr = self.parse_call_or_atom()?;
119
120 loop {
121 if self.check_exact(&TokenKind::Question) {
122 self.advance();
123 expr = Expr::ErrorProp(Box::new(expr));
124 } else if self.check_exact(&TokenKind::Dot) {
125 self.advance();
126 let field_tok = self.expect_kind(
127 &TokenKind::Ident(String::new()),
128 "Expected field name after '.'",
129 )?;
130 let field = match field_tok.kind {
131 TokenKind::Ident(s) => s,
132 _ => unreachable!(),
133 };
134 expr = Expr::Attr(Box::new(expr), field);
135 if self.check_exact(&TokenKind::LParen) {
136 if let Some(path) = Self::dotted_name(&expr) {
138 if path.ends_with(".update") {
139 let prefix = &path[..path.len() - ".update".len()];
140 if !prefix.is_empty()
141 && prefix.chars().next().map_or(false, |c| c.is_uppercase())
142 {
143 self.advance(); let base = self.parse_expr()?;
145 let updates = if self.check_exact(&TokenKind::Comma) {
146 self.advance();
147 self.skip_formatting();
148 self.parse_record_create_fields()?
149 } else {
150 Vec::new()
151 };
152 self.expect_exact(&TokenKind::RParen)?;
153 expr = Expr::RecordUpdate {
154 type_name: prefix.to_string(),
155 base: Box::new(base),
156 updates,
157 };
158 continue;
159 }
160 }
161 }
162 if let Some(path) = Self::dotted_name(&expr) {
163 self.reject_zero_arg_constructor_call(&path)?;
164 }
165 let named_arg_start = matches!(&self.peek(1).kind, TokenKind::Ident(_))
166 && self.peek(2).kind == TokenKind::Assign;
167 if named_arg_start {
168 if let Some(path) = Self::dotted_name(&expr) {
169 if path == "Tcp.Connection" {
170 return Err(self.error(
171 "Cannot construct 'Tcp.Connection' directly. Use Tcp.connect(host, port)."
172 .to_string(),
173 ));
174 }
175 return Err(self.error(format!(
176 "Named-field call syntax is only valid for direct record constructors like User(...), not '{}(...)'",
177 path
178 )));
179 }
180 }
181 self.advance();
182 let args = self.parse_args()?;
183 self.expect_exact(&TokenKind::RParen)?;
184 expr = Expr::FnCall(Box::new(expr), args);
185 }
186 } else {
187 break;
188 }
189 }
190
191 Ok(expr)
192 }
193
194 pub(super) fn dotted_name(expr: &Expr) -> Option<String> {
195 match expr {
196 Expr::Ident(name) => Some(name.clone()),
197 Expr::Attr(inner, field) => {
198 let mut base = Self::dotted_name(inner)?;
199 base.push('.');
200 base.push_str(field);
201 Some(base)
202 }
203 _ => None,
204 }
205 }
206
207 pub(super) fn parse_call_or_atom(&mut self) -> Result<Expr, ParseError> {
208 let atom = self.parse_atom()?;
209
210 if self.check_exact(&TokenKind::LParen) {
211 if let Some(path) = Self::dotted_name(&atom) {
212 self.reject_zero_arg_constructor_call(&path)?;
213 }
214
215 let is_record_create = if let Expr::Ident(ref name) = atom {
219 name.chars().next().map_or(false, |c| c.is_uppercase())
220 && matches!(&self.peek_skip_formatting(1).kind, TokenKind::Ident(_))
221 && self.peek_skip_formatting(2).kind == TokenKind::Assign
222 } else {
223 false
224 };
225 let named_arg_start = matches!(&self.peek_skip_formatting(1).kind, TokenKind::Ident(_))
226 && self.peek_skip_formatting(2).kind == TokenKind::Assign;
227
228 if is_record_create {
229 if let Expr::Ident(type_name) = atom {
230 self.advance(); let fields = self.parse_record_create_fields()?;
232 self.expect_exact(&TokenKind::RParen)?;
233 return Ok(Expr::RecordCreate { type_name, fields });
234 }
235 }
236
237 if named_arg_start {
238 if let Some(path) = Self::dotted_name(&atom) {
239 if path == "Tcp.Connection" {
240 return Err(self.error(
241 "Cannot construct 'Tcp.Connection' directly. Use Tcp.connect(host, port)."
242 .to_string(),
243 ));
244 }
245 return Err(self.error(format!(
246 "Named-field call syntax is only valid for direct record constructors like User(...), not '{}(...)'",
247 path
248 )));
249 }
250 }
251
252 self.advance();
253 let args = self.parse_args()?;
254 self.expect_exact(&TokenKind::RParen)?;
255 return Ok(Expr::FnCall(Box::new(atom), args));
256 }
257
258 Ok(atom)
259 }
260
261 pub(super) fn parse_record_create_fields(&mut self) -> Result<Vec<(String, Expr)>, ParseError> {
263 let mut fields = Vec::new();
264 self.skip_formatting();
265
266 while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
267 if self.check_exact(&TokenKind::Comma) {
268 self.advance();
269 self.skip_formatting();
270 continue;
271 }
272 let name_tok =
273 self.expect_kind(&TokenKind::Ident(String::new()), "Expected field name")?;
274 let field_name = match name_tok.kind {
275 TokenKind::Ident(s) => s,
276 _ => unreachable!(),
277 };
278 self.expect_exact(&TokenKind::Assign)?;
279 let value = self.parse_expr()?;
280 fields.push((field_name, value));
281 self.skip_formatting();
282 }
283
284 Ok(fields)
285 }
286
287 pub(super) fn parse_args(&mut self) -> Result<Vec<Expr>, ParseError> {
288 let mut args = Vec::new();
289 self.skip_formatting();
290
291 while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
292 if self.check_exact(&TokenKind::Comma) {
293 self.advance();
294 self.skip_formatting();
295 continue;
296 }
297 args.push(self.parse_expr()?);
298 self.skip_formatting();
299 }
300
301 Ok(args)
302 }
303
304 pub(super) fn parse_map_literal(&mut self) -> Result<Expr, ParseError> {
305 self.expect_exact(&TokenKind::LBrace)?;
306 let mut entries = Vec::new();
307 self.skip_formatting();
308
309 while !self.check_exact(&TokenKind::RBrace) && !self.is_eof() {
310 if self.check_exact(&TokenKind::Comma) {
311 self.advance();
312 self.skip_formatting();
313 continue;
314 }
315
316 let key = self.parse_expr()?;
317 self.skip_formatting();
318 if !self.check_exact(&TokenKind::FatArrow) {
319 return Err(
320 self.error("Expected '=>' between key and value in map literal".to_string())
321 );
322 }
323 self.advance(); self.skip_formatting();
325 let value = self.parse_expr()?;
326 entries.push((key, value));
327 self.skip_formatting();
328
329 if self.check_exact(&TokenKind::Comma) {
330 self.advance();
331 self.skip_formatting();
332 }
333 }
334
335 self.expect_exact(&TokenKind::RBrace)?;
336 Ok(Expr::MapLiteral(entries))
337 }
338
339 pub(super) fn parse_atom(&mut self) -> Result<Expr, ParseError> {
340 match self.current().kind.clone() {
341 TokenKind::Int(i) => {
342 self.advance();
343 Ok(Expr::Literal(Literal::Int(i)))
344 }
345 TokenKind::Float(f) => {
346 self.advance();
347 Ok(Expr::Literal(Literal::Float(f)))
348 }
349 TokenKind::Str(s) => {
350 self.advance();
351 Ok(Expr::Literal(Literal::Str(s)))
352 }
353 TokenKind::InterpStr(parts) => {
354 self.advance();
355 let mut str_parts = Vec::new();
356 for (is_expr, s) in parts {
357 if is_expr {
358 if s.trim().is_empty() {
360 str_parts.push(StrPart::Literal(String::new()));
361 } else {
362 let mut lexer = crate::lexer::Lexer::new(&s);
363 let tokens = lexer.tokenize().map_err(|e| ParseError::Error {
364 msg: format!("Error in interpolation: {}", e),
365 line: self.current().line,
366 col: self.current().col,
367 })?;
368 let mut sub_parser = Parser::new(tokens);
369 let expr = sub_parser.parse_expr().map_err(|e| ParseError::Error {
370 msg: format!("Error in interpolation: {}", e),
371 line: self.current().line,
372 col: self.current().col,
373 })?;
374 str_parts.push(StrPart::Parsed(Box::new(expr)));
375 }
376 } else {
377 str_parts.push(StrPart::Literal(s));
378 }
379 }
380 Ok(Expr::InterpolatedStr(str_parts))
381 }
382 TokenKind::Bool(b) => {
383 self.advance();
384 Ok(Expr::Literal(Literal::Bool(b)))
385 }
386 TokenKind::Match => self.parse_match(),
387 TokenKind::LParen => {
388 self.advance();
389 let first = self.parse_expr()?;
390 if self.check_exact(&TokenKind::Comma) {
391 let mut items = vec![first];
392 while self.check_exact(&TokenKind::Comma) {
393 self.advance();
394 items.push(self.parse_expr()?);
395 }
396 self.expect_exact(&TokenKind::RParen)?;
397 Ok(Expr::Tuple(items))
398 } else {
399 self.expect_exact(&TokenKind::RParen)?;
400 Ok(first)
401 }
402 }
403 TokenKind::Ident(s) => {
404 self.advance();
405 Ok(Expr::Ident(s))
406 }
407 TokenKind::LBracket => {
408 self.advance(); let mut elements = Vec::new();
410 self.skip_formatting();
411 while !self.check_exact(&TokenKind::RBracket) && !self.is_eof() {
412 if self.check_exact(&TokenKind::Comma) {
413 self.advance();
414 self.skip_formatting();
415 continue;
416 }
417 elements.push(self.parse_expr()?);
418 self.skip_formatting();
419 }
420 self.expect_exact(&TokenKind::RBracket)?;
421 Ok(Expr::List(elements))
422 }
423 TokenKind::LBrace => self.parse_map_literal(),
424 TokenKind::Fn => Err(self.error(
425 "Anonymous functions are not supported in Aver. Define a top-level function and pass its name."
426 .to_string(),
427 )),
428 _ => Err(self.error(format!(
429 "Expected expression (identifier, literal, '[', or '{{'), found {}",
430 self.current().kind
431 ))),
432 }
433 }
434}