Skip to main content

tupa_parser/
lib.rs

1use serde::Serialize;
2use thiserror::Error;
3pub use tupa_lexer::{lex_with_spans, LexerError, Span, Token, TokenSpan};
4
5#[derive(Debug, Clone, PartialEq, Serialize)]
6pub struct Program {
7    pub items: Vec<Item>,
8}
9
10#[derive(Debug, Clone, PartialEq, Serialize)]
11pub enum Item {
12    Function(Function),
13    Enum(EnumDef),
14    Trait(TraitDef),
15    Pipeline(PipelineDecl),
16}
17
18#[derive(Debug, Clone, PartialEq, Serialize)]
19pub struct Attribute {
20    pub name: String,
21    pub args: Vec<String>,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize)]
25pub struct ExternalSpec {
26    pub python: Option<String>,
27    pub effects: Vec<String>,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize)]
31pub struct EnumDef {
32    pub name: String,
33    pub generics: Vec<String>,
34    pub variants: Vec<EnumVariant>,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize)]
38pub struct EnumVariant {
39    pub name: String,
40    pub args: Vec<Type>,
41}
42
43#[derive(Debug, Clone, PartialEq, Serialize)]
44pub struct TraitDef {
45    pub name: String,
46    pub methods: Vec<Function>,
47}
48
49#[derive(Debug, Clone, PartialEq, Serialize)]
50pub struct PipelineDecl {
51    pub name: String,
52    pub attrs: Vec<Attribute>,
53    pub seed: Option<u64>,
54    pub input_ty: Type,
55    pub output_ty: Option<Type>,
56    pub constraints: Vec<Constraint>,
57    pub steps: Vec<PipelineStep>,
58    pub validation: Option<Block>,
59    pub span: Span,
60}
61
62#[derive(Debug, Clone, PartialEq, Serialize)]
63pub enum Comparator {
64    Lt,
65    Le,
66    Eq,
67    Ge,
68    Gt,
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize)]
72pub struct Constraint {
73    pub metric: String,
74    pub comparator: Comparator,
75    pub threshold: f64,
76    pub span: Span,
77}
78
79#[derive(Debug, Clone, PartialEq, Serialize)]
80pub struct PipelineStep {
81    pub name: String,
82    pub body: Expr,
83    pub span: Span,
84}
85
86#[derive(Debug, Clone, PartialEq, Serialize)]
87pub struct Function {
88    pub name: String,
89    pub params: Vec<Param>,
90    pub return_type: Option<Type>,
91    pub body: Vec<Stmt>,
92    pub attrs: Vec<Attribute>,
93    pub external_spec: Option<ExternalSpec>,
94}
95
96#[derive(Debug, Clone, PartialEq, Serialize)]
97pub struct Param {
98    pub name: String,
99    pub ty: Type,
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize)]
103pub enum Stmt {
104    Let {
105        name: String,
106        ty: Option<Type>,
107        expr: Expr,
108    },
109    Return(Option<Expr>),
110    While {
111        condition: Expr,
112        body: Block,
113    },
114    For {
115        name: String,
116        iter: Expr,
117        body: Block,
118    },
119    Break,
120    Continue,
121    Expr(Expr),
122    Lambda {
123        params: Vec<String>,
124        body: Box<Expr>,
125    },
126}
127#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
128pub struct TensorType {
129    pub dtype: String,
130    pub shape: Vec<Option<i64>>,
131}
132
133#[derive(Debug, Clone, PartialEq, Serialize)]
134pub enum Type {
135    Ident(String),
136    Generic {
137        name: String,
138        args: Vec<Type>,
139    },
140    Tuple(Vec<Type>),
141    Safe {
142        base: Box<Type>,
143        constraints: Vec<String>,
144    },
145    Array {
146        elem: Box<Type>,
147        len: i64,
148    },
149    Slice {
150        elem: Box<Type>,
151    },
152    Func {
153        params: Vec<Type>,
154        ret: Box<Type>,
155    },
156    Tensor(TensorType),
157    Unit,
158}
159
160#[derive(Debug, Clone, PartialEq, Serialize)]
161pub struct Expr {
162    pub kind: ExprKind,
163    pub span: Span,
164}
165
166#[derive(Debug, Clone, PartialEq, Serialize)]
167pub enum ExprKind {
168    Lambda {
169        params: Vec<String>,
170        body: Box<Expr>,
171    },
172    Int(i64),
173    Float(f64),
174    Str(String),
175    Bool(bool),
176    Null,
177    Ident(String),
178    Tuple(Vec<Expr>),
179    Assign {
180        name: String,
181        expr: Box<Expr>,
182    },
183    AssignIndex {
184        expr: Box<Expr>,
185        index: Box<Expr>,
186        value: Box<Expr>,
187    },
188    ArrayLiteral(Vec<Expr>),
189    Call {
190        callee: Box<Expr>,
191        args: Vec<Expr>,
192    },
193    Field {
194        expr: Box<Expr>,
195        field: FieldAccess,
196    },
197    Index {
198        expr: Box<Expr>,
199        index: Box<Expr>,
200    },
201    Await(Box<Expr>),
202    Block(Block),
203    If {
204        condition: Box<Expr>,
205        then_branch: Block,
206        else_branch: Option<ElseBranch>,
207    },
208    Match {
209        expr: Box<Expr>,
210        arms: Vec<MatchArm>,
211    },
212    Unary {
213        op: UnaryOp,
214        expr: Box<Expr>,
215    },
216    Binary {
217        op: BinaryOp,
218        left: Box<Expr>,
219        right: Box<Expr>,
220    },
221}
222
223pub type Block = Vec<Stmt>;
224
225#[derive(Debug, Clone, PartialEq, Serialize)]
226pub enum ElseBranch {
227    Block(Block),
228    If(Box<Expr>),
229}
230
231#[derive(Debug, Clone, PartialEq, Serialize)]
232pub struct MatchArm {
233    pub pattern: Pattern,
234    pub pattern_span: Span,
235    pub guard: Option<Expr>,
236    pub expr: Expr,
237}
238
239#[derive(Debug, Clone, PartialEq, Serialize)]
240pub enum Pattern {
241    Wildcard,
242    Int(i64),
243    Str(String),
244    Bool(bool),
245    Ident(String),
246    Tuple(Vec<Pattern>),
247    Constructor { name: String, args: Vec<Pattern> },
248}
249
250#[derive(Debug, Clone, PartialEq, Serialize)]
251pub enum FieldAccess {
252    Ident(String),
253    Index(i64),
254}
255
256#[derive(Debug, Clone, PartialEq, Serialize)]
257pub enum UnaryOp {
258    Not,
259    Neg,
260}
261
262#[derive(Debug, Clone, PartialEq, Serialize)]
263pub enum BinaryOp {
264    Range,
265    Or,
266    And,
267    Equal,
268    NotEqual,
269    Less,
270    LessEqual,
271    Greater,
272    GreaterEqual,
273    Add,
274    Sub,
275    Mul,
276    Div,
277    Mod,
278    Pow,
279}
280
281#[derive(Debug, Error)]
282pub enum ParserError {
283    #[error("lexer error: {0}")]
284    Lexer(#[from] LexerError),
285    #[error("unexpected token {0:?} at {1:?}")]
286    Unexpected(Token, Span),
287    #[error("expected ';' after expression")]
288    MissingSemicolon(Span),
289    #[error("unexpected end of input at position {0}")]
290    Eof(usize),
291}
292
293impl Expr {
294    fn new(kind: ExprKind, span: Span) -> Self {
295        Self { kind, span }
296    }
297}
298
299fn merge_span(start: Span, end: Span) -> Span {
300    Span {
301        start: start.start,
302        end: end.end,
303    }
304}
305
306fn token_to_string(token: &Token) -> String {
307    match token {
308        Token::Ident(s) | Token::Int(s) | Token::Float(s) | Token::Str(s) => s.clone(),
309        Token::Fn => "fn".to_string(),
310        Token::Enum => "enum".to_string(),
311        Token::Trait => "trait".to_string(),
312        Token::Pipeline => "pipeline".to_string(),
313        Token::Step => "step".to_string(),
314        Token::Let => "let".to_string(),
315        Token::Return => "return".to_string(),
316        Token::If => "if".to_string(),
317        Token::Else => "else".to_string(),
318        Token::Match => "match".to_string(),
319        Token::While => "while".to_string(),
320        Token::For => "for".to_string(),
321        Token::Break => "break".to_string(),
322        Token::Continue => "continue".to_string(),
323        Token::In => "in".to_string(),
324        Token::Await => "await".to_string(),
325        Token::True => "true".to_string(),
326        Token::False => "false".to_string(),
327        Token::Null => "null".to_string(),
328        Token::LParen => "(".to_string(),
329        Token::RParen => ")".to_string(),
330        Token::LBrace => "{".to_string(),
331        Token::RBrace => "}".to_string(),
332        Token::LBracket => "[".to_string(),
333        Token::RBracket => "]".to_string(),
334        Token::Semicolon => ";".to_string(),
335        Token::Comma => ",".to_string(),
336        Token::Colon => ":".to_string(),
337        Token::Equal => "=".to_string(),
338        Token::Arrow => "=>".to_string(),
339        Token::ThinArrow => "->".to_string(),
340        Token::EqualEqual => "==".to_string(),
341        Token::BangEqual => "!=".to_string(),
342        Token::Less => "<".to_string(),
343        Token::LessEqual => "<=".to_string(),
344        Token::Greater => ">".to_string(),
345        Token::GreaterEqual => ">=".to_string(),
346        Token::AndAnd => "&&".to_string(),
347        Token::OrOr => "||".to_string(),
348        Token::Plus => "+".to_string(),
349        Token::PlusEqual => "+=".to_string(),
350        Token::Minus => "-".to_string(),
351        Token::MinusEqual => "-=".to_string(),
352        Token::Star => "*".to_string(),
353        Token::StarEqual => "*=".to_string(),
354        Token::Slash => "/".to_string(),
355        Token::SlashEqual => "/=".to_string(),
356        Token::DoubleStar => "**".to_string(),
357        Token::DotDot => "..".to_string(),
358        Token::Dot => ".".to_string(),
359        Token::Bang => "!".to_string(),
360        Token::Pipe => "|".to_string(),
361        Token::At => "@".to_string(),
362        Token::Percent => "%".to_string(),
363        Token::PercentEqual => "%=".to_string(),
364    }
365}
366
367fn parse_external_effect_item(tokens: &[String]) -> Option<String> {
368    if tokens.is_empty() {
369        return None;
370    }
371
372    if tokens.len() == 1 {
373        return Some(tokens[0].clone());
374    }
375
376    if tokens[0] == "ExternalCall"
377        && tokens.get(1).is_some_and(|t| t == "(")
378        && tokens.last().is_some_and(|t| t == ")")
379        && tokens.len() >= 4
380    {
381        let inner = tokens[2..tokens.len() - 1].join("");
382        return Some(format!("ExternalCall({inner})"));
383    }
384
385    Some(tokens.join(""))
386}
387
388fn parse_external_spec(args: &[String]) -> ExternalSpec {
389    let mut spec = ExternalSpec {
390        python: None,
391        effects: Vec::new(),
392    };
393
394    if args.is_empty() {
395        return spec;
396    }
397
398    if !args.iter().any(|a| a == "=") {
399        spec.python = args.first().cloned();
400        return spec;
401    }
402
403    let mut i = 0;
404    while i < args.len() {
405        let key = &args[i];
406
407        if i + 1 >= args.len() || args[i + 1] != "=" {
408            i += 1;
409            continue;
410        }
411
412        if key == "python" {
413            if let Some(value) = args.get(i + 2) {
414                spec.python = Some(value.clone());
415            }
416            i += 3;
417            continue;
418        }
419
420        if key == "effects" {
421            if args.get(i + 2).is_some_and(|t| t == "[") {
422                let mut j = i + 3;
423                let mut bracket_depth = 1;
424                let mut paren_depth = 0;
425                let mut current = Vec::new();
426
427                while j < args.len() {
428                    let tok = &args[j];
429                    match tok.as_str() {
430                        "[" => {
431                            bracket_depth += 1;
432                            if bracket_depth > 1 {
433                                current.push(tok.clone());
434                            }
435                        }
436                        "]" => {
437                            bracket_depth -= 1;
438                            if bracket_depth == 0 {
439                                if let Some(effect) = parse_external_effect_item(&current) {
440                                    spec.effects.push(effect);
441                                }
442                                break;
443                            }
444                            current.push(tok.clone());
445                        }
446                        "," if bracket_depth == 1 && paren_depth == 0 => {
447                            if let Some(effect) = parse_external_effect_item(&current) {
448                                spec.effects.push(effect);
449                            }
450                            current.clear();
451                        }
452                        "(" => {
453                            paren_depth += 1;
454                            current.push(tok.clone());
455                        }
456                        ")" => {
457                            if paren_depth > 0 {
458                                paren_depth -= 1;
459                            }
460                            current.push(tok.clone());
461                        }
462                        _ => current.push(tok.clone()),
463                    }
464                    j += 1;
465                }
466
467                i = j + 1;
468                continue;
469            }
470
471            if let Some(value) = args.get(i + 2) {
472                spec.effects.push(value.clone());
473            }
474            i += 3;
475            continue;
476        }
477
478        i += 1;
479    }
480
481    spec
482}
483pub fn parse_program(input: &str) -> Result<Program, ParserError> {
484    let tokens = lex_with_spans(input)?;
485    let mut parser = Parser::new(tokens, input.len());
486    let mut items = Vec::new();
487
488    while !parser.is_eof() {
489        items.push(parser.parse_item()?);
490    }
491
492    Ok(Program { items })
493}
494
495struct Parser {
496    tokens: Vec<TokenSpan>,
497    pos: usize,
498    eof_pos: usize,
499}
500
501impl Parser {
502    fn new(tokens: Vec<TokenSpan>, eof_pos: usize) -> Self {
503        Self {
504            tokens,
505            pos: 0,
506            eof_pos,
507        }
508    }
509
510    fn is_eof(&self) -> bool {
511        self.pos >= self.tokens.len()
512    }
513
514    fn peek(&self) -> Option<&Token> {
515        self.tokens.get(self.pos).map(|t| &t.token)
516    }
517
518    fn peek_next(&self) -> Option<&Token> {
519        self.tokens.get(self.pos + 1).map(|t| &t.token)
520    }
521
522    fn is_index_assignment(&self) -> bool {
523        if !matches!(self.peek(), Some(Token::Ident(_))) {
524            return false;
525        }
526        if !matches!(self.peek_next(), Some(Token::LBracket)) {
527            return false;
528        }
529        let mut depth = 0usize;
530        let mut idx = self.pos + 1;
531        while idx < self.tokens.len() {
532            match &self.tokens[idx].token {
533                Token::LBracket => depth += 1,
534                Token::RBracket => {
535                    if depth == 1 {
536                        return matches!(
537                            self.tokens.get(idx + 1).map(|t| &t.token),
538                            Some(Token::Equal)
539                        );
540                    }
541                    depth = depth.saturating_sub(1);
542                }
543                _ => {}
544            }
545            idx += 1;
546        }
547        false
548    }
549
550    fn next(&mut self) -> Option<TokenSpan> {
551        let tok = self.tokens.get(self.pos).cloned();
552        self.pos += 1;
553        tok
554    }
555
556    fn expect(&mut self, expected: Token) -> Result<(), ParserError> {
557        match self.next() {
558            Some(TokenSpan { token, .. }) if token == expected => Ok(()),
559            Some(TokenSpan { token, span }) => Err(ParserError::Unexpected(token, span)),
560            None => Err(ParserError::Eof(self.eof_pos)),
561        }
562    }
563
564    fn expect_span(&mut self, expected: Token) -> Result<Span, ParserError> {
565        match self.next() {
566            Some(TokenSpan { token, span }) if token == expected => Ok(span),
567            Some(TokenSpan { token, span }) => Err(ParserError::Unexpected(token, span)),
568            None => Err(ParserError::Eof(self.eof_pos)),
569        }
570    }
571
572    fn parse_item(&mut self) -> Result<Item, ParserError> {
573        let mut attrs = Vec::new();
574        while matches!(self.peek(), Some(Token::At)) {
575            attrs.push(self.parse_attribute()?);
576        }
577        match self.peek() {
578            Some(Token::Fn) => Ok(Item::Function(self.parse_function(attrs)?)),
579            Some(Token::Enum) => Ok(Item::Enum(self.parse_enum()?)),
580            Some(Token::Trait) => Ok(Item::Trait(self.parse_trait()?)),
581            Some(Token::Pipeline) => Ok(Item::Pipeline(self.parse_pipeline(attrs)?)),
582            Some(token) => {
583                let span = self.tokens.get(self.pos).map(|t| t.span).unwrap_or(Span {
584                    start: self.eof_pos,
585                    end: self.eof_pos,
586                });
587                Err(ParserError::Unexpected(token.clone(), span))
588            }
589            None => Err(ParserError::Eof(self.eof_pos)),
590        }
591    }
592
593    fn parse_attribute(&mut self) -> Result<Attribute, ParserError> {
594        self.expect(Token::At)?;
595        let name = match self.next() {
596            Some(TokenSpan {
597                token: Token::Ident(name),
598                ..
599            }) => name,
600            Some(TokenSpan { token, span }) => return Err(ParserError::Unexpected(token, span)),
601            None => return Err(ParserError::Eof(self.eof_pos)),
602        };
603        let mut args = Vec::new();
604        if matches!(self.peek(), Some(Token::LParen)) {
605            self.expect(Token::LParen)?;
606
607            let mut depth = 0;
608            while let Some(tok) = self.peek() {
609                if depth == 0 && *tok == Token::RParen {
610                    break;
611                }
612
613                let token_span = self.next().ok_or(ParserError::Eof(self.eof_pos))?;
614                let token = token_span.token;
615
616                match &token {
617                    Token::LParen | Token::LBracket | Token::LBrace => {
618                        depth += 1;
619                        args.push(token_to_string(&token));
620                    }
621                    Token::RParen | Token::RBracket | Token::RBrace => {
622                        if depth > 0 {
623                            depth -= 1;
624                        }
625                        args.push(token_to_string(&token));
626                    }
627                    Token::Comma => {
628                        if depth > 0 {
629                            args.push(",".to_string());
630                        }
631                    }
632                    _ => {
633                        args.push(token_to_string(&token));
634                    }
635                }
636            }
637
638            self.expect(Token::RParen)?;
639        }
640        Ok(Attribute { name, args })
641    }
642
643    fn parse_function(&mut self, attrs: Vec<Attribute>) -> Result<Function, ParserError> {
644        self.expect(Token::Fn)?;
645        let name = match self.next() {
646            Some(TokenSpan {
647                token: Token::Ident(name),
648                ..
649            }) => name,
650            Some(TokenSpan { token, span }) => return Err(ParserError::Unexpected(token, span)),
651            None => return Err(ParserError::Eof(self.eof_pos)),
652        };
653        self.expect(Token::LParen)?;
654        let params = self.parse_params()?;
655        self.expect(Token::RParen)?;
656        let return_type = if matches!(self.peek(), Some(Token::Colon)) {
657            self.next();
658            Some(self.parse_type()?)
659        } else {
660            None
661        };
662        let body = self.parse_block()?;
663        let external_spec = attrs
664            .iter()
665            .find(|attr| attr.name == "external")
666            .map(|attr| parse_external_spec(&attr.args));
667
668        Ok(Function {
669            name,
670            params,
671            return_type,
672            body,
673            attrs,
674            external_spec,
675        })
676    }
677
678    fn parse_enum(&mut self) -> Result<EnumDef, ParserError> {
679        self.expect(Token::Enum)?;
680        let name = match self.next() {
681            Some(TokenSpan {
682                token: Token::Ident(name),
683                ..
684            }) => name,
685            Some(TokenSpan { token, span }) => return Err(ParserError::Unexpected(token, span)),
686            None => return Err(ParserError::Eof(self.eof_pos)),
687        };
688        let mut generics = Vec::new();
689        if matches!(self.peek(), Some(Token::Less)) {
690            self.next();
691            loop {
692                let param = match self.next() {
693                    Some(TokenSpan {
694                        token: Token::Ident(name),
695                        ..
696                    }) => name,
697                    Some(TokenSpan { token, span }) => {
698                        return Err(ParserError::Unexpected(token, span))
699                    }
700                    None => return Err(ParserError::Eof(self.eof_pos)),
701                };
702                generics.push(param);
703                if matches!(self.peek(), Some(Token::Comma)) {
704                    self.next();
705                    if matches!(self.peek(), Some(Token::Greater)) {
706                        break;
707                    }
708                } else {
709                    break;
710                }
711            }
712            self.expect(Token::Greater)?;
713        }
714        self.expect(Token::LBrace)?;
715        let mut variants = Vec::new();
716        while let Some(tok) = self.peek() {
717            if *tok == Token::RBrace {
718                break;
719            }
720            match self.next() {
721                Some(TokenSpan {
722                    token: Token::Ident(variant),
723                    ..
724                }) => {
725                    let args = if matches!(self.peek(), Some(Token::LParen)) {
726                        self.next();
727                        let mut args = Vec::new();
728                        if !matches!(self.peek(), Some(Token::RParen)) {
729                            loop {
730                                args.push(self.parse_type()?);
731                                if matches!(self.peek(), Some(Token::Comma)) {
732                                    self.next();
733                                    if matches!(self.peek(), Some(Token::RParen)) {
734                                        break;
735                                    }
736                                } else {
737                                    break;
738                                }
739                            }
740                        }
741                        self.expect(Token::RParen)?;
742                        args
743                    } else {
744                        Vec::new()
745                    };
746                    variants.push(EnumVariant {
747                        name: variant,
748                        args,
749                    });
750                }
751                Some(TokenSpan { token, span }) => {
752                    return Err(ParserError::Unexpected(token, span))
753                }
754                None => return Err(ParserError::Eof(self.eof_pos)),
755            }
756            if let Some(Token::Comma) = self.peek() {
757                self.next();
758            }
759        }
760        self.expect(Token::RBrace)?;
761        Ok(EnumDef {
762            name,
763            generics,
764            variants,
765        })
766    }
767
768    fn parse_trait(&mut self) -> Result<TraitDef, ParserError> {
769        self.expect(Token::Trait)?;
770        let name = match self.next() {
771            Some(TokenSpan {
772                token: Token::Ident(name),
773                ..
774            }) => name,
775            Some(TokenSpan { token, span }) => return Err(ParserError::Unexpected(token, span)),
776            None => return Err(ParserError::Eof(self.eof_pos)),
777        };
778        self.expect(Token::LBrace)?;
779        let mut methods = Vec::new();
780        while let Some(token) = self.peek().cloned() {
781            if token == Token::RBrace {
782                break;
783            }
784
785            let mut attrs = Vec::new();
786            while matches!(self.peek(), Some(Token::At)) {
787                attrs.push(self.parse_attribute()?);
788            }
789
790            if let Some(Token::Fn) = self.peek() {
791                methods.push(self.parse_function(attrs)?);
792            } else {
793                let span = self.tokens.get(self.pos).map(|t| t.span).unwrap_or(Span {
794                    start: self.eof_pos,
795                    end: self.eof_pos,
796                });
797                return Err(ParserError::Unexpected(token, span));
798            }
799        }
800        self.expect(Token::RBrace)?;
801        Ok(TraitDef { name, methods })
802    }
803
804    fn parse_pipeline(&mut self, mut attrs: Vec<Attribute>) -> Result<PipelineDecl, ParserError> {
805        self.expect(Token::Pipeline)?;
806        let (name, _name_span) = match self.next() {
807            Some(TokenSpan {
808                token: Token::Ident(name),
809                span,
810            }) => (name, span),
811            Some(TokenSpan { token, span }) => return Err(ParserError::Unexpected(token, span)),
812            None => return Err(ParserError::Eof(self.eof_pos)),
813        };
814
815        while matches!(self.peek(), Some(Token::At)) {
816            attrs.push(self.parse_attribute()?);
817        }
818
819        let mut seed = None;
820        for attr in &attrs {
821            if attr.name == "deterministic" {
822                for (i, arg) in attr.args.iter().enumerate() {
823                    if arg == "seed" {
824                        if let Some(eq) = attr.args.get(i + 1) {
825                            if eq == "=" {
826                                if let Some(val) = attr.args.get(i + 2) {
827                                    if let Ok(n) = val.parse::<u64>() {
828                                        seed = Some(n);
829                                    } else if let Ok(f) = val.parse::<f64>() {
830                                        seed = Some(f as u64);
831                                    }
832                                }
833                            }
834                        }
835                    }
836                }
837            }
838        }
839
840        let start_span = self.expect_span(Token::LBrace)?;
841
842        let mut input_ty = Type::Unit;
843        let mut output_ty = None;
844        let mut constraints = Vec::new();
845        let mut steps = Vec::new();
846        let mut validation = None;
847
848        while !matches!(self.peek(), Some(Token::RBrace)) {
849            let field_name = match self.peek() {
850                Some(Token::Ident(n)) => n.clone(),
851                Some(token) => {
852                    let span = self.tokens.get(self.pos).map(|t| t.span).unwrap_or(Span {
853                        start: self.eof_pos,
854                        end: self.eof_pos,
855                    });
856                    return Err(ParserError::Unexpected(token.clone(), span));
857                }
858                None => return Err(ParserError::Eof(self.eof_pos)),
859            };
860            self.next(); // consume field name
861            self.expect(Token::Colon)?;
862
863            match field_name.as_str() {
864                "input" => {
865                    input_ty = self.parse_type()?;
866                }
867                "output" => {
868                    output_ty = Some(self.parse_type()?);
869                }
870                "constraints" => {
871                    self.expect(Token::LBracket)?;
872                    while !matches!(self.peek(), Some(Token::RBracket)) {
873                        let start = if let Some(ts) = self.peek() {
874                            match ts {
875                                Token::LBrace => self.expect_span(Token::LBrace)?,
876                                _ => {
877                                    let span =
878                                        self.tokens.get(self.pos).map(|t| t.span).unwrap_or(Span {
879                                            start: self.eof_pos,
880                                            end: self.eof_pos,
881                                        });
882                                    return Err(ParserError::Unexpected(ts.clone(), span));
883                                }
884                            }
885                        } else {
886                            return Err(ParserError::Eof(self.eof_pos));
887                        };
888
889                        // metric: "..."
890                        match self.next() {
891                            Some(TokenSpan {
892                                token: Token::Ident(name),
893                                ..
894                            }) if name == "metric" => {}
895                            Some(TokenSpan { token, span }) => {
896                                return Err(ParserError::Unexpected(token, span))
897                            }
898                            None => return Err(ParserError::Eof(self.eof_pos)),
899                        }
900                        self.expect(Token::Colon)?;
901                        let metric = match self.next() {
902                            Some(TokenSpan {
903                                token: Token::Str(value),
904                                ..
905                            }) => value,
906                            Some(TokenSpan { token, span }) => {
907                                return Err(ParserError::Unexpected(token, span))
908                            }
909                            None => return Err(ParserError::Eof(self.eof_pos)),
910                        };
911
912                        if matches!(self.peek(), Some(Token::Comma)) {
913                            self.next();
914                        }
915
916                        // comparator: threshold
917                        let (comparator, threshold) = match self.next() {
918                            Some(TokenSpan {
919                                token: Token::Ident(key),
920                                span,
921                            }) => {
922                                self.expect(Token::Colon)?;
923                                let value = match self.next() {
924                                    Some(TokenSpan {
925                                        token: Token::Float(v),
926                                        ..
927                                    }) => v.parse::<f64>().unwrap_or(0.0),
928                                    Some(TokenSpan {
929                                        token: Token::Int(v),
930                                        ..
931                                    }) => v.parse::<f64>().unwrap_or(0.0),
932                                    Some(TokenSpan { token, span }) => {
933                                        return Err(ParserError::Unexpected(token, span))
934                                    }
935                                    None => return Err(ParserError::Eof(self.eof_pos)),
936                                };
937                                let cmp = match key.as_str() {
938                                    "lt" => Comparator::Lt,
939                                    "le" => Comparator::Le,
940                                    "eq" => Comparator::Eq,
941                                    "ge" => Comparator::Ge,
942                                    "gt" => Comparator::Gt,
943                                    _ => {
944                                        return Err(ParserError::Unexpected(
945                                            Token::Ident(key),
946                                            span,
947                                        ))
948                                    }
949                                };
950                                (cmp, value)
951                            }
952                            Some(TokenSpan { token, span }) => {
953                                return Err(ParserError::Unexpected(token, span))
954                            }
955                            None => return Err(ParserError::Eof(self.eof_pos)),
956                        };
957
958                        self.expect(Token::RBrace)?;
959                        constraints.push(Constraint {
960                            metric,
961                            comparator,
962                            threshold,
963                            span: start, // simplified span
964                        });
965
966                        if matches!(self.peek(), Some(Token::Comma)) {
967                            self.next();
968                        }
969                    }
970                    self.expect(Token::RBracket)?;
971                }
972                "steps" => {
973                    self.expect(Token::LBracket)?;
974                    while !matches!(self.peek(), Some(Token::RBracket)) {
975                        match self.next() {
976                            Some(TokenSpan {
977                                token: Token::Ident(s),
978                                ..
979                            }) if s == "step" => {} // allow "step" ident
980                            Some(TokenSpan {
981                                token: Token::Step, ..
982                            }) => {} // allow Step token if exists
983                            Some(TokenSpan { token, span }) => {
984                                return Err(ParserError::Unexpected(token, span))
985                            }
986                            None => return Err(ParserError::Eof(self.eof_pos)),
987                        }
988                        self.expect(Token::LParen)?;
989                        let (step_name, name_span) = match self.next() {
990                            Some(TokenSpan {
991                                token: Token::Str(value),
992                                span,
993                            }) => (value, span),
994                            Some(TokenSpan { token, span }) => {
995                                return Err(ParserError::Unexpected(token, span))
996                            }
997                            None => return Err(ParserError::Eof(self.eof_pos)),
998                        };
999                        self.expect(Token::RParen)?;
1000                        let _ = self.expect_span(Token::LBrace)?;
1001                        let body = self.parse_expr()?;
1002                        let _ = self.expect_span(Token::RBrace)?;
1003
1004                        let body_span = body.span;
1005                        steps.push(PipelineStep {
1006                            name: step_name,
1007                            body,
1008                            span: merge_span(name_span, body_span),
1009                        });
1010
1011                        if matches!(self.peek(), Some(Token::Comma)) {
1012                            self.next();
1013                        }
1014                    }
1015                    self.expect(Token::RBracket)?;
1016                }
1017                "validation" => {
1018                    validation = Some(self.parse_block()?);
1019                }
1020                _ => {
1021                    let span = self.tokens.get(self.pos).map(|t| t.span).unwrap_or(Span {
1022                        start: self.eof_pos,
1023                        end: self.eof_pos,
1024                    });
1025                    return Err(ParserError::Unexpected(Token::Ident(field_name), span));
1026                }
1027            }
1028
1029            if matches!(self.peek(), Some(Token::Comma)) {
1030                self.next();
1031            }
1032        }
1033
1034        let end_span = self.expect_span(Token::RBrace)?;
1035
1036        Ok(PipelineDecl {
1037            name,
1038            attrs,
1039            seed,
1040            input_ty,
1041            output_ty,
1042            constraints,
1043            steps,
1044            validation,
1045            span: merge_span(start_span, end_span),
1046        })
1047    }
1048
1049    fn parse_block(&mut self) -> Result<Block, ParserError> {
1050        let (body, _) = self.parse_block_with_span()?;
1051        Ok(body)
1052    }
1053
1054    fn parse_block_with_span(&mut self) -> Result<(Block, Span), ParserError> {
1055        let start = self.expect_span(Token::LBrace)?;
1056        let mut body = Vec::new();
1057        while let Some(tok) = self.peek() {
1058            if *tok == Token::RBrace {
1059                break;
1060            }
1061            body.push(self.parse_stmt_in_block()?);
1062        }
1063        let end = self.expect_span(Token::RBrace)?;
1064        Ok((body, merge_span(start, end)))
1065    }
1066
1067    fn parse_stmt_in_block(&mut self) -> Result<Stmt, ParserError> {
1068        match self.peek() {
1069            Some(Token::Let) => {
1070                self.next();
1071                let name = match self.next() {
1072                    Some(TokenSpan {
1073                        token: Token::Ident(name),
1074                        ..
1075                    }) => name,
1076                    Some(TokenSpan { token, span }) => {
1077                        return Err(ParserError::Unexpected(token, span))
1078                    }
1079                    None => return Err(ParserError::Eof(self.eof_pos)),
1080                };
1081                let ty = if matches!(self.peek(), Some(Token::Colon)) {
1082                    self.next();
1083                    Some(self.parse_type()?)
1084                } else {
1085                    None
1086                };
1087                self.expect(Token::Equal)?;
1088                let expr = self.parse_expr()?;
1089                self.expect(Token::Semicolon)?;
1090                Ok(Stmt::Let { name, ty, expr })
1091            }
1092            Some(Token::Return) => {
1093                self.next();
1094                let expr = if matches!(self.peek(), Some(Token::Semicolon)) {
1095                    None
1096                } else {
1097                    Some(self.parse_expr()?)
1098                };
1099                self.expect(Token::Semicolon)?;
1100                Ok(Stmt::Return(expr))
1101            }
1102            Some(Token::While) => {
1103                self.next();
1104                let condition = self.parse_expr()?;
1105                let body = self.parse_block()?;
1106                Ok(Stmt::While { condition, body })
1107            }
1108            Some(Token::For) => {
1109                self.next();
1110                let name = match self.next() {
1111                    Some(TokenSpan {
1112                        token: Token::Ident(name),
1113                        ..
1114                    }) => name,
1115                    Some(TokenSpan { token, span }) => {
1116                        return Err(ParserError::Unexpected(token, span))
1117                    }
1118                    None => return Err(ParserError::Eof(self.eof_pos)),
1119                };
1120                self.expect(Token::In)?;
1121                let iter = self.parse_expr()?;
1122                let body = self.parse_block()?;
1123                Ok(Stmt::For { name, iter, body })
1124            }
1125            Some(Token::Break) => {
1126                self.next();
1127                self.expect(Token::Semicolon)?;
1128                Ok(Stmt::Break)
1129            }
1130            Some(Token::Continue) => {
1131                self.next();
1132                self.expect(Token::Semicolon)?;
1133                Ok(Stmt::Continue)
1134            }
1135            Some(Token::LBrace) => {
1136                let (block, span) = self.parse_block_with_span()?;
1137                Ok(Stmt::Expr(Expr::new(ExprKind::Block(block), span)))
1138            }
1139            Some(Token::If) | Some(Token::Match) => {
1140                let expr = self.parse_expr()?;
1141                if matches!(self.peek(), Some(Token::Semicolon)) {
1142                    self.next();
1143                }
1144                Ok(Stmt::Expr(expr))
1145            }
1146            _ => {
1147                let expr = self.parse_expr()?;
1148                if matches!(self.peek(), Some(Token::Semicolon)) {
1149                    self.next();
1150                    return Ok(Stmt::Expr(expr));
1151                }
1152                if matches!(self.peek(), Some(Token::RBrace)) {
1153                    return Ok(Stmt::Expr(expr));
1154                }
1155                Err(ParserError::MissingSemicolon(expr.span))
1156            }
1157        }
1158    }
1159
1160    fn parse_params(&mut self) -> Result<Vec<Param>, ParserError> {
1161        let mut params = Vec::new();
1162        if matches!(self.peek(), Some(Token::RParen)) {
1163            return Ok(params);
1164        }
1165        loop {
1166            let name = match self.next() {
1167                Some(TokenSpan {
1168                    token: Token::Ident(name),
1169                    ..
1170                }) => name,
1171                Some(TokenSpan { token, span }) => {
1172                    return Err(ParserError::Unexpected(token, span))
1173                }
1174                None => return Err(ParserError::Eof(self.eof_pos)),
1175            };
1176            self.expect(Token::Colon)?;
1177            let ty = self.parse_type()?;
1178            params.push(Param { name, ty });
1179
1180            if matches!(self.peek(), Some(Token::Comma)) {
1181                self.next();
1182                if matches!(self.peek(), Some(Token::RParen)) {
1183                    break;
1184                }
1185            } else {
1186                break;
1187            }
1188        }
1189        Ok(params)
1190    }
1191
1192    fn parse_type(&mut self) -> Result<Type, ParserError> {
1193        match self.next() {
1194            Some(TokenSpan {
1195                token: Token::Ident(name),
1196                ..
1197            }) => {
1198                if name == "Safe" {
1199                    self.expect(Token::Less)?;
1200                    let base = self.parse_type()?;
1201                    self.expect(Token::Comma)?;
1202                    let mut constraints = Vec::new();
1203                    self.expect(Token::Bang)?;
1204                    let first = match self.next() {
1205                        Some(TokenSpan {
1206                            token: Token::Ident(constraint),
1207                            ..
1208                        }) => constraint,
1209                        Some(TokenSpan { token, span }) => {
1210                            return Err(ParserError::Unexpected(token, span))
1211                        }
1212                        None => return Err(ParserError::Eof(self.eof_pos)),
1213                    };
1214                    constraints.push(first);
1215                    while matches!(self.peek(), Some(Token::Comma)) {
1216                        self.next();
1217                        self.expect(Token::Bang)?;
1218                        let constraint = match self.next() {
1219                            Some(TokenSpan {
1220                                token: Token::Ident(constraint),
1221                                ..
1222                            }) => constraint,
1223                            Some(TokenSpan { token, span }) => {
1224                                return Err(ParserError::Unexpected(token, span))
1225                            }
1226                            None => return Err(ParserError::Eof(self.eof_pos)),
1227                        };
1228                        constraints.push(constraint);
1229                    }
1230                    self.expect(Token::Greater)?;
1231                    Ok(Type::Safe {
1232                        base: Box::new(base),
1233                        constraints,
1234                    })
1235                } else if matches!(self.peek(), Some(Token::Less)) {
1236                    self.next();
1237                    let mut args = Vec::new();
1238                    args.push(self.parse_type()?);
1239                    while matches!(self.peek(), Some(Token::Comma)) {
1240                        self.next();
1241                        if matches!(self.peek(), Some(Token::Greater)) {
1242                            break;
1243                        }
1244                        args.push(self.parse_type()?);
1245                    }
1246                    self.expect(Token::Greater)?;
1247                    Ok(Type::Generic { name, args })
1248                } else {
1249                    Ok(Type::Ident(name))
1250                }
1251            }
1252            Some(TokenSpan {
1253                token: Token::Fn, ..
1254            }) => {
1255                self.expect(Token::LParen)?;
1256                let mut params = Vec::new();
1257                if !matches!(self.peek(), Some(Token::RParen)) {
1258                    params.push(self.parse_type()?);
1259                    while matches!(self.peek(), Some(Token::Comma)) {
1260                        self.next();
1261                        if matches!(self.peek(), Some(Token::RParen)) {
1262                            break;
1263                        }
1264                        params.push(self.parse_type()?);
1265                    }
1266                }
1267                self.expect(Token::RParen)?;
1268                self.expect(Token::ThinArrow)?;
1269                let ret = self.parse_type()?;
1270                Ok(Type::Func {
1271                    params,
1272                    ret: Box::new(ret),
1273                })
1274            }
1275            Some(TokenSpan {
1276                token: Token::LBracket,
1277                ..
1278            }) => {
1279                let elem = self.parse_type()?;
1280                if matches!(self.peek(), Some(Token::Semicolon)) {
1281                    self.next();
1282                    let len = match self.next() {
1283                        Some(TokenSpan {
1284                            token: Token::Int(value),
1285                            span,
1286                        }) => value
1287                            .parse::<i64>()
1288                            .map_err(|_| ParserError::Unexpected(Token::Int(value), span))?,
1289                        Some(TokenSpan { token, span }) => {
1290                            return Err(ParserError::Unexpected(token, span))
1291                        }
1292                        None => return Err(ParserError::Eof(self.eof_pos)),
1293                    };
1294                    self.expect(Token::RBracket)?;
1295                    Ok(Type::Array {
1296                        elem: Box::new(elem),
1297                        len,
1298                    })
1299                } else {
1300                    self.expect(Token::RBracket)?;
1301                    Ok(Type::Slice {
1302                        elem: Box::new(elem),
1303                    })
1304                }
1305            }
1306            Some(TokenSpan {
1307                token: Token::LParen,
1308                ..
1309            }) => {
1310                if matches!(self.peek(), Some(Token::RParen)) {
1311                    let end = self.expect_span(Token::RParen)?;
1312                    return Err(ParserError::Unexpected(Token::RParen, end));
1313                }
1314                let first = self.parse_type()?;
1315                if matches!(self.peek(), Some(Token::Comma)) {
1316                    self.next();
1317                    let mut items = vec![first];
1318                    while !matches!(self.peek(), Some(Token::RParen)) {
1319                        items.push(self.parse_type()?);
1320                        if !matches!(self.peek(), Some(Token::Comma)) {
1321                            break;
1322                        }
1323                        self.next();
1324                        if matches!(self.peek(), Some(Token::RParen)) {
1325                            break;
1326                        }
1327                    }
1328                    self.expect(Token::RParen)?;
1329                    Ok(Type::Tuple(items))
1330                } else {
1331                    self.expect(Token::RParen)?;
1332                    Ok(first)
1333                }
1334            }
1335            Some(TokenSpan { token, span }) => Err(ParserError::Unexpected(token, span)),
1336            None => Err(ParserError::Eof(self.eof_pos)),
1337        }
1338    }
1339
1340    fn parse_expr(&mut self) -> Result<Expr, ParserError> {
1341        if self.is_index_assignment() {
1342            let ident = self.next().ok_or(ParserError::Eof(self.eof_pos))?;
1343            let (name, ident_span) = match ident {
1344                TokenSpan {
1345                    token: Token::Ident(name),
1346                    span,
1347                } => (name, span),
1348                TokenSpan { token, span } => return Err(ParserError::Unexpected(token, span)),
1349            };
1350            self.expect(Token::LBracket)?;
1351            let index = self.parse_expr()?;
1352            self.expect(Token::RBracket)?;
1353            self.expect(Token::Equal)?;
1354            let value = self.parse_expr()?;
1355            let base = Expr::new(ExprKind::Ident(name), ident_span);
1356            let span = merge_span(ident_span, value.span);
1357            return Ok(Expr::new(
1358                ExprKind::AssignIndex {
1359                    expr: Box::new(base),
1360                    index: Box::new(index),
1361                    value: Box::new(value),
1362                },
1363                span,
1364            ));
1365        }
1366        if matches!(self.peek(), Some(Token::Ident(_)))
1367            && matches!(
1368                self.peek_next(),
1369                Some(
1370                    Token::Equal
1371                        | Token::PlusEqual
1372                        | Token::MinusEqual
1373                        | Token::StarEqual
1374                        | Token::SlashEqual
1375                )
1376            )
1377        {
1378            let ident = self.next().ok_or(ParserError::Eof(self.eof_pos))?;
1379            let name = match ident {
1380                TokenSpan {
1381                    token: Token::Ident(name),
1382                    span,
1383                } => (name, span),
1384                TokenSpan { token, span } => return Err(ParserError::Unexpected(token, span)),
1385            };
1386            let op = self.next().ok_or(ParserError::Eof(self.eof_pos))?;
1387            match op {
1388                TokenSpan {
1389                    token: Token::Equal,
1390                    ..
1391                } => {
1392                    let expr = self.parse_expr()?;
1393                    let span = merge_span(name.1, expr.span);
1394                    return Ok(Expr::new(
1395                        ExprKind::Assign {
1396                            name: name.0,
1397                            expr: Box::new(expr),
1398                        },
1399                        span,
1400                    ));
1401                }
1402                TokenSpan {
1403                    token: Token::PlusEqual,
1404                    ..
1405                } => {
1406                    let rhs = self.parse_expr()?;
1407                    let lhs = Expr::new(ExprKind::Ident(name.0.clone()), name.1);
1408                    let bin_span = merge_span(lhs.span, rhs.span);
1409                    let bin = Expr::new(
1410                        ExprKind::Binary {
1411                            op: BinaryOp::Add,
1412                            left: Box::new(lhs),
1413                            right: Box::new(rhs),
1414                        },
1415                        bin_span,
1416                    );
1417                    let span = merge_span(name.1, bin.span);
1418                    return Ok(Expr::new(
1419                        ExprKind::Assign {
1420                            name: name.0,
1421                            expr: Box::new(bin),
1422                        },
1423                        span,
1424                    ));
1425                }
1426                TokenSpan {
1427                    token: Token::MinusEqual,
1428                    ..
1429                } => {
1430                    let rhs = self.parse_expr()?;
1431                    let lhs = Expr::new(ExprKind::Ident(name.0.clone()), name.1);
1432                    let bin_span = merge_span(lhs.span, rhs.span);
1433                    let bin = Expr::new(
1434                        ExprKind::Binary {
1435                            op: BinaryOp::Sub,
1436                            left: Box::new(lhs),
1437                            right: Box::new(rhs),
1438                        },
1439                        bin_span,
1440                    );
1441                    let span = merge_span(name.1, bin.span);
1442                    return Ok(Expr::new(
1443                        ExprKind::Assign {
1444                            name: name.0,
1445                            expr: Box::new(bin),
1446                        },
1447                        span,
1448                    ));
1449                }
1450                TokenSpan {
1451                    token: Token::StarEqual,
1452                    ..
1453                } => {
1454                    let rhs = self.parse_expr()?;
1455                    let lhs = Expr::new(ExprKind::Ident(name.0.clone()), name.1);
1456                    let bin_span = merge_span(lhs.span, rhs.span);
1457                    let bin = Expr::new(
1458                        ExprKind::Binary {
1459                            op: BinaryOp::Mul,
1460                            left: Box::new(lhs),
1461                            right: Box::new(rhs),
1462                        },
1463                        bin_span,
1464                    );
1465                    let span = merge_span(name.1, bin.span);
1466                    return Ok(Expr::new(
1467                        ExprKind::Assign {
1468                            name: name.0,
1469                            expr: Box::new(bin),
1470                        },
1471                        span,
1472                    ));
1473                }
1474                TokenSpan {
1475                    token: Token::SlashEqual,
1476                    ..
1477                } => {
1478                    let rhs = self.parse_expr()?;
1479                    let lhs = Expr::new(ExprKind::Ident(name.0.clone()), name.1);
1480                    let bin_span = merge_span(lhs.span, rhs.span);
1481                    let bin = Expr::new(
1482                        ExprKind::Binary {
1483                            op: BinaryOp::Div,
1484                            left: Box::new(lhs),
1485                            right: Box::new(rhs),
1486                        },
1487                        bin_span,
1488                    );
1489                    let span = merge_span(name.1, bin.span);
1490                    return Ok(Expr::new(
1491                        ExprKind::Assign {
1492                            name: name.0,
1493                            expr: Box::new(bin),
1494                        },
1495                        span,
1496                    ));
1497                }
1498                TokenSpan { token, span } => return Err(ParserError::Unexpected(token, span)),
1499            }
1500        }
1501        self.parse_precedence(0)
1502    }
1503
1504    fn parse_precedence(&mut self, min_prec: u8) -> Result<Expr, ParserError> {
1505        let mut left = self.parse_unary()?;
1506
1507        while let Some((op, prec, right_assoc)) = self.peek().and_then(Self::token_to_binary_op) {
1508            if prec < min_prec {
1509                break;
1510            }
1511
1512            self.next();
1513            let next_min_prec = if right_assoc { prec } else { prec + 1 };
1514            let right = self.parse_precedence(next_min_prec)?;
1515            let span = merge_span(left.span, right.span);
1516            left = Expr::new(
1517                ExprKind::Binary {
1518                    op,
1519                    left: Box::new(left),
1520                    right: Box::new(right),
1521                },
1522                span,
1523            );
1524        }
1525
1526        Ok(left)
1527    }
1528
1529    fn parse_unary(&mut self) -> Result<Expr, ParserError> {
1530        if matches!(self.peek(), Some(Token::Pipe)) {
1531            // Lambda: |x, y| expr
1532            let start = self.next().unwrap().span;
1533            let mut params = Vec::new();
1534            loop {
1535                match self.next() {
1536                    Some(TokenSpan {
1537                        token: Token::Ident(name),
1538                        ..
1539                    }) => params.push(name),
1540                    Some(TokenSpan {
1541                        token: Token::Pipe, ..
1542                    }) => break,
1543                    Some(TokenSpan { token, span }) => {
1544                        return Err(ParserError::Unexpected(token, span))
1545                    }
1546                    None => return Err(ParserError::Eof(self.eof_pos)),
1547                }
1548                if matches!(self.peek(), Some(Token::Comma)) {
1549                    self.next();
1550                }
1551            }
1552            let body = self.parse_expr()?;
1553            let span = merge_span(start, body.span);
1554            Ok(Expr::new(
1555                ExprKind::Lambda {
1556                    params,
1557                    body: Box::new(body),
1558                },
1559                span,
1560            ))
1561        } else {
1562            match self.peek() {
1563                Some(Token::Bang) => {
1564                    let span = self.next().unwrap().span;
1565                    let expr = self.parse_unary()?;
1566                    let full = merge_span(span, expr.span);
1567                    Ok(Expr::new(
1568                        ExprKind::Unary {
1569                            op: UnaryOp::Not,
1570                            expr: Box::new(expr),
1571                        },
1572                        full,
1573                    ))
1574                }
1575                Some(Token::Minus) => {
1576                    let span = self.next().unwrap().span;
1577                    let expr = self.parse_unary()?;
1578                    let full = merge_span(span, expr.span);
1579                    Ok(Expr::new(
1580                        ExprKind::Unary {
1581                            op: UnaryOp::Neg,
1582                            expr: Box::new(expr),
1583                        },
1584                        full,
1585                    ))
1586                }
1587                _ => self.parse_primary(),
1588            }
1589        }
1590    }
1591
1592    fn parse_primary(&mut self) -> Result<Expr, ParserError> {
1593        if matches!(self.peek(), Some(Token::LBrace)) {
1594            let (block, span) = self.parse_block_with_span()?;
1595            return Ok(Expr::new(ExprKind::Block(block), span));
1596        }
1597
1598        let mut expr = match self.next() {
1599            Some(TokenSpan {
1600                token: Token::Int(value),
1601                span,
1602            }) => value
1603                .parse::<i64>()
1604                .map(|v| Expr::new(ExprKind::Int(v), span))
1605                .map_err(|_| ParserError::Unexpected(Token::Int(value), span)),
1606            Some(TokenSpan {
1607                token: Token::Float(value),
1608                span,
1609            }) => value
1610                .parse::<f64>()
1611                .map(|v| Expr::new(ExprKind::Float(v), span))
1612                .map_err(|_| ParserError::Unexpected(Token::Float(value), span)),
1613            Some(TokenSpan {
1614                token: Token::Str(value),
1615                span,
1616            }) => Ok(Expr::new(ExprKind::Str(value), span)),
1617            Some(TokenSpan {
1618                token: Token::True,
1619                span,
1620            }) => Ok(Expr::new(ExprKind::Bool(true), span)),
1621            Some(TokenSpan {
1622                token: Token::False,
1623                span,
1624            }) => Ok(Expr::new(ExprKind::Bool(false), span)),
1625            Some(TokenSpan {
1626                token: Token::Null,
1627                span,
1628            }) => Ok(Expr::new(ExprKind::Null, span)),
1629            Some(TokenSpan {
1630                token: Token::Ident(name),
1631                span,
1632            }) => Ok(Expr::new(ExprKind::Ident(name), span)),
1633            Some(TokenSpan {
1634                token: Token::LParen,
1635                span,
1636            }) => {
1637                let first = self.parse_expr()?;
1638                if matches!(self.peek(), Some(Token::Comma)) {
1639                    self.next();
1640                    let mut items = vec![first];
1641                    while !matches!(self.peek(), Some(Token::RParen)) {
1642                        items.push(self.parse_expr()?);
1643                        if !matches!(self.peek(), Some(Token::Comma)) {
1644                            break;
1645                        }
1646                        self.next();
1647                        if matches!(self.peek(), Some(Token::RParen)) {
1648                            break;
1649                        }
1650                    }
1651                    let end = self.expect_span(Token::RParen)?;
1652                    Ok(Expr::new(ExprKind::Tuple(items), merge_span(span, end)))
1653                } else {
1654                    let end = self.expect_span(Token::RParen)?;
1655                    Ok(Expr::new(first.kind, merge_span(span, end)))
1656                }
1657            }
1658            Some(TokenSpan {
1659                token: Token::LBracket,
1660                span,
1661            }) => {
1662                let mut items = Vec::new();
1663                if !matches!(self.peek(), Some(Token::RBracket)) {
1664                    items.push(self.parse_expr()?);
1665                    while matches!(self.peek(), Some(Token::Comma)) {
1666                        self.next();
1667                        if matches!(self.peek(), Some(Token::RBracket)) {
1668                            break;
1669                        }
1670                        items.push(self.parse_expr()?);
1671                    }
1672                }
1673                let end = self.expect_span(Token::RBracket)?;
1674                Ok(Expr::new(
1675                    ExprKind::ArrayLiteral(items),
1676                    merge_span(span, end),
1677                ))
1678            }
1679            Some(TokenSpan {
1680                token: Token::Await,
1681                span,
1682            }) => {
1683                let expr = self.parse_expr()?;
1684                Ok(Expr::new(
1685                    ExprKind::Await(Box::new(expr.clone())),
1686                    merge_span(span, expr.span),
1687                ))
1688            }
1689            Some(TokenSpan {
1690                token: Token::If,
1691                span,
1692            }) => {
1693                let condition = self.parse_expr()?;
1694                let (then_branch, then_span) = self.parse_block_with_span()?;
1695                let (else_branch, end_span) = if matches!(self.peek(), Some(Token::Else)) {
1696                    self.next();
1697                    if matches!(self.peek(), Some(Token::If)) {
1698                        let else_if = self.parse_expr()?;
1699                        let end = else_if.span;
1700                        (Some(ElseBranch::If(Box::new(else_if))), end)
1701                    } else {
1702                        let (block, block_span) = self.parse_block_with_span()?;
1703                        (Some(ElseBranch::Block(block)), block_span)
1704                    }
1705                } else {
1706                    (None, then_span)
1707                };
1708                Ok(Expr::new(
1709                    ExprKind::If {
1710                        condition: Box::new(condition),
1711                        then_branch,
1712                        else_branch,
1713                    },
1714                    merge_span(span, end_span),
1715                ))
1716            }
1717            Some(TokenSpan {
1718                token: Token::Match,
1719                span,
1720            }) => {
1721                let expr = self.parse_expr()?;
1722                self.expect(Token::LBrace)?;
1723                let mut arms = Vec::new();
1724                while let Some(tok) = self.peek() {
1725                    if *tok == Token::RBrace {
1726                        break;
1727                    }
1728                    let (pattern, pattern_span) = self.parse_pattern()?;
1729                    let guard = if matches!(self.peek(), Some(Token::If)) {
1730                        self.next();
1731                        Some(self.parse_expr()?)
1732                    } else {
1733                        None
1734                    };
1735                    self.expect(Token::Arrow)?;
1736                    let arm_expr = self.parse_expr()?;
1737                    if matches!(self.peek(), Some(Token::Comma)) {
1738                        self.next();
1739                    }
1740                    arms.push(MatchArm {
1741                        pattern,
1742                        pattern_span,
1743                        guard,
1744                        expr: arm_expr,
1745                    });
1746                }
1747                let end = self.expect_span(Token::RBrace)?;
1748                Ok(Expr::new(
1749                    ExprKind::Match {
1750                        expr: Box::new(expr),
1751                        arms,
1752                    },
1753                    merge_span(span, end),
1754                ))
1755            }
1756            Some(TokenSpan { token, span }) => Err(ParserError::Unexpected(token, span)),
1757            None => Err(ParserError::Eof(self.eof_pos)),
1758        }?;
1759
1760        loop {
1761            match self.peek() {
1762                Some(Token::LParen) => {
1763                    self.next();
1764                    let mut args = Vec::new();
1765                    if !matches!(self.peek(), Some(Token::RParen)) {
1766                        args.push(self.parse_expr()?);
1767                        while matches!(self.peek(), Some(Token::Comma)) {
1768                            self.next();
1769                            args.push(self.parse_expr()?);
1770                        }
1771                    }
1772                    let end = self.expect_span(Token::RParen)?;
1773                    let span = merge_span(expr.span, end);
1774                    expr = Expr::new(
1775                        ExprKind::Call {
1776                            callee: Box::new(expr),
1777                            args,
1778                        },
1779                        span,
1780                    );
1781                }
1782                Some(Token::Dot) => {
1783                    self.next();
1784                    let field = match self.next() {
1785                        Some(TokenSpan {
1786                            token: Token::Ident(name),
1787                            span,
1788                        }) => (FieldAccess::Ident(name), span),
1789                        Some(TokenSpan {
1790                            token: Token::Int(value),
1791                            span,
1792                        }) => value
1793                            .parse::<i64>()
1794                            .map(FieldAccess::Index)
1795                            .map_err(|_| ParserError::Unexpected(Token::Int(value), span))
1796                            .map(|f| (f, span))?,
1797                        Some(TokenSpan { token, span }) => {
1798                            return Err(ParserError::Unexpected(token, span))
1799                        }
1800                        None => return Err(ParserError::Eof(self.eof_pos)),
1801                    };
1802                    let span = merge_span(expr.span, field.1);
1803                    expr = Expr::new(
1804                        ExprKind::Field {
1805                            expr: Box::new(expr),
1806                            field: field.0,
1807                        },
1808                        span,
1809                    );
1810                }
1811                Some(Token::LBracket) => {
1812                    self.next();
1813                    let index = self.parse_expr()?;
1814                    let end = self.expect_span(Token::RBracket)?;
1815                    let span = merge_span(expr.span, end);
1816                    expr = Expr::new(
1817                        ExprKind::Index {
1818                            expr: Box::new(expr),
1819                            index: Box::new(index),
1820                        },
1821                        span,
1822                    );
1823                }
1824                _ => break,
1825            }
1826        }
1827
1828        Ok(expr)
1829    }
1830
1831    fn token_to_binary_op(token: &Token) -> Option<(BinaryOp, u8, bool)> {
1832        match token {
1833            Token::DotDot => Some((BinaryOp::Range, 0, false)),
1834            Token::OrOr => Some((BinaryOp::Or, 1, false)),
1835            Token::AndAnd => Some((BinaryOp::And, 2, false)),
1836            Token::EqualEqual => Some((BinaryOp::Equal, 3, false)),
1837            Token::BangEqual => Some((BinaryOp::NotEqual, 3, false)),
1838            Token::Less => Some((BinaryOp::Less, 4, false)),
1839            Token::LessEqual => Some((BinaryOp::LessEqual, 4, false)),
1840            Token::Greater => Some((BinaryOp::Greater, 4, false)),
1841            Token::GreaterEqual => Some((BinaryOp::GreaterEqual, 4, false)),
1842            Token::Plus => Some((BinaryOp::Add, 5, false)),
1843            Token::Minus => Some((BinaryOp::Sub, 5, false)),
1844            Token::Star => Some((BinaryOp::Mul, 6, false)),
1845            Token::Slash => Some((BinaryOp::Div, 6, false)),
1846            Token::DoubleStar => Some((BinaryOp::Pow, 7, true)),
1847            _ => None,
1848        }
1849    }
1850
1851    fn parse_pattern(&mut self) -> Result<(Pattern, Span), ParserError> {
1852        match self.next() {
1853            Some(TokenSpan {
1854                token: Token::LParen,
1855                span,
1856            }) => {
1857                if matches!(self.peek(), Some(Token::RParen)) {
1858                    let end = self.expect_span(Token::RParen)?;
1859                    return Err(ParserError::Unexpected(Token::RParen, end));
1860                }
1861                let (first, _) = self.parse_pattern()?;
1862                if matches!(self.peek(), Some(Token::Comma)) {
1863                    self.next();
1864                    let mut items = vec![first];
1865                    while !matches!(self.peek(), Some(Token::RParen)) {
1866                        let (item, _) = self.parse_pattern()?;
1867                        items.push(item);
1868                        if !matches!(self.peek(), Some(Token::Comma)) {
1869                            break;
1870                        }
1871                        self.next();
1872                        if matches!(self.peek(), Some(Token::RParen)) {
1873                            break;
1874                        }
1875                    }
1876                    let end = self.expect_span(Token::RParen)?;
1877                    Ok((Pattern::Tuple(items), merge_span(span, end)))
1878                } else {
1879                    let end = self.expect_span(Token::RParen)?;
1880                    Ok((first, merge_span(span, end)))
1881                }
1882            }
1883            Some(TokenSpan {
1884                token: Token::Ident(name),
1885                span,
1886            }) => {
1887                if name == "_" {
1888                    Ok((Pattern::Wildcard, span))
1889                } else if matches!(self.peek(), Some(Token::LParen)) {
1890                    self.next();
1891                    let mut args = Vec::new();
1892                    if !matches!(self.peek(), Some(Token::RParen)) {
1893                        loop {
1894                            let (arg, _) = self.parse_pattern()?;
1895                            args.push(arg);
1896                            if !matches!(self.peek(), Some(Token::Comma)) {
1897                                break;
1898                            }
1899                            self.next();
1900                            if matches!(self.peek(), Some(Token::RParen)) {
1901                                break;
1902                            }
1903                        }
1904                    }
1905                    let end = self.expect_span(Token::RParen)?;
1906                    Ok((Pattern::Constructor { name, args }, merge_span(span, end)))
1907                } else {
1908                    Ok((Pattern::Ident(name), span))
1909                }
1910            }
1911            Some(TokenSpan {
1912                token: Token::Int(value),
1913                span,
1914            }) => value
1915                .parse::<i64>()
1916                .map(|value| (Pattern::Int(value), span))
1917                .map_err(|_| ParserError::Unexpected(Token::Int(value), span)),
1918            Some(TokenSpan {
1919                token: Token::Str(value),
1920                span,
1921            }) => Ok((Pattern::Str(value), span)),
1922            Some(TokenSpan {
1923                token: Token::True,
1924                span,
1925            }) => Ok((Pattern::Bool(true), span)),
1926            Some(TokenSpan {
1927                token: Token::False,
1928                span,
1929            }) => Ok((Pattern::Bool(false), span)),
1930            Some(TokenSpan { token, span }) => Err(ParserError::Unexpected(token, span)),
1931            None => Err(ParserError::Eof(self.eof_pos)),
1932        }
1933    }
1934}
1935
1936#[cfg(test)]
1937mod tests {
1938    use super::*;
1939
1940    #[test]
1941    fn parse_empty_function() {
1942        let program = parse_program("fn main() {}\n").unwrap();
1943        assert_eq!(program.items.len(), 1);
1944    }
1945
1946    #[test]
1947    fn parse_let_and_return() {
1948        let src = "fn main() { let x = 1; return x; }";
1949        let program = parse_program(src).unwrap();
1950        let func = match &program.items[0] {
1951            Item::Trait(_) => panic!("expected function"),
1952            Item::Enum(_) => panic!("expected function"),
1953            Item::Pipeline(_) => panic!("expected function"),
1954            Item::Function(func) => func,
1955        };
1956        assert_eq!(func.body.len(), 2);
1957    }
1958
1959    #[test]
1960    fn parse_if_expression() {
1961        let src = "fn main() { if 1 { return 2; } else { return 3; } }";
1962        let program = parse_program(src).unwrap();
1963        let func = match &program.items[0] {
1964            Item::Trait(_) => panic!("expected function"),
1965            Item::Enum(_) => panic!("expected function"),
1966            Item::Pipeline(_) => panic!("expected function"),
1967            Item::Function(func) => func,
1968        };
1969        assert_eq!(func.body.len(), 1);
1970    }
1971
1972    #[test]
1973    fn parse_pipeline_suffix_attributes() {
1974        let src = r#"
1975        pipeline MyPipeline @suffix(val=1) {
1976            input: i64,
1977            steps: [],
1978        }
1979        "#;
1980        let program = parse_program(src).unwrap();
1981        if let Item::Pipeline(pipe) = &program.items[0] {
1982            assert_eq!(pipe.attrs.len(), 1);
1983            assert_eq!(pipe.attrs[0].name, "suffix");
1984        } else {
1985            panic!("expected pipeline");
1986        }
1987    }
1988
1989    #[test]
1990    fn parse_complex_attributes() {
1991        let src = r#"
1992        @complex(nested=[1, 2], call=ExternalCall("DB"))
1993        fn main() {}
1994        "#;
1995        let program = parse_program(src).unwrap();
1996        if let Item::Function(func) = &program.items[0] {
1997            assert_eq!(func.attrs.len(), 1);
1998            let attr = &func.attrs[0];
1999            assert_eq!(attr.name, "complex");
2000            // args: nested, =, [, 1, ,, 2, ], ,, call, =, ExternalCall, (, DB, )
2001            // My implementation preserves structure by tokens.
2002            // nested -> Ident
2003            // = -> Equal
2004            // [ -> LBracket
2005            // 1 -> Int
2006            // , -> Comma (inside brackets)
2007            // 2 -> Int
2008            // ] -> RBracket
2009            // , -> Comma (top level) -> SKIPPED
2010            // call -> Ident
2011            // = -> Equal
2012            // ExternalCall -> Ident
2013            // ( -> LParen
2014            // DB -> Str
2015            // ) -> RParen
2016
2017            let expected = vec![
2018                "nested",
2019                "=",
2020                "[",
2021                "1",
2022                ",",
2023                "2",
2024                "]",
2025                "call",
2026                "=",
2027                "ExternalCall",
2028                "(",
2029                "DB",
2030                ")",
2031            ];
2032            assert_eq!(attr.args, expected);
2033        } else {
2034            panic!("expected function");
2035        }
2036    }
2037
2038    #[test]
2039    fn parse_external_attribute_spec() {
2040        let src = r#"
2041        @external(python="torch.nn.Linear", effects=[IO, Time, ExternalCall("Bybit")])
2042        fn predict(input: i64): i64 { return input; }
2043        "#;
2044        let program = parse_program(src).unwrap();
2045        let func = match &program.items[0] {
2046            Item::Function(func) => func,
2047            _ => panic!("expected function"),
2048        };
2049
2050        let spec = func.external_spec.as_ref().expect("expected external spec");
2051        assert_eq!(spec.python.as_deref(), Some("torch.nn.Linear"));
2052        assert_eq!(
2053            spec.effects,
2054            vec![
2055                "IO".to_string(),
2056                "Time".to_string(),
2057                "ExternalCall(Bybit)".to_string(),
2058            ]
2059        );
2060    }
2061
2062    #[test]
2063    fn parse_external_attribute_legacy_python_only() {
2064        let src = r#"
2065        @external("math.sqrt")
2066        fn predict(input: i64): i64 { return input; }
2067        "#;
2068        let program = parse_program(src).unwrap();
2069        let func = match &program.items[0] {
2070            Item::Function(func) => func,
2071            _ => panic!("expected function"),
2072        };
2073
2074        let spec = func.external_spec.as_ref().expect("expected external spec");
2075        assert_eq!(spec.python.as_deref(), Some("math.sqrt"));
2076        assert!(spec.effects.is_empty());
2077    }
2078    #[test]
2079    fn parse_match_expression() {
2080        let src = "fn main() { match x { 1 => foo(), _ => bar(), }; }";
2081        let program = parse_program(src).unwrap();
2082        let func = match &program.items[0] {
2083            Item::Trait(_) => panic!("expected function"),
2084            Item::Enum(_) => panic!("expected function"),
2085            Item::Pipeline(_) => panic!("expected function"),
2086            Item::Function(func) => func,
2087        };
2088        assert_eq!(func.body.len(), 1);
2089    }
2090
2091    #[test]
2092    fn parse_tuple_expr_and_pattern() {
2093        let src = "fn main() { let pair = (1, 2); match pair { (1, x) => x, _ => 0 }; }";
2094        let program = parse_program(src).unwrap();
2095        let func = match &program.items[0] {
2096            Item::Trait(_) => panic!("expected function"),
2097            Item::Enum(_) => panic!("expected function"),
2098            Item::Pipeline(_) => panic!("expected function"),
2099            Item::Function(func) => func,
2100        };
2101        assert_eq!(func.body.len(), 2);
2102    }
2103
2104    #[test]
2105    fn parse_binary_precedence() {
2106        let src = "fn main() { let x = 1 + 2 * 3; }";
2107        let program = parse_program(src).unwrap();
2108        let func = match &program.items[0] {
2109            Item::Trait(_) => panic!("expected function"),
2110            Item::Enum(_) => panic!("expected function"),
2111            Item::Pipeline(_) => panic!("expected function"),
2112            Item::Function(func) => func,
2113        };
2114        let Stmt::Let { expr, .. } = &func.body[0] else {
2115            panic!("expected let");
2116        };
2117        match &expr.kind {
2118            ExprKind::Binary { op, left, right } => {
2119                assert_eq!(*op, BinaryOp::Add);
2120                assert!(matches!(left.kind, ExprKind::Int(1)));
2121                assert!(matches!(
2122                    right.kind,
2123                    ExprKind::Binary {
2124                        op: BinaryOp::Mul,
2125                        ..
2126                    }
2127                ));
2128            }
2129            _ => panic!("expected binary expression"),
2130        }
2131    }
2132
2133    #[test]
2134    fn parse_unary_expression() {
2135        let src = "fn main() { let x = -1; let y = !false; }";
2136        let program = parse_program(src).unwrap();
2137        let func = match &program.items[0] {
2138            Item::Trait(_) => panic!("expected function"),
2139            Item::Enum(_) => panic!("expected function"),
2140            Item::Pipeline(_) => panic!("expected function"),
2141            Item::Function(func) => func,
2142        };
2143        let Stmt::Let { expr, .. } = &func.body[0] else {
2144            panic!("expected let");
2145        };
2146        assert!(matches!(
2147            expr.kind,
2148            ExprKind::Unary {
2149                op: UnaryOp::Neg,
2150                ..
2151            }
2152        ));
2153        let Stmt::Let { expr, .. } = &func.body[1] else {
2154            panic!("expected let");
2155        };
2156        assert!(matches!(
2157            expr.kind,
2158            ExprKind::Unary {
2159                op: UnaryOp::Not,
2160                ..
2161            }
2162        ));
2163    }
2164
2165    #[test]
2166    fn parse_enum_generics() {
2167        let src = "enum Result<T, E> { Ok, Err }";
2168        let program = parse_program(src).unwrap();
2169        let Item::Enum(def) = &program.items[0] else {
2170            panic!("expected enum");
2171        };
2172        assert_eq!(def.name, "Result");
2173        assert_eq!(def.generics, vec!["T", "E"]);
2174        assert_eq!(def.variants.len(), 2);
2175        assert_eq!(def.variants[0].name, "Ok");
2176        assert!(def.variants[0].args.is_empty());
2177        assert_eq!(def.variants[1].name, "Err");
2178        assert!(def.variants[1].args.is_empty());
2179    }
2180
2181    #[test]
2182    fn parse_enum_variant_types() {
2183        let src = "enum Result<T> { Ok(Safe<T, !nan>), Err(string) }";
2184        let program = parse_program(src).unwrap();
2185        let Item::Enum(def) = &program.items[0] else {
2186            panic!("expected enum");
2187        };
2188        assert_eq!(def.variants.len(), 2);
2189        assert_eq!(def.variants[0].name, "Ok");
2190        assert_eq!(
2191            def.variants[0].args,
2192            vec![Type::Safe {
2193                base: Box::new(Type::Ident("T".into())),
2194                constraints: vec!["nan".into()]
2195            }]
2196        );
2197        assert_eq!(def.variants[1].name, "Err");
2198        assert_eq!(def.variants[1].args, vec![Type::Ident("string".into())]);
2199    }
2200
2201    #[test]
2202    fn parse_float_literal() {
2203        let src = "fn main() { let x = 3.14; }";
2204        let program = parse_program(src).unwrap();
2205        let func = match &program.items[0] {
2206            Item::Trait(_) => panic!("expected function"),
2207            Item::Enum(_) => panic!("expected function"),
2208            Item::Pipeline(_) => panic!("expected function"),
2209            Item::Function(func) => func,
2210        };
2211        let Stmt::Let { expr, .. } = &func.body[0] else {
2212            panic!("expected let");
2213        };
2214        assert!(
2215            matches!(expr.kind, ExprKind::Float(f) if (f - 314.0_f64 / 100.0_f64).abs() < 1e-9)
2216        );
2217    }
2218
2219    #[test]
2220    fn parse_typed_let_and_params() {
2221        let src = "fn add(x: i64, y: i64): i64 { let z: i64 = x + y; return z; }";
2222        let program = parse_program(src).unwrap();
2223        let func = match &program.items[0] {
2224            Item::Trait(_) => panic!("expected function"),
2225            Item::Enum(_) => panic!("expected function"),
2226            Item::Pipeline(_) => panic!("expected function"),
2227            Item::Function(func) => func,
2228        };
2229        assert_eq!(func.params.len(), 2);
2230        assert_eq!(func.return_type, Some(Type::Ident("i64".into())));
2231        let Stmt::Let { ty, .. } = &func.body[0] else {
2232            panic!("expected let");
2233        };
2234        assert_eq!(ty, &Some(Type::Ident("i64".into())));
2235    }
2236
2237    #[test]
2238    fn parse_array_and_slice_types() {
2239        let src = "fn main() { let a: [i64; 3] = 0; let b: [i64] = 0; }";
2240        let program = parse_program(src).unwrap();
2241        let func = match &program.items[0] {
2242            Item::Trait(_) => panic!("expected function"),
2243            Item::Enum(_) => panic!("expected function"),
2244            Item::Pipeline(_) => panic!("expected function"),
2245            Item::Function(func) => func,
2246        };
2247        let Stmt::Let { ty, .. } = &func.body[0] else {
2248            panic!("expected let");
2249        };
2250        assert!(matches!(ty, Some(Type::Array { len: 3, .. })));
2251        let Stmt::Let { ty, .. } = &func.body[1] else {
2252            panic!("expected let");
2253        };
2254        assert!(matches!(ty, Some(Type::Slice { .. })));
2255    }
2256
2257    #[test]
2258    fn parse_safe_type() {
2259        let src = "fn main() { let x: Safe<i64, !nan, !inf> = 1; }";
2260        let program = parse_program(src).unwrap();
2261        let func = match &program.items[0] {
2262            Item::Trait(_) => panic!("expected function"),
2263            Item::Enum(_) => panic!("expected function"),
2264            Item::Pipeline(_) => panic!("expected function"),
2265            Item::Function(func) => func,
2266        };
2267        let Stmt::Let { ty, .. } = &func.body[0] else {
2268            panic!("expected let");
2269        };
2270        assert_eq!(
2271            ty,
2272            &Some(Type::Safe {
2273                base: Box::new(Type::Ident("i64".into())),
2274                constraints: vec!["nan".into(), "inf".into()],
2275            })
2276        );
2277    }
2278
2279    #[test]
2280    fn parse_function_type() {
2281        let src = "fn main() { let f: fn(i64, i64) -> i64 = add; }";
2282        let program = parse_program(src).unwrap();
2283        let func = match &program.items[0] {
2284            Item::Trait(_) => panic!("expected function"),
2285            Item::Enum(_) => panic!("expected function"),
2286            Item::Pipeline(_) => panic!("expected function"),
2287            Item::Function(func) => func,
2288        };
2289        let Stmt::Let { ty, .. } = &func.body[0] else {
2290            panic!("expected let");
2291        };
2292        assert_eq!(
2293            ty,
2294            &Some(Type::Func {
2295                params: vec![Type::Ident("i64".into()), Type::Ident("i64".into())],
2296                ret: Box::new(Type::Ident("i64".into())),
2297            })
2298        );
2299    }
2300
2301    #[test]
2302    fn parse_while_and_for() {
2303        let src = "fn main() { while x < 10 { x = x + 1; } for i in xs { return i; } }";
2304        let program = parse_program(src).unwrap();
2305        let func = match &program.items[0] {
2306            Item::Trait(_) => panic!("expected function"),
2307            Item::Enum(_) => panic!("expected function"),
2308            Item::Pipeline(_) => panic!("expected function"),
2309            Item::Function(func) => func,
2310        };
2311        assert!(matches!(func.body[0], Stmt::While { .. }));
2312        assert!(matches!(func.body[1], Stmt::For { .. }));
2313    }
2314
2315    #[test]
2316    fn parse_array_literal() {
2317        let src = "fn main() { let xs = [1, 2, 3]; }";
2318        let program = parse_program(src).unwrap();
2319        let func = match &program.items[0] {
2320            Item::Trait(_) => panic!("expected function"),
2321            Item::Enum(_) => panic!("expected function"),
2322            Item::Pipeline(_) => panic!("expected function"),
2323            Item::Function(func) => func,
2324        };
2325        let Stmt::Let { expr, .. } = &func.body[0] else {
2326            panic!("expected let");
2327        };
2328        assert!(matches!(expr.kind, ExprKind::ArrayLiteral(ref items) if items.len() == 3));
2329    }
2330
2331    #[test]
2332    fn parse_range_expression() {
2333        let src = "fn main() { let xs = 1..10; }";
2334        let program = parse_program(src).unwrap();
2335        let func = match &program.items[0] {
2336            Item::Trait(_) => panic!("expected function"),
2337            Item::Enum(_) => panic!("expected function"),
2338            Item::Pipeline(_) => panic!("expected function"),
2339            Item::Function(func) => func,
2340        };
2341        let Stmt::Let { expr, .. } = &func.body[0] else {
2342            panic!("expected let");
2343        };
2344        assert!(matches!(
2345            expr.kind,
2346            ExprKind::Binary {
2347                op: BinaryOp::Range,
2348                ..
2349            }
2350        ));
2351    }
2352
2353    #[test]
2354    fn parse_match_with_guard() {
2355        let src = "fn main() { match x { y if y > 0 => y, _ => 0, } }";
2356        let program = parse_program(src).unwrap();
2357        let func = match &program.items[0] {
2358            Item::Trait(_) => panic!("expected function"),
2359            Item::Enum(_) => panic!("expected function"),
2360            Item::Pipeline(_) => panic!("expected function"),
2361            Item::Function(func) => func,
2362        };
2363        assert_eq!(func.body.len(), 1);
2364    }
2365
2366    #[test]
2367    fn parse_await_and_block_expr() {
2368        let src = "fn main() { let x = await foo(); { return x; } }";
2369        let program = parse_program(src).unwrap();
2370        let func = match &program.items[0] {
2371            Item::Trait(_) => panic!("expected function"),
2372            Item::Enum(_) => panic!("expected function"),
2373            Item::Pipeline(_) => panic!("expected function"),
2374            Item::Function(func) => func,
2375        };
2376        assert_eq!(func.body.len(), 2);
2377        let Stmt::Let { expr, .. } = &func.body[0] else {
2378            panic!("expected let");
2379        };
2380        assert!(matches!(expr.kind, ExprKind::Await(_)));
2381        assert!(
2382            matches!(func.body[1], Stmt::Expr(ref expr) if matches!(expr.kind, ExprKind::Block(_)))
2383        );
2384    }
2385
2386    #[test]
2387    fn parse_postfix_chain() {
2388        let src = "fn main() { let x = foo(1).bar[0]; }";
2389        let program = parse_program(src).unwrap();
2390        let func = match &program.items[0] {
2391            Item::Trait(_) => panic!("expected function"),
2392            Item::Enum(_) => panic!("expected function"),
2393            Item::Pipeline(_) => panic!("expected function"),
2394            Item::Function(func) => func,
2395        };
2396        let Stmt::Let { expr, .. } = &func.body[0] else {
2397            panic!("expected let");
2398        };
2399        assert!(matches!(expr.kind, ExprKind::Index { .. }));
2400    }
2401}