Skip to main content

harn_parser/
parser.rs

1use crate::ast::*;
2use harn_lexer::{Span, Token, TokenKind};
3use std::fmt;
4
5/// Parser errors.
6#[derive(Debug, Clone, PartialEq)]
7pub enum ParserError {
8    Unexpected {
9        got: String,
10        expected: String,
11        span: Span,
12    },
13    UnexpectedEof {
14        expected: String,
15    },
16}
17
18impl fmt::Display for ParserError {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            ParserError::Unexpected {
22                got,
23                expected,
24                span,
25            } => write!(
26                f,
27                "Expected {expected}, got {got} at {}:{}",
28                span.line, span.column
29            ),
30            ParserError::UnexpectedEof { expected } => {
31                write!(f, "Unexpected end of file, expected {expected}")
32            }
33        }
34    }
35}
36
37impl std::error::Error for ParserError {}
38
39/// Recursive descent parser for Harn.
40pub struct Parser {
41    tokens: Vec<Token>,
42    pos: usize,
43    errors: Vec<ParserError>,
44}
45
46impl Parser {
47    pub fn new(tokens: Vec<Token>) -> Self {
48        Self {
49            tokens,
50            pos: 0,
51            errors: Vec::new(),
52        }
53    }
54
55    fn current_span(&self) -> Span {
56        self.tokens
57            .get(self.pos)
58            .map(|t| t.span)
59            .unwrap_or(Span::dummy())
60    }
61
62    fn current_kind(&self) -> Option<&TokenKind> {
63        self.tokens.get(self.pos).map(|t| &t.kind)
64    }
65
66    fn prev_span(&self) -> Span {
67        if self.pos > 0 {
68            self.tokens[self.pos - 1].span
69        } else {
70            Span::dummy()
71        }
72    }
73
74    /// Parse a complete .harn file. Reports multiple errors via recovery.
75    pub fn parse(&mut self) -> Result<Vec<SNode>, ParserError> {
76        let mut nodes = Vec::new();
77        self.skip_newlines();
78
79        while !self.is_at_end() {
80            // Skip any stray closing braces at top level (after recovery)
81            if self.check(&TokenKind::RBrace) {
82                self.advance();
83                self.skip_newlines();
84                continue;
85            }
86
87            let result = if self.check(&TokenKind::Import) {
88                self.parse_import()
89            } else if self.check(&TokenKind::Pipeline) {
90                self.parse_pipeline()
91            } else {
92                self.parse_statement()
93            };
94
95            match result {
96                Ok(node) => nodes.push(node),
97                Err(err) => {
98                    self.errors.push(err);
99                    self.synchronize();
100                }
101            }
102            self.skip_newlines();
103        }
104
105        if let Some(first) = self.errors.first() {
106            return Err(first.clone());
107        }
108        Ok(nodes)
109    }
110
111    /// Return all accumulated parser errors (after `parse()` returns).
112    pub fn all_errors(&self) -> &[ParserError] {
113        &self.errors
114    }
115
116    /// Check if the current token is one that starts a statement.
117    fn is_statement_start(&self) -> bool {
118        matches!(
119            self.current_kind(),
120            Some(
121                TokenKind::Let
122                    | TokenKind::Var
123                    | TokenKind::If
124                    | TokenKind::For
125                    | TokenKind::While
126                    | TokenKind::Match
127                    | TokenKind::Retry
128                    | TokenKind::Return
129                    | TokenKind::Throw
130                    | TokenKind::Fn
131                    | TokenKind::Pub
132                    | TokenKind::Try
133                    | TokenKind::Pipeline
134                    | TokenKind::Import
135                    | TokenKind::Parallel
136                    | TokenKind::ParallelMap
137                    | TokenKind::Enum
138                    | TokenKind::Struct
139                    | TokenKind::Interface
140                    | TokenKind::Guard
141                    | TokenKind::Deadline
142                    | TokenKind::Yield
143                    | TokenKind::Mutex
144            )
145        )
146    }
147
148    /// Advance past tokens until we reach a likely statement boundary.
149    fn synchronize(&mut self) {
150        while !self.is_at_end() {
151            if self.check(&TokenKind::Newline) {
152                self.advance();
153                if self.is_at_end() || self.is_statement_start() {
154                    return;
155                }
156                continue;
157            }
158            if self.check(&TokenKind::RBrace) {
159                return;
160            }
161            self.advance();
162        }
163    }
164
165    /// Parse a single expression (for string interpolation).
166    pub fn parse_single_expression(&mut self) -> Result<SNode, ParserError> {
167        self.skip_newlines();
168        self.parse_expression()
169    }
170
171    // --- Declarations ---
172
173    fn parse_pipeline(&mut self) -> Result<SNode, ParserError> {
174        let start = self.current_span();
175        self.consume(&TokenKind::Pipeline, "pipeline")?;
176        let name = self.consume_identifier("pipeline name")?;
177
178        self.consume(&TokenKind::LParen, "(")?;
179        let params = self.parse_param_list()?;
180        self.consume(&TokenKind::RParen, ")")?;
181
182        let extends = if self.check(&TokenKind::Extends) {
183            self.advance();
184            Some(self.consume_identifier("parent pipeline name")?)
185        } else {
186            None
187        };
188
189        self.consume(&TokenKind::LBrace, "{")?;
190        let body = self.parse_block()?;
191        self.consume(&TokenKind::RBrace, "}")?;
192
193        Ok(spanned(
194            Node::Pipeline {
195                name,
196                params,
197                body,
198                extends,
199            },
200            Span::merge(start, self.prev_span()),
201        ))
202    }
203
204    fn parse_import(&mut self) -> Result<SNode, ParserError> {
205        let start = self.current_span();
206        self.consume(&TokenKind::Import, "import")?;
207
208        // Check for selective import: import { foo, bar } from "module"
209        if self.check(&TokenKind::LBrace) {
210            self.advance(); // skip {
211            let mut names = Vec::new();
212            while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
213                let name = self.consume_identifier("import name")?;
214                names.push(name);
215                if self.check(&TokenKind::Comma) {
216                    self.advance();
217                }
218            }
219            self.consume(&TokenKind::RBrace, "}")?;
220            self.consume(&TokenKind::From, "from")?;
221            if let Some(tok) = self.current() {
222                if let TokenKind::StringLiteral(path) = &tok.kind {
223                    let path = path.clone();
224                    self.advance();
225                    return Ok(spanned(
226                        Node::SelectiveImport { names, path },
227                        Span::merge(start, self.prev_span()),
228                    ));
229                }
230            }
231            return Err(self.error("import path string"));
232        }
233
234        if let Some(tok) = self.current() {
235            if let TokenKind::StringLiteral(path) = &tok.kind {
236                let path = path.clone();
237                self.advance();
238                return Ok(spanned(
239                    Node::ImportDecl { path },
240                    Span::merge(start, self.prev_span()),
241                ));
242            }
243        }
244        Err(self.error("import path string"))
245    }
246
247    // --- Statements ---
248
249    fn parse_block(&mut self) -> Result<Vec<SNode>, ParserError> {
250        let mut stmts = Vec::new();
251        self.skip_newlines();
252
253        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
254            stmts.push(self.parse_statement()?);
255            self.skip_newlines();
256        }
257        Ok(stmts)
258    }
259
260    fn parse_statement(&mut self) -> Result<SNode, ParserError> {
261        self.skip_newlines();
262
263        let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
264            expected: "statement".into(),
265        })?;
266
267        match &tok.kind {
268            TokenKind::Let => self.parse_let_binding(),
269            TokenKind::Var => self.parse_var_binding(),
270            TokenKind::If => self.parse_if_else(),
271            TokenKind::For => self.parse_for_in(),
272            TokenKind::Match => self.parse_match(),
273            TokenKind::Retry => self.parse_retry(),
274            TokenKind::While => self.parse_while_loop(),
275            TokenKind::Parallel => self.parse_parallel(),
276            TokenKind::ParallelMap => self.parse_parallel_map(),
277            TokenKind::Return => self.parse_return(),
278            TokenKind::Throw => self.parse_throw(),
279            TokenKind::Override => self.parse_override(),
280            TokenKind::Try => self.parse_try_catch(),
281            TokenKind::Fn => self.parse_fn_decl_with_pub(false),
282            TokenKind::Pub => {
283                self.advance(); // consume 'pub'
284                let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
285                    expected: "fn, struct, enum, or pipeline after pub".into(),
286                })?;
287                match &tok.kind {
288                    TokenKind::Fn => self.parse_fn_decl_with_pub(true),
289                    _ => Err(self.error("fn, struct, enum, or pipeline after pub")),
290                }
291            }
292            TokenKind::TypeKw => self.parse_type_decl(),
293            TokenKind::Enum => self.parse_enum_decl(),
294            TokenKind::Struct => self.parse_struct_decl(),
295            TokenKind::Interface => self.parse_interface_decl(),
296            TokenKind::Guard => self.parse_guard(),
297            TokenKind::Deadline => self.parse_deadline(),
298            TokenKind::Yield => self.parse_yield(),
299            TokenKind::Mutex => self.parse_mutex(),
300            TokenKind::Break => {
301                let span = self.current_span();
302                self.advance();
303                Ok(spanned(Node::BreakStmt, span))
304            }
305            TokenKind::Continue => {
306                let span = self.current_span();
307                self.advance();
308                Ok(spanned(Node::ContinueStmt, span))
309            }
310            _ => self.parse_expression_statement(),
311        }
312    }
313
314    fn parse_let_binding(&mut self) -> Result<SNode, ParserError> {
315        let start = self.current_span();
316        self.consume(&TokenKind::Let, "let")?;
317        let pattern = self.parse_binding_pattern()?;
318        let type_ann = if matches!(pattern, BindingPattern::Identifier(_)) {
319            self.try_parse_type_annotation()?
320        } else {
321            None
322        };
323        self.consume(&TokenKind::Assign, "=")?;
324        let value = self.parse_expression()?;
325        Ok(spanned(
326            Node::LetBinding {
327                pattern,
328                type_ann,
329                value: Box::new(value),
330            },
331            Span::merge(start, self.prev_span()),
332        ))
333    }
334
335    fn parse_var_binding(&mut self) -> Result<SNode, ParserError> {
336        let start = self.current_span();
337        self.consume(&TokenKind::Var, "var")?;
338        let pattern = self.parse_binding_pattern()?;
339        let type_ann = if matches!(pattern, BindingPattern::Identifier(_)) {
340            self.try_parse_type_annotation()?
341        } else {
342            None
343        };
344        self.consume(&TokenKind::Assign, "=")?;
345        let value = self.parse_expression()?;
346        Ok(spanned(
347            Node::VarBinding {
348                pattern,
349                type_ann,
350                value: Box::new(value),
351            },
352            Span::merge(start, self.prev_span()),
353        ))
354    }
355
356    fn parse_if_else(&mut self) -> Result<SNode, ParserError> {
357        let start = self.current_span();
358        self.consume(&TokenKind::If, "if")?;
359        let condition = self.parse_expression()?;
360        self.consume(&TokenKind::LBrace, "{")?;
361        let then_body = self.parse_block()?;
362        self.consume(&TokenKind::RBrace, "}")?;
363        self.skip_newlines();
364
365        let else_body = if self.check(&TokenKind::Else) {
366            self.advance();
367            if self.check(&TokenKind::If) {
368                Some(vec![self.parse_if_else()?])
369            } else {
370                self.consume(&TokenKind::LBrace, "{")?;
371                let body = self.parse_block()?;
372                self.consume(&TokenKind::RBrace, "}")?;
373                Some(body)
374            }
375        } else {
376            None
377        };
378
379        Ok(spanned(
380            Node::IfElse {
381                condition: Box::new(condition),
382                then_body,
383                else_body,
384            },
385            Span::merge(start, self.prev_span()),
386        ))
387    }
388
389    fn parse_for_in(&mut self) -> Result<SNode, ParserError> {
390        let start = self.current_span();
391        self.consume(&TokenKind::For, "for")?;
392        let pattern = self.parse_binding_pattern()?;
393        self.consume(&TokenKind::In, "in")?;
394        let iterable = self.parse_expression()?;
395        self.consume(&TokenKind::LBrace, "{")?;
396        let body = self.parse_block()?;
397        self.consume(&TokenKind::RBrace, "}")?;
398        Ok(spanned(
399            Node::ForIn {
400                pattern,
401                iterable: Box::new(iterable),
402                body,
403            },
404            Span::merge(start, self.prev_span()),
405        ))
406    }
407
408    /// Parse a binding pattern for let/var/for-in:
409    ///   identifier | { fields } | [ elements ]
410    fn parse_binding_pattern(&mut self) -> Result<BindingPattern, ParserError> {
411        self.skip_newlines();
412        if self.check(&TokenKind::LBrace) {
413            // Dict destructuring: { key, key: alias, ...rest }
414            self.advance(); // consume {
415            let mut fields = Vec::new();
416            while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
417                // Check for rest pattern: ...ident
418                if self.check(&TokenKind::Dot) {
419                    // Consume three dots
420                    self.advance(); // .
421                    self.consume(&TokenKind::Dot, ".")?;
422                    self.consume(&TokenKind::Dot, ".")?;
423                    let name = self.consume_identifier("rest variable name")?;
424                    fields.push(DictPatternField {
425                        key: name,
426                        alias: None,
427                        is_rest: true,
428                    });
429                    // Rest must be last
430                    break;
431                }
432                let key = self.consume_identifier("field name")?;
433                let alias = if self.check(&TokenKind::Colon) {
434                    self.advance(); // consume :
435                    Some(self.consume_identifier("alias name")?)
436                } else {
437                    None
438                };
439                fields.push(DictPatternField {
440                    key,
441                    alias,
442                    is_rest: false,
443                });
444                if self.check(&TokenKind::Comma) {
445                    self.advance();
446                }
447            }
448            self.consume(&TokenKind::RBrace, "}")?;
449            Ok(BindingPattern::Dict(fields))
450        } else if self.check(&TokenKind::LBracket) {
451            // List destructuring: [ name, name, ...rest ]
452            self.advance(); // consume [
453            let mut elements = Vec::new();
454            while !self.is_at_end() && !self.check(&TokenKind::RBracket) {
455                // Check for rest pattern: ...ident
456                if self.check(&TokenKind::Dot) {
457                    self.advance(); // .
458                    self.consume(&TokenKind::Dot, ".")?;
459                    self.consume(&TokenKind::Dot, ".")?;
460                    let name = self.consume_identifier("rest variable name")?;
461                    elements.push(ListPatternElement {
462                        name,
463                        is_rest: true,
464                    });
465                    // Rest must be last
466                    break;
467                }
468                let name = self.consume_identifier("element name")?;
469                elements.push(ListPatternElement {
470                    name,
471                    is_rest: false,
472                });
473                if self.check(&TokenKind::Comma) {
474                    self.advance();
475                }
476            }
477            self.consume(&TokenKind::RBracket, "]")?;
478            Ok(BindingPattern::List(elements))
479        } else {
480            // Simple identifier
481            let name = self.consume_identifier("variable name or destructuring pattern")?;
482            Ok(BindingPattern::Identifier(name))
483        }
484    }
485
486    fn parse_match(&mut self) -> Result<SNode, ParserError> {
487        let start = self.current_span();
488        self.consume(&TokenKind::Match, "match")?;
489        let value = self.parse_expression()?;
490        self.consume(&TokenKind::LBrace, "{")?;
491        self.skip_newlines();
492
493        let mut arms = Vec::new();
494        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
495            let pattern = self.parse_expression()?;
496            self.consume(&TokenKind::Arrow, "->")?;
497            self.consume(&TokenKind::LBrace, "{")?;
498            let body = self.parse_block()?;
499            self.consume(&TokenKind::RBrace, "}")?;
500            arms.push(MatchArm { pattern, body });
501            self.skip_newlines();
502        }
503
504        self.consume(&TokenKind::RBrace, "}")?;
505        Ok(spanned(
506            Node::MatchExpr {
507                value: Box::new(value),
508                arms,
509            },
510            Span::merge(start, self.prev_span()),
511        ))
512    }
513
514    fn parse_while_loop(&mut self) -> Result<SNode, ParserError> {
515        let start = self.current_span();
516        self.consume(&TokenKind::While, "while")?;
517        let condition = if self.check(&TokenKind::LParen) {
518            self.advance();
519            let c = self.parse_expression()?;
520            self.consume(&TokenKind::RParen, ")")?;
521            c
522        } else {
523            self.parse_expression()?
524        };
525        self.consume(&TokenKind::LBrace, "{")?;
526        let body = self.parse_block()?;
527        self.consume(&TokenKind::RBrace, "}")?;
528        Ok(spanned(
529            Node::WhileLoop {
530                condition: Box::new(condition),
531                body,
532            },
533            Span::merge(start, self.prev_span()),
534        ))
535    }
536
537    fn parse_retry(&mut self) -> Result<SNode, ParserError> {
538        let start = self.current_span();
539        self.consume(&TokenKind::Retry, "retry")?;
540        let count = if self.check(&TokenKind::LParen) {
541            self.advance();
542            let c = self.parse_expression()?;
543            self.consume(&TokenKind::RParen, ")")?;
544            c
545        } else {
546            self.parse_primary()?
547        };
548        self.consume(&TokenKind::LBrace, "{")?;
549        let body = self.parse_block()?;
550        self.consume(&TokenKind::RBrace, "}")?;
551        Ok(spanned(
552            Node::Retry {
553                count: Box::new(count),
554                body,
555            },
556            Span::merge(start, self.prev_span()),
557        ))
558    }
559
560    fn parse_parallel(&mut self) -> Result<SNode, ParserError> {
561        let start = self.current_span();
562        self.consume(&TokenKind::Parallel, "parallel")?;
563        self.consume(&TokenKind::LParen, "(")?;
564        let count = self.parse_expression()?;
565        self.consume(&TokenKind::RParen, ")")?;
566        self.consume(&TokenKind::LBrace, "{")?;
567
568        // Optional closure parameter: { i ->
569        let mut variable = None;
570        self.skip_newlines();
571        if let Some(tok) = self.current() {
572            if let TokenKind::Identifier(name) = &tok.kind {
573                if self.peek_kind() == Some(&TokenKind::Arrow) {
574                    let name = name.clone();
575                    self.advance(); // skip identifier
576                    self.advance(); // skip ->
577                    variable = Some(name);
578                }
579            }
580        }
581
582        let body = self.parse_block()?;
583        self.consume(&TokenKind::RBrace, "}")?;
584        Ok(spanned(
585            Node::Parallel {
586                count: Box::new(count),
587                variable,
588                body,
589            },
590            Span::merge(start, self.prev_span()),
591        ))
592    }
593
594    fn parse_parallel_map(&mut self) -> Result<SNode, ParserError> {
595        let start = self.current_span();
596        self.consume(&TokenKind::ParallelMap, "parallel_map")?;
597        self.consume(&TokenKind::LParen, "(")?;
598        let list = self.parse_expression()?;
599        self.consume(&TokenKind::RParen, ")")?;
600        self.consume(&TokenKind::LBrace, "{")?;
601
602        self.skip_newlines();
603        let variable = self.consume_identifier("map variable")?;
604        self.consume(&TokenKind::Arrow, "->")?;
605
606        let body = self.parse_block()?;
607        self.consume(&TokenKind::RBrace, "}")?;
608        Ok(spanned(
609            Node::ParallelMap {
610                list: Box::new(list),
611                variable,
612                body,
613            },
614            Span::merge(start, self.prev_span()),
615        ))
616    }
617
618    fn parse_return(&mut self) -> Result<SNode, ParserError> {
619        let start = self.current_span();
620        self.consume(&TokenKind::Return, "return")?;
621        if self.is_at_end() || self.check(&TokenKind::Newline) || self.check(&TokenKind::RBrace) {
622            return Ok(spanned(
623                Node::ReturnStmt { value: None },
624                Span::merge(start, self.prev_span()),
625            ));
626        }
627        let value = self.parse_expression()?;
628        Ok(spanned(
629            Node::ReturnStmt {
630                value: Some(Box::new(value)),
631            },
632            Span::merge(start, self.prev_span()),
633        ))
634    }
635
636    fn parse_throw(&mut self) -> Result<SNode, ParserError> {
637        let start = self.current_span();
638        self.consume(&TokenKind::Throw, "throw")?;
639        let value = self.parse_expression()?;
640        Ok(spanned(
641            Node::ThrowStmt {
642                value: Box::new(value),
643            },
644            Span::merge(start, self.prev_span()),
645        ))
646    }
647
648    fn parse_override(&mut self) -> Result<SNode, ParserError> {
649        let start = self.current_span();
650        self.consume(&TokenKind::Override, "override")?;
651        let name = self.consume_identifier("override name")?;
652        self.consume(&TokenKind::LParen, "(")?;
653        let params = self.parse_param_list()?;
654        self.consume(&TokenKind::RParen, ")")?;
655        self.consume(&TokenKind::LBrace, "{")?;
656        let body = self.parse_block()?;
657        self.consume(&TokenKind::RBrace, "}")?;
658        Ok(spanned(
659            Node::OverrideDecl { name, params, body },
660            Span::merge(start, self.prev_span()),
661        ))
662    }
663
664    fn parse_try_catch(&mut self) -> Result<SNode, ParserError> {
665        let start = self.current_span();
666        self.consume(&TokenKind::Try, "try")?;
667        self.consume(&TokenKind::LBrace, "{")?;
668        let body = self.parse_block()?;
669        self.consume(&TokenKind::RBrace, "}")?;
670        self.skip_newlines();
671        self.consume(&TokenKind::Catch, "catch")?;
672
673        let (error_var, error_type) = if self.check(&TokenKind::LParen) {
674            self.advance();
675            let name = self.consume_identifier("error variable")?;
676            let ty = self.try_parse_type_annotation()?;
677            self.consume(&TokenKind::RParen, ")")?;
678            (Some(name), ty)
679        } else {
680            (None, None)
681        };
682
683        self.consume(&TokenKind::LBrace, "{")?;
684        let catch_body = self.parse_block()?;
685        self.consume(&TokenKind::RBrace, "}")?;
686        Ok(spanned(
687            Node::TryCatch {
688                body,
689                error_var,
690                error_type,
691                catch_body,
692            },
693            Span::merge(start, self.prev_span()),
694        ))
695    }
696
697    fn parse_fn_decl_with_pub(&mut self, is_pub: bool) -> Result<SNode, ParserError> {
698        let start = self.current_span();
699        self.consume(&TokenKind::Fn, "fn")?;
700        let name = self.consume_identifier("function name")?;
701
702        // Optional generic type parameters: fn name<T, U>(...)
703        let type_params = if self.check(&TokenKind::Lt) {
704            self.advance(); // skip <
705            self.parse_type_param_list()?
706        } else {
707            Vec::new()
708        };
709
710        self.consume(&TokenKind::LParen, "(")?;
711        let params = self.parse_typed_param_list()?;
712        self.consume(&TokenKind::RParen, ")")?;
713        // Optional return type: -> type
714        let return_type = if self.check(&TokenKind::Arrow) {
715            self.advance();
716            Some(self.parse_type_expr()?)
717        } else {
718            None
719        };
720
721        // Optional where clause: where T: bound, U: bound
722        let where_clauses = self.parse_where_clauses()?;
723
724        self.consume(&TokenKind::LBrace, "{")?;
725        let body = self.parse_block()?;
726        self.consume(&TokenKind::RBrace, "}")?;
727        Ok(spanned(
728            Node::FnDecl {
729                name,
730                type_params,
731                params,
732                return_type,
733                where_clauses,
734                body,
735                is_pub,
736            },
737            Span::merge(start, self.prev_span()),
738        ))
739    }
740
741    fn parse_type_decl(&mut self) -> Result<SNode, ParserError> {
742        let start = self.current_span();
743        self.consume(&TokenKind::TypeKw, "type")?;
744        let name = self.consume_identifier("type name")?;
745        self.consume(&TokenKind::Assign, "=")?;
746        let type_expr = self.parse_type_expr()?;
747        Ok(spanned(
748            Node::TypeDecl { name, type_expr },
749            Span::merge(start, self.prev_span()),
750        ))
751    }
752
753    fn parse_enum_decl(&mut self) -> Result<SNode, ParserError> {
754        let start = self.current_span();
755        self.consume(&TokenKind::Enum, "enum")?;
756        let name = self.consume_identifier("enum name")?;
757        self.consume(&TokenKind::LBrace, "{")?;
758        self.skip_newlines();
759
760        let mut variants = Vec::new();
761        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
762            let variant_name = self.consume_identifier("variant name")?;
763            let fields = if self.check(&TokenKind::LParen) {
764                self.advance();
765                let params = self.parse_typed_param_list()?;
766                self.consume(&TokenKind::RParen, ")")?;
767                params
768            } else {
769                Vec::new()
770            };
771            variants.push(EnumVariant {
772                name: variant_name,
773                fields,
774            });
775            self.skip_newlines();
776            if self.check(&TokenKind::Comma) {
777                self.advance();
778                self.skip_newlines();
779            }
780        }
781
782        self.consume(&TokenKind::RBrace, "}")?;
783        Ok(spanned(
784            Node::EnumDecl { name, variants },
785            Span::merge(start, self.prev_span()),
786        ))
787    }
788
789    fn parse_struct_decl(&mut self) -> Result<SNode, ParserError> {
790        let start = self.current_span();
791        self.consume(&TokenKind::Struct, "struct")?;
792        let name = self.consume_identifier("struct name")?;
793        self.consume(&TokenKind::LBrace, "{")?;
794        self.skip_newlines();
795
796        let mut fields = Vec::new();
797        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
798            let field_name = self.consume_identifier("field name")?;
799            let optional = if self.check(&TokenKind::Question) {
800                self.advance();
801                true
802            } else {
803                false
804            };
805            let type_expr = self.try_parse_type_annotation()?;
806            fields.push(StructField {
807                name: field_name,
808                type_expr,
809                optional,
810            });
811            self.skip_newlines();
812            if self.check(&TokenKind::Comma) {
813                self.advance();
814                self.skip_newlines();
815            }
816        }
817
818        self.consume(&TokenKind::RBrace, "}")?;
819        Ok(spanned(
820            Node::StructDecl { name, fields },
821            Span::merge(start, self.prev_span()),
822        ))
823    }
824
825    fn parse_interface_decl(&mut self) -> Result<SNode, ParserError> {
826        let start = self.current_span();
827        self.consume(&TokenKind::Interface, "interface")?;
828        let name = self.consume_identifier("interface name")?;
829        self.consume(&TokenKind::LBrace, "{")?;
830        self.skip_newlines();
831
832        let mut methods = Vec::new();
833        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
834            self.consume(&TokenKind::Fn, "fn")?;
835            let method_name = self.consume_identifier("method name")?;
836            self.consume(&TokenKind::LParen, "(")?;
837            let params = self.parse_typed_param_list()?;
838            self.consume(&TokenKind::RParen, ")")?;
839            // Optional return type: -> type
840            let return_type = if self.check(&TokenKind::Arrow) {
841                self.advance();
842                Some(self.parse_type_expr()?)
843            } else {
844                None
845            };
846            methods.push(InterfaceMethod {
847                name: method_name,
848                params,
849                return_type,
850            });
851            self.skip_newlines();
852        }
853
854        self.consume(&TokenKind::RBrace, "}")?;
855        Ok(spanned(
856            Node::InterfaceDecl { name, methods },
857            Span::merge(start, self.prev_span()),
858        ))
859    }
860
861    fn parse_guard(&mut self) -> Result<SNode, ParserError> {
862        let start = self.current_span();
863        self.consume(&TokenKind::Guard, "guard")?;
864        let condition = self.parse_expression()?;
865        // Consume "else" — we reuse the Else keyword
866        self.consume(&TokenKind::Else, "else")?;
867        self.consume(&TokenKind::LBrace, "{")?;
868        let else_body = self.parse_block()?;
869        self.consume(&TokenKind::RBrace, "}")?;
870        Ok(spanned(
871            Node::GuardStmt {
872                condition: Box::new(condition),
873                else_body,
874            },
875            Span::merge(start, self.prev_span()),
876        ))
877    }
878
879    fn parse_deadline(&mut self) -> Result<SNode, ParserError> {
880        let start = self.current_span();
881        self.consume(&TokenKind::Deadline, "deadline")?;
882        let duration = self.parse_primary()?;
883        self.consume(&TokenKind::LBrace, "{")?;
884        let body = self.parse_block()?;
885        self.consume(&TokenKind::RBrace, "}")?;
886        Ok(spanned(
887            Node::DeadlineBlock {
888                duration: Box::new(duration),
889                body,
890            },
891            Span::merge(start, self.prev_span()),
892        ))
893    }
894
895    fn parse_yield(&mut self) -> Result<SNode, ParserError> {
896        let start = self.current_span();
897        self.consume(&TokenKind::Yield, "yield")?;
898        if self.is_at_end() || self.check(&TokenKind::Newline) || self.check(&TokenKind::RBrace) {
899            return Ok(spanned(
900                Node::YieldExpr { value: None },
901                Span::merge(start, self.prev_span()),
902            ));
903        }
904        let value = self.parse_expression()?;
905        Ok(spanned(
906            Node::YieldExpr {
907                value: Some(Box::new(value)),
908            },
909            Span::merge(start, self.prev_span()),
910        ))
911    }
912
913    fn parse_mutex(&mut self) -> Result<SNode, ParserError> {
914        let start = self.current_span();
915        self.consume(&TokenKind::Mutex, "mutex")?;
916        self.consume(&TokenKind::LBrace, "{")?;
917        let body = self.parse_block()?;
918        self.consume(&TokenKind::RBrace, "}")?;
919        Ok(spanned(
920            Node::MutexBlock { body },
921            Span::merge(start, self.prev_span()),
922        ))
923    }
924
925    fn parse_ask_expr(&mut self) -> Result<SNode, ParserError> {
926        let start = self.current_span();
927        self.consume(&TokenKind::Ask, "ask")?;
928        self.consume(&TokenKind::LBrace, "{")?;
929        // Parse as dict entries
930        let mut entries = Vec::new();
931        self.skip_newlines();
932        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
933            let key_span = self.current_span();
934            let name = self.consume_identifier("ask field")?;
935            let key = spanned(Node::StringLiteral(name), key_span);
936            self.consume(&TokenKind::Colon, ":")?;
937            let value = self.parse_expression()?;
938            entries.push(DictEntry { key, value });
939            self.skip_newlines();
940            if self.check(&TokenKind::Comma) {
941                self.advance();
942                self.skip_newlines();
943            }
944        }
945        self.consume(&TokenKind::RBrace, "}")?;
946        Ok(spanned(
947            Node::AskExpr { fields: entries },
948            Span::merge(start, self.prev_span()),
949        ))
950    }
951
952    // --- Expressions (precedence climbing) ---
953
954    fn parse_expression_statement(&mut self) -> Result<SNode, ParserError> {
955        let start = self.current_span();
956        let expr = self.parse_expression()?;
957
958        // Check for assignment or compound assignment on valid targets:
959        // identifier, property access (obj.field), subscript access (obj[key])
960        let is_assignable = matches!(
961            expr.node,
962            Node::Identifier(_) | Node::PropertyAccess { .. } | Node::SubscriptAccess { .. }
963        );
964        if is_assignable {
965            if self.check(&TokenKind::Assign) {
966                self.advance();
967                let value = self.parse_expression()?;
968                return Ok(spanned(
969                    Node::Assignment {
970                        target: Box::new(expr),
971                        value: Box::new(value),
972                        op: None,
973                    },
974                    Span::merge(start, self.prev_span()),
975                ));
976            }
977            let compound_op = if self.check(&TokenKind::PlusAssign) {
978                Some("+")
979            } else if self.check(&TokenKind::MinusAssign) {
980                Some("-")
981            } else if self.check(&TokenKind::StarAssign) {
982                Some("*")
983            } else if self.check(&TokenKind::SlashAssign) {
984                Some("/")
985            } else if self.check(&TokenKind::PercentAssign) {
986                Some("%")
987            } else {
988                None
989            };
990            if let Some(op) = compound_op {
991                self.advance();
992                let value = self.parse_expression()?;
993                return Ok(spanned(
994                    Node::Assignment {
995                        target: Box::new(expr),
996                        value: Box::new(value),
997                        op: Some(op.into()),
998                    },
999                    Span::merge(start, self.prev_span()),
1000                ));
1001            }
1002        }
1003
1004        Ok(expr)
1005    }
1006
1007    fn parse_expression(&mut self) -> Result<SNode, ParserError> {
1008        self.skip_newlines();
1009        self.parse_pipe()
1010    }
1011
1012    fn parse_pipe(&mut self) -> Result<SNode, ParserError> {
1013        let mut left = self.parse_range()?;
1014        while self.check_skip_newlines(&TokenKind::Pipe) {
1015            let start = left.span;
1016            self.advance();
1017            let right = self.parse_range()?;
1018            left = spanned(
1019                Node::BinaryOp {
1020                    op: "|>".into(),
1021                    left: Box::new(left),
1022                    right: Box::new(right),
1023                },
1024                Span::merge(start, self.prev_span()),
1025            );
1026        }
1027        Ok(left)
1028    }
1029
1030    fn parse_range(&mut self) -> Result<SNode, ParserError> {
1031        let left = self.parse_ternary()?;
1032        if self.check(&TokenKind::Thru) {
1033            let start = left.span;
1034            self.advance();
1035            let right = self.parse_ternary()?;
1036            return Ok(spanned(
1037                Node::RangeExpr {
1038                    start: Box::new(left),
1039                    end: Box::new(right),
1040                    inclusive: true,
1041                },
1042                Span::merge(start, self.prev_span()),
1043            ));
1044        }
1045        if self.check(&TokenKind::Upto) {
1046            let start = left.span;
1047            self.advance();
1048            let right = self.parse_ternary()?;
1049            return Ok(spanned(
1050                Node::RangeExpr {
1051                    start: Box::new(left),
1052                    end: Box::new(right),
1053                    inclusive: false,
1054                },
1055                Span::merge(start, self.prev_span()),
1056            ));
1057        }
1058        Ok(left)
1059    }
1060
1061    fn parse_ternary(&mut self) -> Result<SNode, ParserError> {
1062        let condition = self.parse_nil_coalescing()?;
1063        if !self.check(&TokenKind::Question) {
1064            return Ok(condition);
1065        }
1066        let start = condition.span;
1067        self.advance(); // skip ?
1068        let true_val = self.parse_nil_coalescing()?;
1069        self.consume(&TokenKind::Colon, ":")?;
1070        let false_val = self.parse_nil_coalescing()?;
1071        Ok(spanned(
1072            Node::Ternary {
1073                condition: Box::new(condition),
1074                true_expr: Box::new(true_val),
1075                false_expr: Box::new(false_val),
1076            },
1077            Span::merge(start, self.prev_span()),
1078        ))
1079    }
1080
1081    fn parse_nil_coalescing(&mut self) -> Result<SNode, ParserError> {
1082        let mut left = self.parse_logical_or()?;
1083        while self.check(&TokenKind::NilCoal) {
1084            let start = left.span;
1085            self.advance();
1086            let right = self.parse_logical_or()?;
1087            left = spanned(
1088                Node::BinaryOp {
1089                    op: "??".into(),
1090                    left: Box::new(left),
1091                    right: Box::new(right),
1092                },
1093                Span::merge(start, self.prev_span()),
1094            );
1095        }
1096        Ok(left)
1097    }
1098
1099    fn parse_logical_or(&mut self) -> Result<SNode, ParserError> {
1100        let mut left = self.parse_logical_and()?;
1101        while self.check_skip_newlines(&TokenKind::Or) {
1102            let start = left.span;
1103            self.advance();
1104            let right = self.parse_logical_and()?;
1105            left = spanned(
1106                Node::BinaryOp {
1107                    op: "||".into(),
1108                    left: Box::new(left),
1109                    right: Box::new(right),
1110                },
1111                Span::merge(start, self.prev_span()),
1112            );
1113        }
1114        Ok(left)
1115    }
1116
1117    fn parse_logical_and(&mut self) -> Result<SNode, ParserError> {
1118        let mut left = self.parse_equality()?;
1119        while self.check_skip_newlines(&TokenKind::And) {
1120            let start = left.span;
1121            self.advance();
1122            let right = self.parse_equality()?;
1123            left = spanned(
1124                Node::BinaryOp {
1125                    op: "&&".into(),
1126                    left: Box::new(left),
1127                    right: Box::new(right),
1128                },
1129                Span::merge(start, self.prev_span()),
1130            );
1131        }
1132        Ok(left)
1133    }
1134
1135    fn parse_equality(&mut self) -> Result<SNode, ParserError> {
1136        let mut left = self.parse_comparison()?;
1137        while self.check(&TokenKind::Eq) || self.check(&TokenKind::Neq) {
1138            let start = left.span;
1139            let op = if self.check(&TokenKind::Eq) {
1140                "=="
1141            } else {
1142                "!="
1143            };
1144            self.advance();
1145            let right = self.parse_comparison()?;
1146            left = spanned(
1147                Node::BinaryOp {
1148                    op: op.into(),
1149                    left: Box::new(left),
1150                    right: Box::new(right),
1151                },
1152                Span::merge(start, self.prev_span()),
1153            );
1154        }
1155        Ok(left)
1156    }
1157
1158    fn parse_comparison(&mut self) -> Result<SNode, ParserError> {
1159        let mut left = self.parse_additive()?;
1160        while self.check(&TokenKind::Lt)
1161            || self.check(&TokenKind::Gt)
1162            || self.check(&TokenKind::Lte)
1163            || self.check(&TokenKind::Gte)
1164        {
1165            let start = left.span;
1166            let op = match self.current().map(|t| &t.kind) {
1167                Some(TokenKind::Lt) => "<",
1168                Some(TokenKind::Gt) => ">",
1169                Some(TokenKind::Lte) => "<=",
1170                Some(TokenKind::Gte) => ">=",
1171                _ => "<",
1172            };
1173            self.advance();
1174            let right = self.parse_additive()?;
1175            left = spanned(
1176                Node::BinaryOp {
1177                    op: op.into(),
1178                    left: Box::new(left),
1179                    right: Box::new(right),
1180                },
1181                Span::merge(start, self.prev_span()),
1182            );
1183        }
1184        Ok(left)
1185    }
1186
1187    fn parse_additive(&mut self) -> Result<SNode, ParserError> {
1188        let mut left = self.parse_multiplicative()?;
1189        while self.check_skip_newlines(&TokenKind::Plus) || self.check(&TokenKind::Minus) {
1190            let start = left.span;
1191            let op = if self.check(&TokenKind::Plus) {
1192                "+"
1193            } else {
1194                "-"
1195            };
1196            self.advance();
1197            let right = self.parse_multiplicative()?;
1198            left = spanned(
1199                Node::BinaryOp {
1200                    op: op.into(),
1201                    left: Box::new(left),
1202                    right: Box::new(right),
1203                },
1204                Span::merge(start, self.prev_span()),
1205            );
1206        }
1207        Ok(left)
1208    }
1209
1210    fn parse_multiplicative(&mut self) -> Result<SNode, ParserError> {
1211        let mut left = self.parse_unary()?;
1212        while self.check_skip_newlines(&TokenKind::Star)
1213            || self.check_skip_newlines(&TokenKind::Slash)
1214            || self.check_skip_newlines(&TokenKind::Percent)
1215        {
1216            let start = left.span;
1217            let op = if self.check(&TokenKind::Star) {
1218                "*"
1219            } else if self.check(&TokenKind::Slash) {
1220                "/"
1221            } else {
1222                "%"
1223            };
1224            self.advance();
1225            let right = self.parse_unary()?;
1226            left = spanned(
1227                Node::BinaryOp {
1228                    op: op.into(),
1229                    left: Box::new(left),
1230                    right: Box::new(right),
1231                },
1232                Span::merge(start, self.prev_span()),
1233            );
1234        }
1235        Ok(left)
1236    }
1237
1238    fn parse_unary(&mut self) -> Result<SNode, ParserError> {
1239        if self.check(&TokenKind::Not) {
1240            let start = self.current_span();
1241            self.advance();
1242            let operand = self.parse_unary()?;
1243            return Ok(spanned(
1244                Node::UnaryOp {
1245                    op: "!".into(),
1246                    operand: Box::new(operand),
1247                },
1248                Span::merge(start, self.prev_span()),
1249            ));
1250        }
1251        if self.check(&TokenKind::Minus) {
1252            let start = self.current_span();
1253            self.advance();
1254            let operand = self.parse_unary()?;
1255            return Ok(spanned(
1256                Node::UnaryOp {
1257                    op: "-".into(),
1258                    operand: Box::new(operand),
1259                },
1260                Span::merge(start, self.prev_span()),
1261            ));
1262        }
1263        self.parse_postfix()
1264    }
1265
1266    fn parse_postfix(&mut self) -> Result<SNode, ParserError> {
1267        let mut expr = self.parse_primary()?;
1268
1269        loop {
1270            if self.check_skip_newlines(&TokenKind::Dot)
1271                || self.check_skip_newlines(&TokenKind::QuestionDot)
1272            {
1273                let optional = self.check(&TokenKind::QuestionDot);
1274                let start = expr.span;
1275                self.advance();
1276                let member = self.consume_identifier_or_keyword("member name")?;
1277                if self.check(&TokenKind::LParen) {
1278                    self.advance();
1279                    let args = self.parse_arg_list()?;
1280                    self.consume(&TokenKind::RParen, ")")?;
1281                    if optional {
1282                        expr = spanned(
1283                            Node::OptionalMethodCall {
1284                                object: Box::new(expr),
1285                                method: member,
1286                                args,
1287                            },
1288                            Span::merge(start, self.prev_span()),
1289                        );
1290                    } else {
1291                        expr = spanned(
1292                            Node::MethodCall {
1293                                object: Box::new(expr),
1294                                method: member,
1295                                args,
1296                            },
1297                            Span::merge(start, self.prev_span()),
1298                        );
1299                    }
1300                } else if optional {
1301                    expr = spanned(
1302                        Node::OptionalPropertyAccess {
1303                            object: Box::new(expr),
1304                            property: member,
1305                        },
1306                        Span::merge(start, self.prev_span()),
1307                    );
1308                } else {
1309                    expr = spanned(
1310                        Node::PropertyAccess {
1311                            object: Box::new(expr),
1312                            property: member,
1313                        },
1314                        Span::merge(start, self.prev_span()),
1315                    );
1316                }
1317            } else if self.check(&TokenKind::LBracket) {
1318                let start = expr.span;
1319                self.advance();
1320
1321                // Check for slice vs subscript:
1322                // [:end] — slice with no start
1323                // [start:end] or [start:] — slice with start
1324                // [index] — normal subscript
1325                if self.check(&TokenKind::Colon) {
1326                    // [:end] or [:]
1327                    self.advance(); // consume ':'
1328                    let end_expr = if self.check(&TokenKind::RBracket) {
1329                        None
1330                    } else {
1331                        Some(Box::new(self.parse_expression()?))
1332                    };
1333                    self.consume(&TokenKind::RBracket, "]")?;
1334                    expr = spanned(
1335                        Node::SliceAccess {
1336                            object: Box::new(expr),
1337                            start: None,
1338                            end: end_expr,
1339                        },
1340                        Span::merge(start, self.prev_span()),
1341                    );
1342                } else {
1343                    let index = self.parse_expression()?;
1344                    if self.check(&TokenKind::Colon) {
1345                        // [start:end] or [start:]
1346                        self.advance(); // consume ':'
1347                        let end_expr = if self.check(&TokenKind::RBracket) {
1348                            None
1349                        } else {
1350                            Some(Box::new(self.parse_expression()?))
1351                        };
1352                        self.consume(&TokenKind::RBracket, "]")?;
1353                        expr = spanned(
1354                            Node::SliceAccess {
1355                                object: Box::new(expr),
1356                                start: Some(Box::new(index)),
1357                                end: end_expr,
1358                            },
1359                            Span::merge(start, self.prev_span()),
1360                        );
1361                    } else {
1362                        self.consume(&TokenKind::RBracket, "]")?;
1363                        expr = spanned(
1364                            Node::SubscriptAccess {
1365                                object: Box::new(expr),
1366                                index: Box::new(index),
1367                            },
1368                            Span::merge(start, self.prev_span()),
1369                        );
1370                    }
1371                }
1372            } else if self.check(&TokenKind::LParen) && matches!(expr.node, Node::Identifier(_)) {
1373                let start = expr.span;
1374                self.advance();
1375                let args = self.parse_arg_list()?;
1376                self.consume(&TokenKind::RParen, ")")?;
1377                if let Node::Identifier(name) = expr.node {
1378                    expr = spanned(
1379                        Node::FunctionCall { name, args },
1380                        Span::merge(start, self.prev_span()),
1381                    );
1382                }
1383            } else {
1384                break;
1385            }
1386        }
1387
1388        Ok(expr)
1389    }
1390
1391    fn parse_primary(&mut self) -> Result<SNode, ParserError> {
1392        let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
1393            expected: "expression".into(),
1394        })?;
1395        let start = self.current_span();
1396
1397        match &tok.kind {
1398            TokenKind::StringLiteral(s) => {
1399                let s = s.clone();
1400                self.advance();
1401                Ok(spanned(
1402                    Node::StringLiteral(s),
1403                    Span::merge(start, self.prev_span()),
1404                ))
1405            }
1406            TokenKind::InterpolatedString(segments) => {
1407                let segments = segments.clone();
1408                self.advance();
1409                Ok(spanned(
1410                    Node::InterpolatedString(segments),
1411                    Span::merge(start, self.prev_span()),
1412                ))
1413            }
1414            TokenKind::IntLiteral(n) => {
1415                let n = *n;
1416                self.advance();
1417                Ok(spanned(
1418                    Node::IntLiteral(n),
1419                    Span::merge(start, self.prev_span()),
1420                ))
1421            }
1422            TokenKind::FloatLiteral(n) => {
1423                let n = *n;
1424                self.advance();
1425                Ok(spanned(
1426                    Node::FloatLiteral(n),
1427                    Span::merge(start, self.prev_span()),
1428                ))
1429            }
1430            TokenKind::True => {
1431                self.advance();
1432                Ok(spanned(
1433                    Node::BoolLiteral(true),
1434                    Span::merge(start, self.prev_span()),
1435                ))
1436            }
1437            TokenKind::False => {
1438                self.advance();
1439                Ok(spanned(
1440                    Node::BoolLiteral(false),
1441                    Span::merge(start, self.prev_span()),
1442                ))
1443            }
1444            TokenKind::Nil => {
1445                self.advance();
1446                Ok(spanned(
1447                    Node::NilLiteral,
1448                    Span::merge(start, self.prev_span()),
1449                ))
1450            }
1451            TokenKind::Identifier(name) => {
1452                let name = name.clone();
1453                self.advance();
1454                Ok(spanned(
1455                    Node::Identifier(name),
1456                    Span::merge(start, self.prev_span()),
1457                ))
1458            }
1459            TokenKind::LParen => {
1460                self.advance();
1461                let expr = self.parse_expression()?;
1462                self.consume(&TokenKind::RParen, ")")?;
1463                Ok(expr)
1464            }
1465            TokenKind::LBracket => self.parse_list_literal(),
1466            TokenKind::LBrace => self.parse_dict_or_closure(),
1467            TokenKind::Parallel => self.parse_parallel(),
1468            TokenKind::ParallelMap => self.parse_parallel_map(),
1469            TokenKind::Retry => self.parse_retry(),
1470            TokenKind::If => self.parse_if_else(),
1471            TokenKind::Spawn => self.parse_spawn_expr(),
1472            TokenKind::DurationLiteral(ms) => {
1473                let ms = *ms;
1474                self.advance();
1475                Ok(spanned(
1476                    Node::DurationLiteral(ms),
1477                    Span::merge(start, self.prev_span()),
1478                ))
1479            }
1480            TokenKind::Ask => self.parse_ask_expr(),
1481            TokenKind::Deadline => self.parse_deadline(),
1482            _ => Err(self.error("expression")),
1483        }
1484    }
1485
1486    fn parse_spawn_expr(&mut self) -> Result<SNode, ParserError> {
1487        let start = self.current_span();
1488        self.consume(&TokenKind::Spawn, "spawn")?;
1489        self.consume(&TokenKind::LBrace, "{")?;
1490        let body = self.parse_block()?;
1491        self.consume(&TokenKind::RBrace, "}")?;
1492        Ok(spanned(
1493            Node::SpawnExpr { body },
1494            Span::merge(start, self.prev_span()),
1495        ))
1496    }
1497
1498    fn parse_list_literal(&mut self) -> Result<SNode, ParserError> {
1499        let start = self.current_span();
1500        self.consume(&TokenKind::LBracket, "[")?;
1501        let mut elements = Vec::new();
1502        self.skip_newlines();
1503
1504        while !self.is_at_end() && !self.check(&TokenKind::RBracket) {
1505            // Check for spread: ...expr
1506            if self.check(&TokenKind::Dot) {
1507                let saved_pos = self.pos;
1508                self.advance(); // first .
1509                if self.check(&TokenKind::Dot) {
1510                    self.advance(); // second .
1511                    self.consume(&TokenKind::Dot, ".")?; // third .
1512                    let spread_start = self.tokens[saved_pos].span;
1513                    let expr = self.parse_expression()?;
1514                    elements.push(spanned(
1515                        Node::Spread(Box::new(expr)),
1516                        Span::merge(spread_start, self.prev_span()),
1517                    ));
1518                } else {
1519                    // Not a spread, restore and parse as expression
1520                    self.pos = saved_pos;
1521                    elements.push(self.parse_expression()?);
1522                }
1523            } else {
1524                elements.push(self.parse_expression()?);
1525            }
1526            self.skip_newlines();
1527            if self.check(&TokenKind::Comma) {
1528                self.advance();
1529                self.skip_newlines();
1530            }
1531        }
1532
1533        self.consume(&TokenKind::RBracket, "]")?;
1534        Ok(spanned(
1535            Node::ListLiteral(elements),
1536            Span::merge(start, self.prev_span()),
1537        ))
1538    }
1539
1540    fn parse_dict_or_closure(&mut self) -> Result<SNode, ParserError> {
1541        let start = self.current_span();
1542        self.consume(&TokenKind::LBrace, "{")?;
1543        self.skip_newlines();
1544
1545        // Empty dict
1546        if self.check(&TokenKind::RBrace) {
1547            self.advance();
1548            return Ok(spanned(
1549                Node::DictLiteral(Vec::new()),
1550                Span::merge(start, self.prev_span()),
1551            ));
1552        }
1553
1554        // Lookahead: scan for -> before } to disambiguate closure from dict.
1555        let saved = self.pos;
1556        if self.is_closure_lookahead() {
1557            self.pos = saved;
1558            return self.parse_closure_body(start);
1559        }
1560        self.pos = saved;
1561        self.parse_dict_literal(start)
1562    }
1563
1564    /// Scan forward to determine if this is a closure (has -> before matching }).
1565    /// Does not consume tokens (caller saves/restores pos).
1566    fn is_closure_lookahead(&mut self) -> bool {
1567        let mut depth = 0;
1568        while !self.is_at_end() {
1569            if let Some(tok) = self.current() {
1570                match &tok.kind {
1571                    TokenKind::Arrow if depth == 0 => return true,
1572                    TokenKind::LBrace | TokenKind::LParen | TokenKind::LBracket => depth += 1,
1573                    TokenKind::RBrace if depth == 0 => return false,
1574                    TokenKind::RBrace => depth -= 1,
1575                    TokenKind::RParen | TokenKind::RBracket => {
1576                        if depth > 0 {
1577                            depth -= 1;
1578                        }
1579                    }
1580                    _ => {}
1581                }
1582                self.advance();
1583            } else {
1584                return false;
1585            }
1586        }
1587        false
1588    }
1589
1590    /// Parse closure params and body (after opening { has been consumed).
1591    fn parse_closure_body(&mut self, start: Span) -> Result<SNode, ParserError> {
1592        let params = self.parse_typed_param_list_until_arrow()?;
1593        self.consume(&TokenKind::Arrow, "->")?;
1594        let body = self.parse_block()?;
1595        self.consume(&TokenKind::RBrace, "}")?;
1596        Ok(spanned(
1597            Node::Closure { params, body },
1598            Span::merge(start, self.prev_span()),
1599        ))
1600    }
1601
1602    /// Parse typed params until we see ->. Handles: `x`, `x: int`, `x, y`, `x: int, y: string`.
1603    fn parse_typed_param_list_until_arrow(&mut self) -> Result<Vec<TypedParam>, ParserError> {
1604        let mut params = Vec::new();
1605        self.skip_newlines();
1606        while !self.is_at_end() && !self.check(&TokenKind::Arrow) {
1607            let name = self.consume_identifier("parameter name")?;
1608            let type_expr = self.try_parse_type_annotation()?;
1609            params.push(TypedParam { name, type_expr });
1610            if self.check(&TokenKind::Comma) {
1611                self.advance();
1612                self.skip_newlines();
1613            }
1614        }
1615        Ok(params)
1616    }
1617
1618    fn parse_dict_literal(&mut self, start: Span) -> Result<SNode, ParserError> {
1619        let mut entries = Vec::new();
1620        self.skip_newlines();
1621
1622        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1623            // Check for spread: ...expr
1624            if self.check(&TokenKind::Dot) {
1625                let saved_pos = self.pos;
1626                self.advance(); // first .
1627                if self.check(&TokenKind::Dot) {
1628                    self.advance(); // second .
1629                    if self.check(&TokenKind::Dot) {
1630                        self.advance(); // third .
1631                        let spread_start = self.tokens[saved_pos].span;
1632                        let expr = self.parse_expression()?;
1633                        entries.push(DictEntry {
1634                            key: spanned(Node::NilLiteral, spread_start),
1635                            value: spanned(
1636                                Node::Spread(Box::new(expr)),
1637                                Span::merge(spread_start, self.prev_span()),
1638                            ),
1639                        });
1640                        self.skip_newlines();
1641                        if self.check(&TokenKind::Comma) {
1642                            self.advance();
1643                            self.skip_newlines();
1644                        }
1645                        continue;
1646                    }
1647                    // Not three dots — restore
1648                    self.pos = saved_pos;
1649                } else {
1650                    self.pos = saved_pos;
1651                }
1652            }
1653            let key = if self.check(&TokenKind::LBracket) {
1654                // Computed key: [expression]
1655                self.advance();
1656                let k = self.parse_expression()?;
1657                self.consume(&TokenKind::RBracket, "]")?;
1658                k
1659            } else if matches!(
1660                self.current().map(|t| &t.kind),
1661                Some(TokenKind::StringLiteral(_))
1662            ) {
1663                // Quoted string key: {"key": value}
1664                let key_span = self.current_span();
1665                let name =
1666                    if let Some(TokenKind::StringLiteral(s)) = self.current().map(|t| &t.kind) {
1667                        s.clone()
1668                    } else {
1669                        unreachable!()
1670                    };
1671                self.advance();
1672                spanned(Node::StringLiteral(name), key_span)
1673            } else {
1674                // Static key: identifier or keyword -> string literal
1675                let key_span = self.current_span();
1676                let name = self.consume_identifier_or_keyword("dict key")?;
1677                spanned(Node::StringLiteral(name), key_span)
1678            };
1679            self.consume(&TokenKind::Colon, ":")?;
1680            let value = self.parse_expression()?;
1681            entries.push(DictEntry { key, value });
1682            self.skip_newlines();
1683            if self.check(&TokenKind::Comma) {
1684                self.advance();
1685                self.skip_newlines();
1686            }
1687        }
1688
1689        self.consume(&TokenKind::RBrace, "}")?;
1690        Ok(spanned(
1691            Node::DictLiteral(entries),
1692            Span::merge(start, self.prev_span()),
1693        ))
1694    }
1695
1696    // --- Helpers ---
1697
1698    /// Parse untyped parameter list (for pipelines, overrides).
1699    fn parse_param_list(&mut self) -> Result<Vec<String>, ParserError> {
1700        let mut params = Vec::new();
1701        self.skip_newlines();
1702
1703        while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1704            params.push(self.consume_identifier("parameter name")?);
1705            if self.check(&TokenKind::Comma) {
1706                self.advance();
1707                self.skip_newlines();
1708            }
1709        }
1710        Ok(params)
1711    }
1712
1713    /// Parse typed parameter list (for fn declarations).
1714    fn parse_typed_param_list(&mut self) -> Result<Vec<TypedParam>, ParserError> {
1715        let mut params = Vec::new();
1716        self.skip_newlines();
1717
1718        while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1719            let name = self.consume_identifier("parameter name")?;
1720            let type_expr = self.try_parse_type_annotation()?;
1721            params.push(TypedParam { name, type_expr });
1722            if self.check(&TokenKind::Comma) {
1723                self.advance();
1724                self.skip_newlines();
1725            }
1726        }
1727        Ok(params)
1728    }
1729
1730    /// Parse a comma-separated list of type parameter names until `>`.
1731    fn parse_type_param_list(&mut self) -> Result<Vec<TypeParam>, ParserError> {
1732        let mut params = Vec::new();
1733        self.skip_newlines();
1734        while !self.is_at_end() && !self.check(&TokenKind::Gt) {
1735            let name = self.consume_identifier("type parameter name")?;
1736            params.push(TypeParam { name });
1737            if self.check(&TokenKind::Comma) {
1738                self.advance();
1739                self.skip_newlines();
1740            }
1741        }
1742        self.consume(&TokenKind::Gt, ">")?;
1743        Ok(params)
1744    }
1745
1746    /// Parse an optional `where T: bound, U: bound` clause.
1747    /// Looks for an identifier "where" before `{`.
1748    fn parse_where_clauses(&mut self) -> Result<Vec<WhereClause>, ParserError> {
1749        // Check if the next identifier is "where"
1750        if let Some(tok) = self.current() {
1751            if let TokenKind::Identifier(ref id) = tok.kind {
1752                if id == "where" {
1753                    self.advance(); // skip "where"
1754                    let mut clauses = Vec::new();
1755                    loop {
1756                        self.skip_newlines();
1757                        // Stop if we hit `{` or EOF
1758                        if self.check(&TokenKind::LBrace) || self.is_at_end() {
1759                            break;
1760                        }
1761                        let type_name = self.consume_identifier("type parameter name")?;
1762                        self.consume(&TokenKind::Colon, ":")?;
1763                        let bound = self.consume_identifier("type bound")?;
1764                        clauses.push(WhereClause { type_name, bound });
1765                        if self.check(&TokenKind::Comma) {
1766                            self.advance();
1767                        } else {
1768                            break;
1769                        }
1770                    }
1771                    return Ok(clauses);
1772                }
1773            }
1774        }
1775        Ok(Vec::new())
1776    }
1777
1778    /// Try to parse an optional type annotation (`: type`).
1779    /// Returns None if no colon follows.
1780    fn try_parse_type_annotation(&mut self) -> Result<Option<TypeExpr>, ParserError> {
1781        if !self.check(&TokenKind::Colon) {
1782            return Ok(None);
1783        }
1784        self.advance(); // skip :
1785        Ok(Some(self.parse_type_expr()?))
1786    }
1787
1788    /// Parse a type expression: `int`, `string | nil`, `{name: string, age?: int}`.
1789    fn parse_type_expr(&mut self) -> Result<TypeExpr, ParserError> {
1790        self.skip_newlines();
1791        let first = self.parse_type_primary()?;
1792
1793        // Check for union: type | type | ...
1794        if self.check(&TokenKind::Bar) {
1795            let mut types = vec![first];
1796            while self.check(&TokenKind::Bar) {
1797                self.advance(); // skip |
1798                types.push(self.parse_type_primary()?);
1799            }
1800            return Ok(TypeExpr::Union(types));
1801        }
1802
1803        Ok(first)
1804    }
1805
1806    /// Parse a primary type: named type or shape type.
1807    /// Accepts identifiers and certain keywords (nil, bool, etc.) as type names.
1808    fn parse_type_primary(&mut self) -> Result<TypeExpr, ParserError> {
1809        self.skip_newlines();
1810        if self.check(&TokenKind::LBrace) {
1811            return self.parse_shape_type();
1812        }
1813        // Accept keyword type names: nil, true, false map to their type names
1814        if let Some(tok) = self.current() {
1815            let type_name = match &tok.kind {
1816                TokenKind::Nil => {
1817                    self.advance();
1818                    return Ok(TypeExpr::Named("nil".to_string()));
1819                }
1820                TokenKind::True | TokenKind::False => {
1821                    self.advance();
1822                    return Ok(TypeExpr::Named("bool".to_string()));
1823                }
1824                _ => None,
1825            };
1826            if let Some(name) = type_name {
1827                return Ok(TypeExpr::Named(name));
1828            }
1829        }
1830        // Function type: fn(T, U) -> R
1831        if self.check(&TokenKind::Fn) {
1832            self.advance(); // skip `fn`
1833            self.consume(&TokenKind::LParen, "(")?;
1834            let mut params = Vec::new();
1835            self.skip_newlines();
1836            while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1837                params.push(self.parse_type_expr()?);
1838                self.skip_newlines();
1839                if self.check(&TokenKind::Comma) {
1840                    self.advance();
1841                    self.skip_newlines();
1842                }
1843            }
1844            self.consume(&TokenKind::RParen, ")")?;
1845            self.consume(&TokenKind::Arrow, "->")?;
1846            let return_type = self.parse_type_expr()?;
1847            return Ok(TypeExpr::FnType {
1848                params,
1849                return_type: Box::new(return_type),
1850            });
1851        }
1852        let name = self.consume_identifier("type name")?;
1853        // Check for generic type parameters: list<int>, dict<string, int>
1854        if self.check(&TokenKind::Lt) {
1855            self.advance(); // skip <
1856            let first_param = self.parse_type_expr()?;
1857            if name == "list" {
1858                self.consume(&TokenKind::Gt, ">")?;
1859                return Ok(TypeExpr::List(Box::new(first_param)));
1860            } else if name == "dict" {
1861                self.consume(&TokenKind::Comma, ",")?;
1862                let second_param = self.parse_type_expr()?;
1863                self.consume(&TokenKind::Gt, ">")?;
1864                return Ok(TypeExpr::DictType(
1865                    Box::new(first_param),
1866                    Box::new(second_param),
1867                ));
1868            }
1869            // Unknown generic — just consume > and treat as Named
1870            self.consume(&TokenKind::Gt, ">")?;
1871        }
1872        Ok(TypeExpr::Named(name))
1873    }
1874
1875    /// Parse a shape type: `{ name: string, age: int, active?: bool }`.
1876    fn parse_shape_type(&mut self) -> Result<TypeExpr, ParserError> {
1877        self.consume(&TokenKind::LBrace, "{")?;
1878        let mut fields = Vec::new();
1879        self.skip_newlines();
1880
1881        while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1882            let name = self.consume_identifier("field name")?;
1883            let optional = if self.check(&TokenKind::Question) {
1884                self.advance();
1885                true
1886            } else {
1887                false
1888            };
1889            self.consume(&TokenKind::Colon, ":")?;
1890            let type_expr = self.parse_type_expr()?;
1891            fields.push(ShapeField {
1892                name,
1893                type_expr,
1894                optional,
1895            });
1896            self.skip_newlines();
1897            if self.check(&TokenKind::Comma) {
1898                self.advance();
1899                self.skip_newlines();
1900            }
1901        }
1902
1903        self.consume(&TokenKind::RBrace, "}")?;
1904        Ok(TypeExpr::Shape(fields))
1905    }
1906
1907    fn parse_arg_list(&mut self) -> Result<Vec<SNode>, ParserError> {
1908        let mut args = Vec::new();
1909        self.skip_newlines();
1910
1911        while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1912            args.push(self.parse_expression()?);
1913            self.skip_newlines();
1914            if self.check(&TokenKind::Comma) {
1915                self.advance();
1916                self.skip_newlines();
1917            }
1918        }
1919        Ok(args)
1920    }
1921
1922    fn is_at_end(&self) -> bool {
1923        self.pos >= self.tokens.len()
1924            || matches!(self.tokens.get(self.pos), Some(t) if t.kind == TokenKind::Eof)
1925    }
1926
1927    fn current(&self) -> Option<&Token> {
1928        self.tokens.get(self.pos)
1929    }
1930
1931    fn peek_kind(&self) -> Option<&TokenKind> {
1932        self.tokens.get(self.pos + 1).map(|t| &t.kind)
1933    }
1934
1935    fn check(&self, kind: &TokenKind) -> bool {
1936        self.current()
1937            .map(|t| std::mem::discriminant(&t.kind) == std::mem::discriminant(kind))
1938            .unwrap_or(false)
1939    }
1940
1941    /// Check for a token kind, skipping past any newlines first.
1942    /// Used for binary operators like `||` and `&&` that can span lines.
1943    fn check_skip_newlines(&mut self, kind: &TokenKind) -> bool {
1944        let saved = self.pos;
1945        self.skip_newlines();
1946        if self.check(kind) {
1947            true
1948        } else {
1949            self.pos = saved;
1950            false
1951        }
1952    }
1953
1954    fn advance(&mut self) {
1955        if self.pos < self.tokens.len() {
1956            self.pos += 1;
1957        }
1958    }
1959
1960    fn consume(&mut self, kind: &TokenKind, expected: &str) -> Result<Token, ParserError> {
1961        self.skip_newlines();
1962        let tok = self.current().ok_or_else(|| self.make_error(expected))?;
1963        if std::mem::discriminant(&tok.kind) != std::mem::discriminant(kind) {
1964            return Err(self.make_error(expected));
1965        }
1966        let tok = tok.clone();
1967        self.advance();
1968        Ok(tok)
1969    }
1970
1971    fn consume_identifier(&mut self, expected: &str) -> Result<String, ParserError> {
1972        self.skip_newlines();
1973        let tok = self.current().ok_or_else(|| self.make_error(expected))?;
1974        if let TokenKind::Identifier(name) = &tok.kind {
1975            let name = name.clone();
1976            self.advance();
1977            Ok(name)
1978        } else {
1979            Err(self.make_error(expected))
1980        }
1981    }
1982
1983    /// Like `consume_identifier`, but also accepts keywords as identifiers.
1984    /// Used for property access (e.g., `obj.type`) and dict keys where
1985    /// keywords are valid member names.
1986    fn consume_identifier_or_keyword(&mut self, expected: &str) -> Result<String, ParserError> {
1987        self.skip_newlines();
1988        let tok = self.current().ok_or_else(|| self.make_error(expected))?;
1989        if let TokenKind::Identifier(name) = &tok.kind {
1990            let name = name.clone();
1991            self.advance();
1992            return Ok(name);
1993        }
1994        // Accept any keyword token as an identifier
1995        let name = match &tok.kind {
1996            TokenKind::Pipeline => "pipeline",
1997            TokenKind::Extends => "extends",
1998            TokenKind::Override => "override",
1999            TokenKind::Let => "let",
2000            TokenKind::Var => "var",
2001            TokenKind::If => "if",
2002            TokenKind::Else => "else",
2003            TokenKind::For => "for",
2004            TokenKind::In => "in",
2005            TokenKind::Match => "match",
2006            TokenKind::Retry => "retry",
2007            TokenKind::Parallel => "parallel",
2008            TokenKind::ParallelMap => "parallel_map",
2009            TokenKind::Return => "return",
2010            TokenKind::Import => "import",
2011            TokenKind::True => "true",
2012            TokenKind::False => "false",
2013            TokenKind::Nil => "nil",
2014            TokenKind::Try => "try",
2015            TokenKind::Catch => "catch",
2016            TokenKind::Throw => "throw",
2017            TokenKind::Fn => "fn",
2018            TokenKind::Spawn => "spawn",
2019            TokenKind::While => "while",
2020            TokenKind::TypeKw => "type",
2021            TokenKind::Enum => "enum",
2022            TokenKind::Struct => "struct",
2023            TokenKind::Interface => "interface",
2024            TokenKind::Pub => "pub",
2025            TokenKind::From => "from",
2026            TokenKind::Thru => "thru",
2027            TokenKind::Upto => "upto",
2028            TokenKind::Guard => "guard",
2029            TokenKind::Ask => "ask",
2030            TokenKind::Deadline => "deadline",
2031            TokenKind::Yield => "yield",
2032            TokenKind::Mutex => "mutex",
2033            TokenKind::Break => "break",
2034            TokenKind::Continue => "continue",
2035            _ => return Err(self.make_error(expected)),
2036        };
2037        let name = name.to_string();
2038        self.advance();
2039        Ok(name)
2040    }
2041
2042    fn skip_newlines(&mut self) {
2043        while self.pos < self.tokens.len() && self.tokens[self.pos].kind == TokenKind::Newline {
2044            self.pos += 1;
2045        }
2046    }
2047
2048    fn make_error(&self, expected: &str) -> ParserError {
2049        if let Some(tok) = self.tokens.get(self.pos) {
2050            if tok.kind == TokenKind::Eof {
2051                return ParserError::UnexpectedEof {
2052                    expected: expected.into(),
2053                };
2054            }
2055            ParserError::Unexpected {
2056                got: tok.kind.to_string(),
2057                expected: expected.into(),
2058                span: tok.span,
2059            }
2060        } else {
2061            ParserError::UnexpectedEof {
2062                expected: expected.into(),
2063            }
2064        }
2065    }
2066
2067    fn error(&self, expected: &str) -> ParserError {
2068        self.make_error(expected)
2069    }
2070}