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(¤t) {
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(¤t) {
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(); 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 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 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, });
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" => {} Some(TokenSpan {
981 token: Token::Step, ..
982 }) => {} 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 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 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}