Skip to main content

rl_lang/parser/expressions/
primary.rs

1use crate::{
2    ast::{ExprId, nodes::ExpressionKind},
3    lexer::tokentypes::TokenType,
4    parser::parser_logic::Parser,
5    utils::errors::Error,
6};
7
8impl Parser {
9    /// Parses a primary expression - the highest-precedence, non-recursive forms.
10    ///
11    /// Handles (in order):
12    /// - **Identifiers** - plain names, module paths (`a::b::c`), function calls
13    ///   (`f(args)`), variable assignments (`x = expr`), index access (`arr[i]`),
14    ///   chained index access (`arr[i][j]`), index-assign (`arr[i] = expr`), and
15    ///   call-on-index (`fns[0](args)`).
16    /// - **Array literals** - `[a, b, c]`
17    /// - **Integer literals** - `42`
18    /// - **Byte literals** - `0b` style byte values
19    /// - **String literals** - `"hello"`
20    /// - **Character literals** - `'x'`
21    /// - **Boolean literals** - `true` / `false`
22    /// - **Float literals** - `3.14`
23    /// - **Null** - the `null` keyword
24    /// - **Grouped expressions** - `(expr)`
25    /// - **Lambda expressions** - `fn(params) -> T { body }`
26    ///
27    /// Every matched form is then passed through [`parse_postfix`] to handle
28    /// any trailing method-call chains.
29    ///
30    /// # Errors
31    /// Returns an error with the message `"expected expression"` if none of the
32    /// above forms match the current token.
33    ///
34    /// [`parse_postfix`]: Parser::parse_postfix
35    pub fn parse_primary(&mut self) -> Result<ExprId, Error> {
36        #[cfg(feature = "debug")]
37        log::debug!("current index: {:?}", self.current);
38        #[cfg(feature = "debug")]
39        log::debug!("current token: {:?}", self.peek());
40
41        let start = self.peek_span();
42
43        // ---- identifier start ----
44        if self.match_type(&[TokenType::Identifier(String::new())]) {
45            #[cfg(feature = "debug")]
46            log::debug!("found identifier");
47            let ident_span = self.previous_span();
48
49            if let TokenType::Identifier(first) = self.previous() {
50                // consume :: segments to build a module path
51                let mut path = vec![first];
52                while self.match_type(&[TokenType::ColonColon]) {
53                    if !self.match_type(&[TokenType::Identifier(String::new())]) {
54                        return Err(self.err("expected identifier after `::`", self.peek_span()));
55                    }
56                    if let TokenType::Identifier(seg) = self.previous() {
57                        path.push(seg);
58                    }
59                }
60                let path_span = start.join(self.previous_span());
61
62                // --- function call ---
63                if self.match_type(&[TokenType::LeftParen]) {
64                    #[cfg(feature = "debug")]
65                    log::debug!("found function call");
66                    let mut args = Vec::new();
67                    while self.match_type(&[TokenType::Newline]) {}
68                    if !(std::mem::discriminant(&self.peek())
69                        == std::mem::discriminant(&TokenType::RightParen))
70                    {
71                        loop {
72                            args.push(self.parse_expression()?);
73                            while self.match_type(&[TokenType::Newline]) {}
74                            if !self.match_type(&[TokenType::Comma]) {
75                                break;
76                            }
77                            while self.match_type(&[TokenType::Newline]) {}
78                        }
79                    }
80                    self.match_type(&[TokenType::RightParen]);
81                    let span = start.join(self.previous_span());
82                    #[cfg(feature = "debug")]
83                    log::trace!(
84                        "alloc Call expr: path={:?} args={} @ {:?}",
85                        path,
86                        args.len(),
87                        span
88                    );
89                    let expr = self
90                        .ast_arena
91                        .alloc_expr(ExpressionKind::Call { path, args }, span);
92
93                    return self.parse_postfix(expr, start);
94                }
95
96                // module paths are not first-class values
97                if path.len() > 1 {
98                    return Err(self.err(
99                        format!("module path `{}` used as value", path.join("::")),
100                        path_span,
101                    ));
102                }
103                let name = path.pop().unwrap();
104
105                // --- struct literal: Name { field: value, ... } ---
106                if self.record_names.contains(&name) && self.peek() == TokenType::LeftBrace {
107                    return self.parse_struct_literal(name, start);
108                }
109
110                // --- enum variant reference: Name.Variant ---
111                if self.tag_names.contains(&name) && self.peek() == TokenType::Dot {
112                    self.advance();
113                    let variant = match self.peek() {
114                        TokenType::Identifier(v) => {
115                            self.advance();
116                            v
117                        }
118                        _ => {
119                            return Err(
120                                self.err("expected variant name after `.`", self.peek_span())
121                            );
122                        }
123                    };
124                    let span = start.join(self.previous_span());
125                    #[cfg(feature = "debug")]
126                    log::trace!(
127                        "alloc EnumVariant expr: enum_name={:?} variant={:?} @ {:?}",
128                        name,
129                        variant,
130                        span
131                    );
132                    let expr = self.ast_arena.alloc_expr(
133                        ExpressionKind::EnumVariant {
134                            enum_name: name,
135                            variant,
136                        },
137                        span,
138                    );
139                    return self.parse_postfix(expr, start);
140                }
141
142                // --- assign expression ---
143                if self.match_type(&[TokenType::Assign]) {
144                    #[cfg(feature = "debug")]
145                    log::debug!("found variable assignment");
146                    let value = self.parse_expression()?;
147                    let value_id = self.ast_arena.exprs.get(value);
148                    let span = start.join(value_id.span);
149                    #[cfg(feature = "debug")]
150                    log::trace!(
151                        "alloc Assign expr: name={} value={:?} @ {:?}",
152                        name,
153                        value,
154                        span
155                    );
156                    let expr = self
157                        .ast_arena
158                        .alloc_expr(ExpressionKind::Assign { name, value }, span);
159
160                    return self.parse_postfix(expr, start);
161                }
162
163                // --- index ---
164                if self.match_type(&[TokenType::LeftBracket]) {
165                    #[cfg(feature = "debug")]
166                    log::trace!(
167                        "alloc Identifier(index target) expr: name={} @ {:?}",
168                        name,
169                        ident_span
170                    );
171
172                    let index = self.parse_expression()?;
173                    self.match_type(&[TokenType::RightBracket]);
174                    let after_index_span = self.previous_span();
175
176                    let target = self
177                        .ast_arena
178                        .alloc_expr(ExpressionKind::Identifier(name.clone()), ident_span);
179
180                    #[cfg(feature = "debug")]
181                    log::trace!(
182                        "alloc Index expr: target={:?} index={:?} @ {:?}",
183                        target,
184                        index,
185                        self.ast_arena.exprs.get(target).span
186                    );
187
188                    let mut expr = self.ast_arena.alloc_expr(
189                        ExpressionKind::Index { target, index },
190                        start.join(after_index_span),
191                    );
192
193                    // --- chained indices: arr[0][1][2] ---
194                    while self.peek() == TokenType::LeftBracket {
195                        self.advance();
196                        let next_index = self.parse_expression()?;
197                        self.match_type(&[TokenType::RightBracket]);
198                        let span = start.join(self.previous_span());
199
200                        #[cfg(feature = "debug")]
201                        log::trace!(
202                            "alloc Index(chained) expr: target={:?} index={:?} @ {:?}",
203                            expr,
204                            next_index,
205                            span
206                        );
207
208                        expr = self.ast_arena.alloc_expr(
209                            ExpressionKind::Index {
210                                target: expr,
211                                index: next_index,
212                            },
213                            span,
214                        );
215                    }
216
217                    // --- call on the result of an index: fns[0](arg) ---
218                    if self.match_type(&[TokenType::LeftParen]) {
219                        let mut args = Vec::new();
220                        while self.match_type(&[TokenType::Newline]) {}
221                        if self.peek() != TokenType::RightParen {
222                            loop {
223                                args.push(self.parse_expression()?);
224                                while self.match_type(&[TokenType::Newline]) {}
225                                if !self.match_type(&[TokenType::Comma]) {
226                                    break;
227                                }
228                                while self.match_type(&[TokenType::Newline]) {}
229                            }
230                        }
231                        while self.match_type(&[TokenType::Newline]) {}
232                        self.match_type(&[TokenType::RightParen]);
233                        let span = start.join(self.previous_span());
234                        #[cfg(feature = "debug")]
235                        log::trace!(
236                            "alloc CallExpr expr: callee={:?} args={} @ {:?}",
237                            expr,
238                            args.len(),
239                            span
240                        );
241
242                        let call_expr = self
243                            .ast_arena
244                            .alloc_expr(ExpressionKind::CallExpr { callee: expr, args }, span);
245
246                        return self.parse_postfix(call_expr, start);
247                    }
248
249                    // --- index assign ---
250                    if self.match_type(&[TokenType::Assign]) {
251                        #[cfg(feature = "debug")]
252                        log::debug!("found array item assignment");
253                        let value = self.parse_expression()?;
254
255                        let value_id = self.ast_arena.exprs.get(value);
256                        let expr_id = self.ast_arena.exprs.get(expr);
257
258                        let span = start.join(value_id.span);
259                        if let ExpressionKind::Index { target, index } = expr_id.kind.clone() {
260                            let expr = self.ast_arena.alloc_expr(
261                                ExpressionKind::IndexAssign {
262                                    target,
263                                    index,
264                                    value,
265                                },
266                                span,
267                            );
268
269                            #[cfg(feature = "debug")]
270                            log::trace!(
271                                "alloc IndexAssign expr: target={:?} index={:?} value={:?} @ {:?}",
272                                target,
273                                index,
274                                value,
275                                span
276                            );
277                            return self.parse_postfix(expr, start);
278                        }
279                    }
280
281                    return self.parse_postfix(expr, start);
282                }
283
284                // --- identifier ---
285                #[cfg(feature = "debug")]
286                log::trace!("alloc Identifier expr: name={} @ {:?}", name, ident_span);
287
288                let expr = self
289                    .ast_arena
290                    .alloc_expr(ExpressionKind::Identifier(name), ident_span);
291
292                return self.parse_postfix(expr, start);
293            }
294        }
295        // ---- identifier end ----
296
297        // --- map literal ---
298        if self.peek() == TokenType::LeftBrace {
299            self.advance();
300            let mut entries = Vec::new();
301            while self.match_type(&[TokenType::Newline]) {}
302            while self.peek() != TokenType::RightBrace {
303                let key = self.parse_expression()?;
304                while self.match_type(&[TokenType::Newline]) {}
305                if !self.match_type(&[TokenType::Colon]) {
306                    return Err(self.err("expected `:` after map key", self.peek_span()));
307                }
308                while self.match_type(&[TokenType::Newline]) {}
309                let value = self.parse_expression()?;
310                entries.push((key, value));
311                while self.match_type(&[TokenType::Newline]) {}
312                if self.peek() == TokenType::RightBrace {
313                    break;
314                }
315                if !self.match_type(&[TokenType::Comma]) {
316                    return Err(self.err("expected `,` between map entries", self.peek_span()));
317                }
318                while self.match_type(&[TokenType::Newline]) {}
319            }
320            self.match_type(&[TokenType::RightBrace]);
321            let span = start.join(self.previous_span());
322
323            #[cfg(feature = "debug")]
324            log::trace!(
325                "alloc MapLiteral expr: entries={} @ {:?}",
326                entries.len(),
327                span
328            );
329
330            let expr = self
331                .ast_arena
332                .alloc_expr(ExpressionKind::MapLiteral(entries), span);
333            return self.parse_postfix(expr, start);
334        }
335
336        // --- set literal ---
337        if self.match_type(&[TokenType::LeftBrace]) {
338            let mut items = Vec::new();
339            while self.match_type(&[TokenType::Newline]) {}
340            while self.peek() != TokenType::RightBrace {
341                items.push(self.parse_expression()?);
342                while self.match_type(&[TokenType::Newline]) {}
343                if self.peek() == TokenType::RightBrace {
344                    break;
345                }
346                if !self.match_type(&[TokenType::Comma]) {
347                    return Err(self.err("expected `,` between set items", self.peek_span()));
348                }
349                while self.match_type(&[TokenType::Newline]) {}
350            }
351            self.match_type(&[TokenType::RightBrace]);
352            let span = start.join(self.previous_span());
353
354            #[cfg(feature = "debug")]
355            log::trace!("alloc SetLiteral expr: items={} @ {:?}", items.len(), span);
356
357            let expr = self
358                .ast_arena
359                .alloc_expr(ExpressionKind::SetLiteral(items), span);
360            return self.parse_postfix(expr, start);
361        }
362
363        // --- array literal ---
364        if self.match_type(&[TokenType::LeftBracket]) {
365            let mut items = Vec::new();
366            while self.match_type(&[TokenType::Newline]) {}
367            while self.peek() != TokenType::RightBracket {
368                items.push(self.parse_expression()?);
369                while self.match_type(&[TokenType::Newline]) {}
370                if self.peek() == TokenType::RightBracket {
371                    break;
372                }
373                if !self.match_type(&[TokenType::Comma]) {
374                    return Err(self.err("expected `,` between array items", self.peek_span()));
375                }
376                while self.match_type(&[TokenType::Newline]) {}
377            }
378            self.match_type(&[TokenType::RightBracket]);
379            let span = start.join(self.previous_span());
380
381            #[cfg(feature = "debug")]
382            log::trace!(
383                "alloc ArrayLiteral expr: items={} @ {:?}",
384                items.len(),
385                span
386            );
387
388            let expr = self
389                .ast_arena
390                .alloc_expr(ExpressionKind::ArrayLiteral(items), span);
391            return self.parse_postfix(expr, start);
392        }
393
394        // ---- numbers start ----
395        // --- integer ---
396        if self.match_type(&[TokenType::NumberLiteral(0)]) {
397            #[cfg(feature = "debug")]
398            log::debug!("found number <integer>");
399            let span = self.previous_span();
400            if let TokenType::NumberLiteral(n) = self.previous() {
401                // ---- cast start ----
402                if self.match_type(&[TokenType::As]) {
403                    // from integer to T
404                    if self.match_type(&[TokenType::Int, TokenType::Byte, TokenType::Float]) {
405                        match self.previous() {
406                            TokenType::Int => {
407                                #[cfg(feature = "debug")]
408                                log::trace!(
409                                    "alloc Integer expr (from number, cast to int): {} @ {:?}",
410                                    n,
411                                    span
412                                );
413
414                                let int_expr =
415                                    self.ast_arena.alloc_expr(ExpressionKind::Integer(n), span);
416                                return self.parse_postfix(int_expr, start);
417                            }
418
419                            TokenType::Float => {
420                                #[cfg(feature = "debug")]
421                                log::trace!(
422                                    "alloc Float expr (from number, cast to float): {} @ {:?}",
423                                    n as f64,
424                                    span
425                                );
426                                let int_expr = self
427                                    .ast_arena
428                                    .alloc_expr(ExpressionKind::Float(n as f64), span);
429                                return self.parse_postfix(int_expr, start);
430                            }
431
432                            TokenType::Byte => {
433                                #[cfg(feature = "debug")]
434                                log::trace!(
435                                    "alloc Byte expr (from number, cast to byte): {} @ {:?}",
436                                    n as u8,
437                                    span
438                                );
439                                if !(0..=255).contains(&n) {
440                                    return Err(self
441                                        .err(format!("value {} is too large for byte", n), span));
442                                }
443                                let int_expr = self
444                                    .ast_arena
445                                    .alloc_expr(ExpressionKind::Byte(n as u8), span);
446                                return self.parse_postfix(int_expr, start);
447                            }
448
449                            other => {
450                                return Err(self.err(
451                                    format!("expected int/byte/float types found {:?}", other),
452                                    span,
453                                ));
454                            }
455                        }
456                    }
457                    return Err(self.err("expected type after `as`", self.previous_span()));
458                }
459                // ---- cast end ----
460
461                // no cast logic
462                #[cfg(feature = "debug")]
463                log::trace!(
464                    "alloc Integer expr (plain number literal): {} @ {:?}",
465                    n,
466                    span
467                );
468                let expr = self.ast_arena.alloc_expr(ExpressionKind::Integer(n), span);
469                return self.parse_postfix(expr, start);
470            }
471        }
472
473        // --- float ---
474        if self.match_type(&[TokenType::FloatLiteral(0.0)]) {
475            #[cfg(feature = "debug")]
476            log::debug!("found number <float>");
477            let span = self.previous_span();
478            if let TokenType::FloatLiteral(f) = self.previous() {
479                // ---- cast start ----
480                if self.match_type(&[TokenType::As]) {
481                    // from float to T
482                    if self.match_type(&[TokenType::Int, TokenType::Byte, TokenType::Float]) {
483                        match self.previous() {
484                            TokenType::Int => {
485                                #[cfg(feature = "debug")]
486                                log::trace!(
487                                    "alloc Integer expr (from float, cast to int): {} @ {:?}",
488                                    f as i64,
489                                    span
490                                );
491                                let float_expr = self
492                                    .ast_arena
493                                    .alloc_expr(ExpressionKind::Integer(f as i64), span);
494                                return self.parse_postfix(float_expr, start);
495                            }
496
497                            TokenType::Float => {
498                                #[cfg(feature = "debug")]
499                                log::trace!(
500                                    "alloc Float expr (from float, cast to float): {} @ {:?}",
501                                    f,
502                                    span
503                                );
504                                let float_expr =
505                                    self.ast_arena.alloc_expr(ExpressionKind::Float(f), span);
506                                return self.parse_postfix(float_expr, start);
507                            }
508
509                            TokenType::Byte => {
510                                #[cfg(feature = "debug")]
511                                log::trace!(
512                                    "alloc Byte expr (from float, cast to byte): {} @ {:?}",
513                                    f as u8,
514                                    span
515                                );
516                                if !(0.0..=255.0).contains(&f) {
517                                    return Err(self
518                                        .err(format!("value {} is too large for byte", f), span));
519                                }
520                                let float_expr = self
521                                    .ast_arena
522                                    .alloc_expr(ExpressionKind::Byte(f as u8), span);
523                                return self.parse_postfix(float_expr, start);
524                            }
525
526                            other => {
527                                return Err(self.err(
528                                    format!("expected int/byte/float types found {:?}", other),
529                                    span,
530                                ));
531                            }
532                        }
533                    }
534                    return Err(self.err("expected type after `as`", span));
535                }
536                // ---- cast end ----
537
538                // no cast logic
539                #[cfg(feature = "debug")]
540                log::trace!("alloc Float expr (plain float literal): {} @ {:?}", f, span);
541                let expr = self
542                    .ast_arena
543                    .alloc_expr(ExpressionKind::Float(f), self.previous_span());
544                return self.parse_postfix(expr, start);
545            }
546        }
547
548        // --- byte ---
549        if self.match_type(&[TokenType::ByteLiteral(0)]) {
550            #[cfg(feature = "debug")]
551            log::debug!("found number <byte>");
552            let span = self.previous_span();
553            if let TokenType::ByteLiteral(b) = self.previous() {
554                // ---- cast start ----
555                if self.match_type(&[TokenType::As]) {
556                    // from byte to T
557                    if self.match_type(&[TokenType::Int, TokenType::Byte, TokenType::Float]) {
558                        match self.previous() {
559                            TokenType::Int => {
560                                #[cfg(feature = "debug")]
561                                log::trace!(
562                                    "alloc Integer expr (from byte, cast to int): {} @ {:?}",
563                                    b as i64,
564                                    span
565                                );
566                                let byte_expr = self
567                                    .ast_arena
568                                    .alloc_expr(ExpressionKind::Integer(b as i64), span);
569                                return self.parse_postfix(byte_expr, start);
570                            }
571
572                            TokenType::Float => {
573                                #[cfg(feature = "debug")]
574                                log::trace!(
575                                    "alloc Float expr (from byte, cast to float): {} @ {:?}",
576                                    b as f64,
577                                    span
578                                );
579                                let byte_expr = self
580                                    .ast_arena
581                                    .alloc_expr(ExpressionKind::Float(b as f64), span);
582                                return self.parse_postfix(byte_expr, start);
583                            }
584
585                            TokenType::Byte => {
586                                // while it shouldn't be possible normally
587                                // keeping it as fallback for safety
588                                #[cfg(feature = "debug")]
589                                log::trace!(
590                                    "alloc Byte expr (from byte, cast to byte): {} @ {:?}",
591                                    b,
592                                    span
593                                );
594                                if !(0..=255).contains(&b) {
595                                    return Err(self
596                                        .err(format!("value {} is too large for byte", b), span));
597                                }
598                                let byte_expr =
599                                    self.ast_arena.alloc_expr(ExpressionKind::Byte(b), span);
600                                return self.parse_postfix(byte_expr, start);
601                            }
602
603                            other => {
604                                return Err(self.err(
605                                    format!("expected int/byte/float types found {:?}", other),
606                                    span,
607                                ));
608                            }
609                        }
610                    }
611                    return Err(self.err("expected type after `as`", self.previous_span()));
612                }
613                // ---- cast end ----
614
615                // no cast logic
616                #[cfg(feature = "debug")]
617                log::trace!("alloc Byte expr (plain byte literal): {} @ {:?}", b, span);
618                let expr = self.ast_arena.alloc_expr(ExpressionKind::Byte(b), span);
619                return self.parse_postfix(expr, start);
620            }
621        }
622        // ---- numbers end ----
623
624        // --- string ---
625        if self.match_type(&[TokenType::StringLiteral(String::new())]) {
626            #[cfg(feature = "debug")]
627            log::debug!("found string");
628            let span = self.previous_span();
629            if let TokenType::StringLiteral(s) = self.previous() {
630                #[cfg(feature = "debug")]
631                log::trace!("alloc String expr: {:?} @ {:?}", s, span);
632                let expr = self.ast_arena.alloc_expr(ExpressionKind::String(s), span);
633                return self.parse_postfix(expr, start);
634            }
635        }
636
637        // --- character ---
638        if matches!(
639            self.tokens[self.current].token,
640            TokenType::CharacterLiteral(_)
641        ) {
642            self.advance();
643            #[cfg(feature = "debug")]
644            log::debug!("found character");
645            let span = self.previous_span();
646            if let TokenType::CharacterLiteral(c) = self.previous() {
647                #[cfg(feature = "debug")]
648                log::trace!("alloc Character expr: {:?} @ {:?}", c, span);
649                let expr = self
650                    .ast_arena
651                    .alloc_expr(ExpressionKind::Character(c), span);
652                return self.parse_postfix(expr, start);
653            }
654        }
655
656        // --- boolean ---
657        if self.match_type(&[TokenType::BoolLiteral(false)]) {
658            let span = self.previous_span();
659            if let TokenType::BoolLiteral(b) = self.previous() {
660                let expr = self.ast_arena.alloc_expr(ExpressionKind::Bool(b), span);
661                #[cfg(feature = "debug")]
662                log::trace!("alloc Bool expr: {} @ {:?}", b, span);
663                return self.parse_postfix(expr, start);
664            }
665        }
666
667        // --- error ---
668        if self.match_type(&[TokenType::Error]) {
669            let error_start = self.previous_span();
670            while self.match_type(&[TokenType::Newline]) {}
671            if !self.match_type(&[TokenType::LeftParen]) {
672                return Err(self.err("expected `(` after `error`", self.peek_span()));
673            }
674            while self.match_type(&[TokenType::Newline]) {}
675            let inner = self.parse_expression()?;
676            while self.match_type(&[TokenType::Newline]) {}
677            if !self.match_type(&[TokenType::RightParen]) {
678                return Err(self.err("expected `)` after error value", self.peek_span()));
679            }
680            let span = error_start.join(self.previous_span());
681            let expr = self
682                .ast_arena
683                .alloc_expr(ExpressionKind::ErrorLiteral(inner), span);
684            #[cfg(feature = "debug")]
685            log::trace!("alloc ErrorLiteral expr: inner={:?} @ {:?}", inner, span);
686            return self.parse_postfix(expr, start);
687        }
688
689        // ---- result start ----
690        // --- ok ---
691        if self.match_type(&[TokenType::Ok]) {
692            let kw_span = self.previous_span();
693            while self.match_type(&[TokenType::Newline]) {}
694            if !self.match_type(&[TokenType::LeftParen]) {
695                return Err(self.err("expected `(` after `ok`", self.peek_span()));
696            }
697            while self.match_type(&[TokenType::Newline]) {}
698            let inner = self.parse_expression()?;
699            while self.match_type(&[TokenType::Newline]) {}
700            if !self.match_type(&[TokenType::RightParen]) {
701                return Err(self.err("expected `)` after ok value", self.peek_span()));
702            }
703            let span = kw_span.join(self.previous_span());
704            #[cfg(feature = "debug")]
705            log::trace!("alloc OkLiteral expr: inner={:?} @ {:?}", inner, span);
706            let ok_expr = self
707                .ast_arena
708                .alloc_expr(ExpressionKind::OkLiteral(inner), span);
709            return self.parse_postfix(ok_expr, start);
710        }
711
712        // --- err ---
713        if self.match_type(&[TokenType::Err]) {
714            let kw_span = self.previous_span();
715            while self.match_type(&[TokenType::Newline]) {}
716            if !self.match_type(&[TokenType::LeftParen]) {
717                return Err(self.err("expected `(` after `err`", self.peek_span()));
718            }
719            while self.match_type(&[TokenType::Newline]) {}
720            let inner = self.parse_expression()?;
721            while self.match_type(&[TokenType::Newline]) {}
722            if !self.match_type(&[TokenType::RightParen]) {
723                return Err(self.err("expected `)` after err value", self.peek_span()));
724            }
725            let span = kw_span.join(self.previous_span());
726            #[cfg(feature = "debug")]
727            log::trace!("alloc ErrLiteral expr: inner={:?} @ {:?}", inner, span);
728            let err_expr = self
729                .ast_arena
730                .alloc_expr(ExpressionKind::ErrLiteral(inner), span);
731            return self.parse_postfix(err_expr, start);
732        }
733        // ---- result end ----
734
735        // --- null ---
736        if self.match_type(&[TokenType::Null]) {
737            let span = self.previous_span();
738            let expr = self.ast_arena.alloc_expr(ExpressionKind::Null, span);
739            #[cfg(feature = "debug")]
740            log::trace!("alloc Null expr @ {:?}", span);
741            return self.parse_postfix(expr, start);
742        }
743
744        // --- group ---
745        if self.match_type(&[TokenType::LeftParen]) {
746            #[cfg(feature = "debug")]
747            log::debug!("found group start");
748            while self.match_type(&[TokenType::Newline]) {}
749            let first = self.parse_expression()?;
750
751            if self.match_type(&[TokenType::Comma]) {
752                // --- tuple literal ---
753                let mut items = vec![first];
754                while self.peek() != TokenType::RightParen && self.peek() != TokenType::Eof {
755                    while self.match_type(&[TokenType::Newline]) {}
756                    items.push(self.parse_expression()?);
757                    while self.match_type(&[TokenType::Newline]) {}
758                    if self.peek() == TokenType::RightParen {
759                        break;
760                    }
761                    if !self.match_type(&[TokenType::Comma]) {
762                        return Err(self.err("expected , between tuple elements", self.peek_span()));
763                    }
764                }
765                while self.match_type(&[TokenType::Newline]) {}
766                if !self.match_type(&[TokenType::RightParen]) {
767                    return Err(self.err("expected ) after tuple elements", self.peek_span()));
768                }
769                let span = start.join(self.previous_span());
770                #[cfg(feature = "debug")]
771                log::trace!(
772                    "alloc TupleLiteral expr: items={} @ {:?}",
773                    items.len(),
774                    span
775                );
776
777                let expr = self
778                    .ast_arena
779                    .alloc_expr(ExpressionKind::TupleLiteral(items), span);
780                return self.parse_postfix(expr, start);
781            }
782
783            // normal group
784            while self.match_type(&[TokenType::Newline]) {}
785            self.match_type(&[TokenType::RightParen]);
786
787            let span = start.join(self.previous_span());
788            let expr = self
789                .ast_arena
790                .alloc_expr(ExpressionKind::Grouping(first), span);
791            #[cfg(feature = "debug")]
792            log::trace!("alloc Grouping expr: inner={:?} @ {:?}", first, span);
793            return self.parse_postfix(expr, start);
794        }
795
796        // --- function/lambda ---
797        if self.match_type(&[TokenType::Fn]) {
798            let lambda_start = self.previous_span();
799            while self.match_type(&[TokenType::Newline]) {}
800            self.match_type(&[TokenType::LeftParen]);
801
802            let mut params: Vec<crate::ast::statements::Param> = Vec::new();
803            while self.match_type(&[TokenType::Newline]) {}
804            while !self.match_type(&[TokenType::RightParen]) {
805                let param_type = self.parse_param_type()?;
806                while self.match_type(&[TokenType::Newline]) {}
807                let param_name = match self.peek() {
808                    TokenType::Identifier(n) => {
809                        self.advance();
810                        n
811                    }
812                    _ => return Err(self.err("expected parameter name", self.peek_span())),
813                };
814                params.push(crate::ast::statements::Param {
815                    param_name,
816                    param_type,
817                });
818                while self.match_type(&[TokenType::Newline]) {}
819                if !self.match_type(&[TokenType::Comma]) {
820                    break;
821                }
822            }
823            while self.match_type(&[TokenType::Newline]) {}
824            self.match_type(&[TokenType::RightParen]);
825
826            while self.match_type(&[TokenType::Newline]) {}
827            let return_type = if self.match_type(&[TokenType::Arrow]) {
828                while self.match_type(&[TokenType::Newline]) {}
829                Some(self.parse_param_type()?)
830            } else {
831                None
832            };
833
834            while self.match_type(&[TokenType::Newline]) {}
835            let body = self.parse_block()?;
836            let span = lambda_start.join(self.previous_span());
837            #[cfg(feature = "debug")]
838            log::trace!(
839                "alloc Lambda expr: params={} return_type={:?} body_stmts={} @ {:?}",
840                params.len(),
841                return_type,
842                body.len(),
843                span
844            );
845            let expr = self.ast_arena.alloc_expr(
846                ExpressionKind::Lambda {
847                    params,
848                    return_type,
849                    body,
850                },
851                span,
852            );
853            return self.parse_postfix(expr, start);
854        }
855
856        // --- not valid expression ---
857        Err(self.err("expected expression", self.peek_span()))
858    }
859}