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