1use tl_ast::*;
13use tl_errors::{ParserError, Span, TlError};
14use tl_lexer::{SpannedToken, Token};
15
16fn make_stmt(kind: StmtKind, start: usize, end: usize) -> Stmt {
18 Stmt {
19 kind,
20 span: Span::new(start, end),
21 doc_comment: None,
22 }
23}
24
25pub struct Parser {
26 tokens: Vec<SpannedToken>,
27 pos: usize,
28}
29
30impl Parser {
31 pub fn new(tokens: Vec<SpannedToken>) -> Self {
32 Self { tokens, pos: 0 }
33 }
34
35 pub fn parse_program(&mut self) -> Result<Program, TlError> {
37 let module_doc = self.consume_inner_doc_comments();
39
40 let mut statements = Vec::new();
41 while !self.is_at_end() {
42 statements.push(self.parse_statement()?);
43 }
44 Ok(Program {
45 statements,
46 module_doc,
47 })
48 }
49
50 fn consume_doc_comments(&mut self) -> Option<String> {
52 let mut lines = Vec::new();
53 while let Token::DocComment(text) = self.peek().clone() {
54 lines.push(text.trim().to_string());
55 self.advance();
56 }
57 if lines.is_empty() {
58 None
59 } else {
60 Some(lines.join("\n"))
61 }
62 }
63
64 fn consume_inner_doc_comments(&mut self) -> Option<String> {
66 let mut lines = Vec::new();
67 while let Token::InnerDocComment(text) = self.peek().clone() {
68 lines.push(text.trim().to_string());
69 self.advance();
70 }
71 if lines.is_empty() {
72 None
73 } else {
74 Some(lines.join("\n"))
75 }
76 }
77
78 fn peek(&self) -> &Token {
81 &self.tokens[self.pos].token
82 }
83
84 fn peek_span(&self) -> Span {
85 self.tokens[self.pos].span
86 }
87
88 fn previous_span(&self) -> Span {
89 if self.pos > 0 {
90 self.tokens[self.pos - 1].span
91 } else {
92 self.tokens[0].span
93 }
94 }
95
96 fn advance(&mut self) -> &SpannedToken {
97 let tok = &self.tokens[self.pos];
98 if !self.is_at_end() {
99 self.pos += 1;
100 }
101 tok
102 }
103
104 fn is_at_end(&self) -> bool {
105 self.pos >= self.tokens.len() - 1
108 }
109
110 fn expect(&mut self, expected: &Token) -> Result<Span, TlError> {
111 if self.peek() == expected {
112 let span = self.peek_span();
113 self.advance();
114 Ok(span)
115 } else {
116 Err(TlError::Parser(ParserError {
117 message: format!(
118 "Expected `{}`, found `{}`",
119 token_name(expected),
120 self.peek()
121 ),
122 span: self.peek_span(),
123 hint: None,
124 }))
125 }
126 }
127
128 fn expect_ident(&mut self) -> Result<String, TlError> {
129 match self.peek().clone() {
130 Token::Ident(name) => {
131 self.advance();
132 Ok(name)
133 }
134 Token::Self_ => {
135 self.advance();
136 Ok("self".to_string())
137 }
138 _ => Err(TlError::Parser(ParserError {
139 message: format!("Expected identifier, found `{}`", self.peek()),
140 span: self.peek_span(),
141 hint: None,
142 })),
143 }
144 }
145
146 fn check(&self, token: &Token) -> bool {
147 self.peek() == token
148 }
149
150 fn match_token(&mut self, token: &Token) -> bool {
151 if self.check(token) {
152 self.advance();
153 true
154 } else {
155 false
156 }
157 }
158
159 fn parse_statement(&mut self) -> Result<Stmt, TlError> {
162 let doc = self.consume_doc_comments();
164 while matches!(self.peek(), Token::InnerDocComment(_)) {
166 self.advance();
167 }
168 let mut stmt = self.parse_statement_inner()?;
169 if let Some(ref doc_text) = doc {
170 if stmt.doc_comment.is_none() {
171 stmt.doc_comment = doc.clone();
172 }
173 if let StmtKind::Schema {
175 ref mut version,
176 ref mut parent_version,
177 ..
178 } = stmt.kind
179 {
180 for line in doc_text.lines() {
181 let trimmed = line.trim();
182 if let Some(rest) = trimmed.strip_prefix("@version") {
183 if let Ok(v) = rest.trim().parse::<i64>() {
184 *version = Some(v);
185 }
186 } else if let Some(rest) = trimmed.strip_prefix("@evolves")
187 && let Ok(v) = rest.trim().parse::<i64>()
188 {
189 *parent_version = Some(v);
190 }
191 }
192 }
193 }
194 Ok(stmt)
195 }
196
197 fn parse_statement_inner(&mut self) -> Result<Stmt, TlError> {
198 match self.peek() {
199 Token::Let => self.parse_let(),
200 Token::Type => self.parse_type_alias(false),
201 Token::Fn => self.parse_fn_decl(),
202 Token::Async => {
203 let start = self.peek_span().start;
204 self.advance(); if self.check(&Token::Fn) {
206 let mut stmt = self.parse_fn_decl()?;
207 if let StmtKind::FnDecl {
208 ref mut is_async, ..
209 } = stmt.kind
210 {
211 *is_async = true;
212 }
213 stmt.span = Span::new(start, stmt.span.end);
214 Ok(stmt)
215 } else {
216 Err(TlError::Parser(tl_errors::ParserError {
217 message: "Expected 'fn' after 'async'".to_string(),
218 span: Span::new(start, self.peek_span().end),
219 hint: None,
220 }))
221 }
222 }
223 Token::If => self.parse_if(),
224 Token::While => self.parse_while(),
225 Token::For => self.parse_for(),
226 Token::Return => self.parse_return(),
227 Token::Schema => self.parse_schema(),
228 Token::Struct => self.parse_struct_decl(),
229 Token::Enum => self.parse_enum_decl(),
230 Token::Impl => self.parse_impl(),
231 Token::Trait => self.parse_trait_def(),
232 Token::Model => self.parse_train(),
233 Token::Pipeline => self.parse_pipeline(),
234 Token::Stream => self.parse_stream_decl(),
235 Token::Source => self.parse_source_decl(),
236 Token::Sink => self.parse_sink_decl(),
237 Token::Try => self.parse_try_catch(),
238 Token::Throw => self.parse_throw(),
239 Token::Import => self.parse_import(),
240 Token::Use => self.parse_use(false),
241 Token::Pub => self.parse_pub(),
242 Token::Mod => self.parse_mod(false),
243 Token::Test => self.parse_test(),
244 Token::Migrate => self.parse_migrate(),
245 Token::Parallel => {
246 let start = self.peek_span().start;
247 self.advance(); self.expect(&Token::For)?;
249 let name = self.expect_ident()?;
250 self.expect(&Token::In)?;
251 let iter = self.parse_expression()?;
252 self.expect(&Token::LBrace)?;
253 let body = self.parse_block_body()?;
254 self.expect(&Token::RBrace)?;
255 let end = self.previous_span().end;
256 Ok(make_stmt(
257 StmtKind::ParallelFor { name, iter, body },
258 start,
259 end,
260 ))
261 }
262 Token::Break => {
263 let start = self.peek_span().start;
264 self.advance();
265 let end = self.previous_span().end;
266 Ok(make_stmt(StmtKind::Break, start, end))
267 }
268 Token::Continue => {
269 let start = self.peek_span().start;
270 self.advance();
271 let end = self.previous_span().end;
272 Ok(make_stmt(StmtKind::Continue, start, end))
273 }
274 _ => {
275 let start = self.peek_span().start;
276 let expr = self.parse_expression()?;
277 let end = self.previous_span().end;
278 Ok(make_stmt(StmtKind::Expr(expr), start, end))
279 }
280 }
281 }
282
283 fn parse_pub(&mut self) -> Result<Stmt, TlError> {
285 let start = self.peek_span().start;
286 self.advance(); match self.peek() {
288 Token::Fn => {
289 let mut stmt = self.parse_fn_decl()?;
290 if let StmtKind::FnDecl {
291 ref mut is_public, ..
292 } = stmt.kind
293 {
294 *is_public = true;
295 }
296 stmt.span = Span::new(start, stmt.span.end);
297 Ok(stmt)
298 }
299 Token::Struct => {
300 let mut stmt = self.parse_struct_decl()?;
301 if let StmtKind::StructDecl {
302 ref mut is_public, ..
303 } = stmt.kind
304 {
305 *is_public = true;
306 }
307 stmt.span = Span::new(start, stmt.span.end);
308 Ok(stmt)
309 }
310 Token::Enum => {
311 let mut stmt = self.parse_enum_decl()?;
312 if let StmtKind::EnumDecl {
313 ref mut is_public, ..
314 } = stmt.kind
315 {
316 *is_public = true;
317 }
318 stmt.span = Span::new(start, stmt.span.end);
319 Ok(stmt)
320 }
321 Token::Schema => {
322 let mut stmt = self.parse_schema()?;
323 if let StmtKind::Schema {
324 ref mut is_public, ..
325 } = stmt.kind
326 {
327 *is_public = true;
328 }
329 stmt.span = Span::new(start, stmt.span.end);
330 Ok(stmt)
331 }
332 Token::Let => {
333 let mut stmt = self.parse_let_with_pub(true)?;
334 stmt.span = Span::new(start, stmt.span.end);
335 Ok(stmt)
336 }
337 Token::Use => {
338 let mut stmt = self.parse_use(true)?;
339 stmt.span = Span::new(start, stmt.span.end);
340 Ok(stmt)
341 }
342 Token::Mod => {
343 let mut stmt = self.parse_mod(true)?;
344 stmt.span = Span::new(start, stmt.span.end);
345 Ok(stmt)
346 }
347 Token::Trait => {
348 let mut stmt = self.parse_trait_def()?;
349 if let StmtKind::TraitDef {
350 ref mut is_public, ..
351 } = stmt.kind
352 {
353 *is_public = true;
354 }
355 stmt.span = Span::new(start, stmt.span.end);
356 Ok(stmt)
357 }
358 Token::Type => {
359 let mut stmt = self.parse_type_alias(true)?;
360 stmt.span = Span::new(start, stmt.span.end);
361 Ok(stmt)
362 }
363 _ => Err(TlError::Parser(ParserError {
364 message: format!(
365 "`pub` can only be applied to fn, struct, enum, schema, let, use, mod, trait, or type, found `{}`",
366 self.peek()
367 ),
368 span: self.peek_span(),
369 hint: None,
370 })),
371 }
372 }
373
374 fn parse_use(&mut self, is_public: bool) -> Result<Stmt, TlError> {
376 let start = self.peek_span().start;
377 self.advance(); let mut segments = Vec::new();
381 segments.push(self.expect_ident()?);
382
383 while self.match_token(&Token::Dot) {
384 match self.peek() {
385 Token::LBrace => {
386 self.advance(); let mut names = Vec::new();
389 names.push(self.expect_ident()?);
390 while self.match_token(&Token::Comma) {
391 if self.check(&Token::RBrace) {
392 break; }
394 names.push(self.expect_ident()?);
395 }
396 self.expect(&Token::RBrace)?;
397 let end = self.previous_span().end;
398 return Ok(make_stmt(
399 StmtKind::Use {
400 item: UseItem::Group(segments, names),
401 is_public,
402 },
403 start,
404 end,
405 ));
406 }
407 Token::Star => {
408 self.advance(); let end = self.previous_span().end;
411 return Ok(make_stmt(
412 StmtKind::Use {
413 item: UseItem::Wildcard(segments),
414 is_public,
415 },
416 start,
417 end,
418 ));
419 }
420 Token::Ident(_) => {
421 segments.push(self.expect_ident()?);
422 }
423 _ => {
424 return Err(TlError::Parser(ParserError {
425 message: format!(
426 "Expected identifier, `{{`, or `*` after `.` in use path, found `{}`",
427 self.peek()
428 ),
429 span: self.peek_span(),
430 hint: None,
431 }));
432 }
433 }
434 }
435
436 if self.match_token(&Token::As) {
438 let alias = self.expect_ident()?;
439 let end = self.previous_span().end;
440 return Ok(make_stmt(
441 StmtKind::Use {
442 item: UseItem::Aliased(segments, alias),
443 is_public,
444 },
445 start,
446 end,
447 ));
448 }
449
450 let end = self.previous_span().end;
452 Ok(make_stmt(
453 StmtKind::Use {
454 item: UseItem::Single(segments),
455 is_public,
456 },
457 start,
458 end,
459 ))
460 }
461
462 fn parse_mod(&mut self, is_public: bool) -> Result<Stmt, TlError> {
464 let start = self.peek_span().start;
465 self.advance(); let name = self.expect_ident()?;
467 let end = self.previous_span().end;
468 Ok(make_stmt(StmtKind::ModDecl { name, is_public }, start, end))
469 }
470
471 fn parse_schema(&mut self) -> Result<Stmt, TlError> {
474 let start = self.peek_span().start;
475 self.advance(); let name = self.expect_ident()?;
477 self.expect(&Token::LBrace)?;
478 let mut fields = Vec::new();
479 while !self.check(&Token::RBrace) && !self.is_at_end() {
480 let field_doc = self.consume_doc_comments();
482 let field_name = self.expect_ident()?;
483 self.expect(&Token::Colon)?;
484 let type_ann = self.parse_type()?;
485 let default_value = if self.match_token(&Token::Assign) {
487 Some(self.parse_expression()?)
488 } else {
489 None
490 };
491 self.match_token(&Token::Comma); let annotations = parse_field_annotations(field_doc.as_deref());
494 fields.push(SchemaField {
495 name: field_name,
496 type_ann,
497 doc_comment: field_doc,
498 default_value,
499 annotations,
500 });
501 }
502 self.expect(&Token::RBrace)?;
503 let end = self.previous_span().end;
504 Ok(make_stmt(
505 StmtKind::Schema {
506 name,
507 fields,
508 is_public: false,
509 version: None,
510 parent_version: None,
511 },
512 start,
513 end,
514 ))
515 }
516
517 fn parse_migrate(&mut self) -> Result<Stmt, TlError> {
519 let start = self.peek_span().start;
520 self.advance(); let schema_name = self.expect_ident()?;
522
523 match self.peek() {
525 Token::Ident(s) if s == "from" => {
526 self.advance();
527 }
528 _ => {
529 return Err(TlError::Parser(ParserError {
530 message: "Expected `from` after schema name in migrate statement".to_string(),
531 span: self.peek_span(),
532 hint: Some("migrate SchemaName from V1 to V2 { ... }".to_string()),
533 }));
534 }
535 }
536 let from_version = match self.peek() {
537 Token::Int(n) => {
538 let n = *n;
539 self.advance();
540 n
541 }
542 _ => {
543 return Err(TlError::Parser(ParserError {
544 message: "Expected version number after `from`".to_string(),
545 span: self.peek_span(),
546 hint: None,
547 }));
548 }
549 };
550
551 match self.peek() {
553 Token::Ident(s) if s == "to" => {
554 self.advance();
555 }
556 _ => {
557 return Err(TlError::Parser(ParserError {
558 message: "Expected `to` after from-version in migrate statement".to_string(),
559 span: self.peek_span(),
560 hint: Some("migrate SchemaName from V1 to V2 { ... }".to_string()),
561 }));
562 }
563 }
564 let to_version = match self.peek() {
565 Token::Int(n) => {
566 let n = *n;
567 self.advance();
568 n
569 }
570 _ => {
571 return Err(TlError::Parser(ParserError {
572 message: "Expected version number after `to`".to_string(),
573 span: self.peek_span(),
574 hint: None,
575 }));
576 }
577 };
578
579 self.expect(&Token::LBrace)?;
580 let mut operations = Vec::new();
581 while !self.check(&Token::RBrace) && !self.is_at_end() {
582 operations.push(self.parse_migrate_op()?);
583 }
584 self.expect(&Token::RBrace)?;
585 let end = self.previous_span().end;
586 Ok(make_stmt(
587 StmtKind::Migrate {
588 schema_name,
589 from_version,
590 to_version,
591 operations,
592 },
593 start,
594 end,
595 ))
596 }
597
598 fn parse_migrate_op(&mut self) -> Result<MigrateOp, TlError> {
600 let op_name = self.expect_ident()?;
601 self.expect(&Token::LParen)?;
602 let result = match op_name.as_str() {
603 "add_column" => {
604 let name = self.expect_ident()?;
605 self.expect(&Token::Colon)?;
606 let type_ann = self.parse_type()?;
607 let default = if self.match_token(&Token::Comma) {
608 if matches!(self.peek(), Token::Ident(s) if s == "default") {
610 self.advance(); self.expect(&Token::Colon)?;
612 Some(self.parse_expression()?)
613 } else {
614 None
615 }
616 } else {
617 None
618 };
619 MigrateOp::AddColumn { name, type_ann, default }
620 }
621 "drop_column" => {
622 let name = self.expect_ident()?;
623 MigrateOp::DropColumn { name }
624 }
625 "rename_column" => {
626 let from = self.expect_ident()?;
627 self.expect(&Token::Comma)?;
628 let to = self.expect_ident()?;
629 MigrateOp::RenameColumn { from, to }
630 }
631 "alter_type" => {
632 let column = self.expect_ident()?;
633 self.expect(&Token::Comma)?;
634 let new_type = self.parse_type()?;
635 MigrateOp::AlterType { column, new_type }
636 }
637 "add_constraint" => {
638 let column = self.expect_ident()?;
639 self.expect(&Token::Comma)?;
640 let constraint = self.expect_ident()?;
641 MigrateOp::AddConstraint { column, constraint }
642 }
643 "drop_constraint" => {
644 let column = self.expect_ident()?;
645 self.expect(&Token::Comma)?;
646 let constraint = self.expect_ident()?;
647 MigrateOp::DropConstraint { column, constraint }
648 }
649 _ => return Err(TlError::Parser(ParserError {
650 message: format!("Unknown migration operation: `{op_name}`"),
651 span: self.peek_span(),
652 hint: Some("Valid operations: add_column, drop_column, rename_column, alter_type, add_constraint, drop_constraint".to_string()),
653 })),
654 };
655 self.expect(&Token::RParen)?;
656 Ok(result)
657 }
658
659 fn parse_train(&mut self) -> Result<Stmt, TlError> {
661 let start = self.peek_span().start;
662 self.advance(); let name = self.expect_ident()?;
664 self.expect(&Token::Assign)?;
665 self.expect(&Token::Train)?;
666 let algorithm = self.expect_ident()?;
667 self.expect(&Token::LBrace)?;
668 let mut config = Vec::new();
669 while !self.check(&Token::RBrace) && !self.is_at_end() {
670 let key = self.expect_ident()?;
671 self.expect(&Token::Colon)?;
672 let value = self.parse_expression()?;
673 self.match_token(&Token::Comma); config.push((key, value));
675 }
676 self.expect(&Token::RBrace)?;
677 let end = self.previous_span().end;
678 Ok(make_stmt(
679 StmtKind::Train {
680 name,
681 algorithm,
682 config,
683 },
684 start,
685 end,
686 ))
687 }
688
689 fn parse_pipeline(&mut self) -> Result<Stmt, TlError> {
691 let start = self.peek_span().start;
692 self.advance(); let name = self.expect_ident()?;
694 self.expect(&Token::LBrace)?;
695
696 let mut extract = Vec::new();
697 let mut transform = Vec::new();
698 let mut load = Vec::new();
699 let mut schedule = None;
700 let mut timeout = None;
701 let mut retries = None;
702 let mut on_failure = None;
703 let mut on_success = None;
704
705 while !self.check(&Token::RBrace) && !self.is_at_end() {
706 match self.peek() {
707 Token::Extract => {
708 self.advance();
709 self.expect(&Token::LBrace)?;
710 extract = self.parse_block_body()?;
711 self.expect(&Token::RBrace)?;
712 }
713 Token::Transform => {
714 self.advance();
715 self.expect(&Token::LBrace)?;
716 transform = self.parse_block_body()?;
717 self.expect(&Token::RBrace)?;
718 }
719 Token::Load => {
720 self.advance();
721 self.expect(&Token::LBrace)?;
722 load = self.parse_block_body()?;
723 self.expect(&Token::RBrace)?;
724 }
725 Token::Ident(s) if s == "schedule" => {
726 self.advance();
727 self.expect(&Token::Colon)?;
728 if let Token::String(s) = self.peek().clone() {
729 self.advance();
730 schedule = Some(s);
731 } else {
732 schedule = Some(self.parse_duration_literal()?);
733 }
734 self.match_token(&Token::Comma);
735 }
736 Token::Ident(s) if s == "timeout" => {
737 self.advance();
738 self.expect(&Token::Colon)?;
739 if let Token::String(s) = self.peek().clone() {
740 self.advance();
741 timeout = Some(s);
742 } else {
743 timeout = Some(self.parse_duration_literal()?);
744 }
745 self.match_token(&Token::Comma);
746 }
747 Token::Ident(s) if s == "retries" => {
748 self.advance();
749 self.expect(&Token::Colon)?;
750 if let Token::Int(n) = self.peek().clone() {
751 self.advance();
752 retries = Some(n);
753 } else {
754 return Err(TlError::Parser(ParserError {
755 message: "Expected integer for retries".to_string(),
756 span: self.peek_span(),
757 hint: None,
758 }));
759 }
760 self.match_token(&Token::Comma);
761 }
762 Token::Ident(s) if s == "on_failure" => {
763 self.advance();
764 self.expect(&Token::LBrace)?;
765 on_failure = Some(self.parse_block_body()?);
766 self.expect(&Token::RBrace)?;
767 }
768 Token::Ident(s) if s == "on_success" => {
769 self.advance();
770 self.expect(&Token::LBrace)?;
771 on_success = Some(self.parse_block_body()?);
772 self.expect(&Token::RBrace)?;
773 }
774 _ => {
775 return Err(TlError::Parser(ParserError {
776 message: format!(
777 "Unexpected token in pipeline block: `{}`",
778 self.peek()
779 ),
780 span: self.peek_span(),
781 hint: Some("Expected extract, transform, load, schedule, timeout, retries, on_failure, or on_success".into()),
782 }));
783 }
784 }
785 }
786 self.expect(&Token::RBrace)?;
787 let end = self.previous_span().end;
788 Ok(make_stmt(
789 StmtKind::Pipeline {
790 name,
791 extract,
792 transform,
793 load,
794 schedule,
795 timeout,
796 retries,
797 on_failure,
798 on_success,
799 },
800 start,
801 end,
802 ))
803 }
804
805 fn parse_stream_decl(&mut self) -> Result<Stmt, TlError> {
807 let start = self.peek_span().start;
808 self.advance(); let name = self.expect_ident()?;
810 self.expect(&Token::LBrace)?;
811
812 let mut source = None;
813 let mut transform = Vec::new();
814 let mut sink = None;
815 let mut window = None;
816 let mut watermark = None;
817
818 while !self.check(&Token::RBrace) && !self.is_at_end() {
819 match self.peek() {
820 Token::Source => {
821 self.advance();
822 self.expect(&Token::Colon)?;
823 source = Some(self.parse_expression()?);
824 self.match_token(&Token::Comma);
825 }
826 Token::Sink => {
827 self.advance();
828 self.expect(&Token::Colon)?;
829 sink = Some(self.parse_expression()?);
830 self.match_token(&Token::Comma);
831 }
832 Token::Transform => {
833 self.advance();
834 self.expect(&Token::Colon)?;
835 self.expect(&Token::LBrace)?;
836 transform = self.parse_block_body()?;
837 self.expect(&Token::RBrace)?;
838 self.match_token(&Token::Comma);
839 }
840 Token::Ident(s) if s == "window" => {
841 self.advance();
842 self.expect(&Token::Colon)?;
843 window = Some(self.parse_window_spec()?);
844 self.match_token(&Token::Comma);
845 }
846 Token::Ident(s) if s == "watermark" => {
847 self.advance();
848 self.expect(&Token::Colon)?;
849 if let Token::String(s) = self.peek().clone() {
850 self.advance();
851 watermark = Some(s);
852 } else {
853 watermark = Some(self.parse_duration_literal()?);
854 }
855 self.match_token(&Token::Comma);
856 }
857 _ => {
858 return Err(TlError::Parser(ParserError {
859 message: format!("Unexpected token in stream block: `{}`", self.peek()),
860 span: self.peek_span(),
861 hint: Some("Expected source, sink, transform, window, or watermark".into()),
862 }));
863 }
864 }
865 }
866 self.expect(&Token::RBrace)?;
867
868 let source = source.ok_or_else(|| {
869 TlError::Parser(ParserError {
870 message: "Stream declaration requires a source".to_string(),
871 span: self.peek_span(),
872 hint: None,
873 })
874 })?;
875
876 let end = self.previous_span().end;
877 Ok(make_stmt(
878 StmtKind::StreamDecl {
879 name,
880 source,
881 transform,
882 sink,
883 window,
884 watermark,
885 },
886 start,
887 end,
888 ))
889 }
890
891 fn parse_source_decl(&mut self) -> Result<Stmt, TlError> {
893 let start = self.peek_span().start;
894 self.advance(); let name = self.expect_ident()?;
896 self.expect(&Token::Assign)?;
897 self.expect(&Token::Connector)?;
898 let connector_type = self.expect_ident()?;
899 self.expect(&Token::LBrace)?;
900 let mut config = Vec::new();
901 while !self.check(&Token::RBrace) && !self.is_at_end() {
902 let key = self.expect_ident()?;
903 self.expect(&Token::Colon)?;
904 let value = self.parse_expression()?;
905 self.match_token(&Token::Comma);
906 config.push((key, value));
907 }
908 self.expect(&Token::RBrace)?;
909 let end = self.previous_span().end;
910 Ok(make_stmt(
911 StmtKind::SourceDecl {
912 name,
913 connector_type,
914 config,
915 },
916 start,
917 end,
918 ))
919 }
920
921 fn parse_sink_decl(&mut self) -> Result<Stmt, TlError> {
923 let start = self.peek_span().start;
924 self.advance(); let name = self.expect_ident()?;
926 self.expect(&Token::Assign)?;
927 self.expect(&Token::Connector)?;
928 let connector_type = self.expect_ident()?;
929 self.expect(&Token::LBrace)?;
930 let mut config = Vec::new();
931 while !self.check(&Token::RBrace) && !self.is_at_end() {
932 let key = self.expect_ident()?;
933 self.expect(&Token::Colon)?;
934 let value = self.parse_expression()?;
935 self.match_token(&Token::Comma);
936 config.push((key, value));
937 }
938 self.expect(&Token::RBrace)?;
939 let end = self.previous_span().end;
940 Ok(make_stmt(
941 StmtKind::SinkDecl {
942 name,
943 connector_type,
944 config,
945 },
946 start,
947 end,
948 ))
949 }
950
951 fn parse_window_spec(&mut self) -> Result<WindowSpec, TlError> {
953 let kind = self.expect_ident()?;
954 self.expect(&Token::LParen)?;
955 match kind.as_str() {
956 "tumbling" => {
957 let dur = self.parse_duration_literal()?;
958 self.expect(&Token::RParen)?;
959 Ok(WindowSpec::Tumbling(dur))
960 }
961 "sliding" => {
962 let window = self.parse_duration_literal()?;
963 self.expect(&Token::Comma)?;
964 let slide = self.parse_duration_literal()?;
965 self.expect(&Token::RParen)?;
966 Ok(WindowSpec::Sliding(window, slide))
967 }
968 "session" => {
969 let gap = self.parse_duration_literal()?;
970 self.expect(&Token::RParen)?;
971 Ok(WindowSpec::Session(gap))
972 }
973 _ => Err(TlError::Parser(ParserError {
974 message: format!("Unknown window type: `{kind}`"),
975 span: self.peek_span(),
976 hint: Some("Expected tumbling, sliding, or session".into()),
977 })),
978 }
979 }
980
981 fn parse_duration_literal(&mut self) -> Result<String, TlError> {
983 match self.peek().clone() {
984 Token::DurationMs(n) => {
985 self.advance();
986 Ok(format!("{n}ms"))
987 }
988 Token::DurationS(n) => {
989 self.advance();
990 Ok(format!("{n}s"))
991 }
992 Token::DurationM(n) => {
993 self.advance();
994 Ok(format!("{n}m"))
995 }
996 Token::DurationH(n) => {
997 self.advance();
998 Ok(format!("{n}h"))
999 }
1000 Token::DurationD(n) => {
1001 self.advance();
1002 Ok(format!("{n}d"))
1003 }
1004 Token::String(s) => {
1005 self.advance();
1006 Ok(s)
1007 }
1008 _ => Err(TlError::Parser(ParserError {
1009 message: format!("Expected duration literal, found `{}`", self.peek()),
1010 span: self.peek_span(),
1011 hint: Some("Expected a duration like 5m, 30s, 100ms, 1h, or 1d".into()),
1012 })),
1013 }
1014 }
1015
1016 fn parse_let(&mut self) -> Result<Stmt, TlError> {
1017 self.parse_let_with_pub(false)
1018 }
1019
1020 fn parse_let_with_pub(&mut self, is_public: bool) -> Result<Stmt, TlError> {
1021 let start = self.peek_span().start;
1022 self.advance(); let mutable = self.match_token(&Token::Mut);
1024 match self.peek() {
1027 Token::LBrace | Token::LBracket => {
1028 let pattern = self.parse_pattern()?;
1029 self.expect(&Token::Assign)?;
1030 let value = self.parse_expression()?;
1031 let end = self.previous_span().end;
1032 return Ok(make_stmt(
1033 StmtKind::LetDestructure {
1034 pattern,
1035 mutable,
1036 value,
1037 is_public,
1038 },
1039 start,
1040 end,
1041 ));
1042 }
1043 Token::Ident(_) => {
1044 if self.pos + 1 < self.tokens.len()
1046 && matches!(self.tokens[self.pos + 1].token, Token::ColonColon)
1047 {
1048 let pattern = self.parse_pattern()?;
1049 self.expect(&Token::Assign)?;
1050 let value = self.parse_expression()?;
1051 let end = self.previous_span().end;
1052 return Ok(make_stmt(
1053 StmtKind::LetDestructure {
1054 pattern,
1055 mutable,
1056 value,
1057 is_public,
1058 },
1059 start,
1060 end,
1061 ));
1062 }
1063 if self.pos + 1 < self.tokens.len()
1065 && matches!(self.tokens[self.pos + 1].token, Token::LBrace)
1066 && self.pos + 2 < self.tokens.len()
1067 {
1068 let third = &self.tokens[self.pos + 2].token;
1069 if matches!(third, Token::Ident(_) | Token::RBrace) {
1070 let pattern = self.parse_pattern()?;
1071 self.expect(&Token::Assign)?;
1072 let value = self.parse_expression()?;
1073 let end = self.previous_span().end;
1074 return Ok(make_stmt(
1075 StmtKind::LetDestructure {
1076 pattern,
1077 mutable,
1078 value,
1079 is_public,
1080 },
1081 start,
1082 end,
1083 ));
1084 }
1085 }
1086 }
1087 _ => {}
1088 }
1089 let name = self.expect_ident()?;
1090 let type_ann = if self.match_token(&Token::Colon) {
1091 Some(self.parse_type()?)
1092 } else {
1093 None
1094 };
1095 self.expect(&Token::Assign)?;
1096 let value = self.parse_expression()?;
1097 let end = self.previous_span().end;
1098 Ok(make_stmt(
1099 StmtKind::Let {
1100 name,
1101 mutable,
1102 type_ann,
1103 value,
1104 is_public,
1105 },
1106 start,
1107 end,
1108 ))
1109 }
1110
1111 fn parse_fn_decl(&mut self) -> Result<Stmt, TlError> {
1112 let start = self.peek_span().start;
1113 self.advance(); let name = self.expect_ident()?;
1115
1116 let (type_params, mut bounds) = self.parse_optional_type_params_with_bounds()?;
1118
1119 self.expect(&Token::LParen)?;
1120 let params = self.parse_param_list()?;
1121 self.expect(&Token::RParen)?;
1122 let return_type = if self.match_token(&Token::Arrow) {
1123 Some(self.parse_type()?)
1124 } else {
1125 None
1126 };
1127
1128 if self.check(&Token::Where) {
1130 self.advance(); let where_bounds = self.parse_where_clause()?;
1132 bounds.extend(where_bounds);
1133 }
1134
1135 self.expect(&Token::LBrace)?;
1136 let body = self.parse_block_body()?;
1137 self.expect(&Token::RBrace)?;
1138 let is_generator = body_contains_yield(&body);
1139 let end = self.previous_span().end;
1140 Ok(make_stmt(
1141 StmtKind::FnDecl {
1142 name,
1143 type_params,
1144 params,
1145 return_type,
1146 bounds,
1147 body,
1148 is_generator,
1149 is_public: false,
1150 is_async: false,
1151 },
1152 start,
1153 end,
1154 ))
1155 }
1156
1157 fn parse_if(&mut self) -> Result<Stmt, TlError> {
1158 let start = self.peek_span().start;
1159 self.advance(); let condition = self.parse_expression()?;
1161 self.expect(&Token::LBrace)?;
1162 let then_body = self.parse_block_body()?;
1163 self.expect(&Token::RBrace)?;
1164
1165 let mut else_ifs = Vec::new();
1166 let mut else_body = None;
1167
1168 while self.match_token(&Token::Else) {
1169 if self.match_token(&Token::If) {
1170 let cond = self.parse_expression()?;
1171 self.expect(&Token::LBrace)?;
1172 let body = self.parse_block_body()?;
1173 self.expect(&Token::RBrace)?;
1174 else_ifs.push((cond, body));
1175 } else {
1176 self.expect(&Token::LBrace)?;
1177 else_body = Some(self.parse_block_body()?);
1178 self.expect(&Token::RBrace)?;
1179 break;
1180 }
1181 }
1182
1183 let end = self.previous_span().end;
1184 Ok(make_stmt(
1185 StmtKind::If {
1186 condition,
1187 then_body,
1188 else_ifs,
1189 else_body,
1190 },
1191 start,
1192 end,
1193 ))
1194 }
1195
1196 fn parse_while(&mut self) -> Result<Stmt, TlError> {
1197 let start = self.peek_span().start;
1198 self.advance(); let condition = self.parse_expression()?;
1200 self.expect(&Token::LBrace)?;
1201 let body = self.parse_block_body()?;
1202 self.expect(&Token::RBrace)?;
1203 let end = self.previous_span().end;
1204 Ok(make_stmt(StmtKind::While { condition, body }, start, end))
1205 }
1206
1207 fn parse_for(&mut self) -> Result<Stmt, TlError> {
1208 let start = self.peek_span().start;
1209 self.advance(); let name = self.expect_ident()?;
1211 self.expect(&Token::In)?;
1212 let iter = self.parse_expression()?;
1213 self.expect(&Token::LBrace)?;
1214 let body = self.parse_block_body()?;
1215 self.expect(&Token::RBrace)?;
1216 let end = self.previous_span().end;
1217 Ok(make_stmt(StmtKind::For { name, iter, body }, start, end))
1218 }
1219
1220 fn parse_return(&mut self) -> Result<Stmt, TlError> {
1221 let start = self.peek_span().start;
1222 self.advance(); if self.check(&Token::RBrace) || self.is_at_end() {
1224 let end = self.previous_span().end;
1225 Ok(make_stmt(StmtKind::Return(None), start, end))
1226 } else {
1227 let expr = self.parse_expression()?;
1228 let end = self.previous_span().end;
1229 Ok(make_stmt(StmtKind::Return(Some(expr)), start, end))
1230 }
1231 }
1232
1233 fn parse_block_body(&mut self) -> Result<Vec<Stmt>, TlError> {
1234 let mut stmts = Vec::new();
1235 while !self.check(&Token::RBrace) && !self.is_at_end() {
1236 stmts.push(self.parse_statement()?);
1237 }
1238 Ok(stmts)
1239 }
1240
1241 fn parse_expression(&mut self) -> Result<Expr, TlError> {
1244 let expr = self.parse_pipe()?;
1245 if self.match_token(&Token::Assign) {
1247 let value = self.parse_expression()?;
1248 return Ok(Expr::Assign {
1249 target: Box::new(expr),
1250 value: Box::new(value),
1251 });
1252 }
1253 Ok(expr)
1254 }
1255
1256 fn parse_pipe(&mut self) -> Result<Expr, TlError> {
1258 let mut left = self.parse_null_coalesce()?;
1259 while self.match_token(&Token::Pipe) {
1260 let right = self.parse_null_coalesce()?;
1261 left = Expr::Pipe {
1262 left: Box::new(left),
1263 right: Box::new(right),
1264 };
1265 }
1266 Ok(left)
1267 }
1268
1269 fn parse_null_coalesce(&mut self) -> Result<Expr, TlError> {
1271 let mut left = self.parse_or()?;
1272 while self.match_token(&Token::NullCoalesce) {
1273 let right = self.parse_or()?;
1274 left = Expr::NullCoalesce {
1275 expr: Box::new(left),
1276 default: Box::new(right),
1277 };
1278 }
1279 Ok(left)
1280 }
1281
1282 fn parse_or(&mut self) -> Result<Expr, TlError> {
1284 let mut left = self.parse_and()?;
1285 while self.match_token(&Token::Or) {
1286 let right = self.parse_and()?;
1287 left = Expr::BinOp {
1288 left: Box::new(left),
1289 op: BinOp::Or,
1290 right: Box::new(right),
1291 };
1292 }
1293 Ok(left)
1294 }
1295
1296 fn parse_and(&mut self) -> Result<Expr, TlError> {
1298 let mut left = self.parse_comparison()?;
1299 while self.match_token(&Token::And) {
1300 let right = self.parse_comparison()?;
1301 left = Expr::BinOp {
1302 left: Box::new(left),
1303 op: BinOp::And,
1304 right: Box::new(right),
1305 };
1306 }
1307 Ok(left)
1308 }
1309
1310 fn parse_comparison(&mut self) -> Result<Expr, TlError> {
1312 let mut left = self.parse_addition()?;
1313 loop {
1314 let op = match self.peek() {
1315 Token::Eq => BinOp::Eq,
1316 Token::Neq => BinOp::Neq,
1317 Token::Lt => BinOp::Lt,
1318 Token::Gt => BinOp::Gt,
1319 Token::Lte => BinOp::Lte,
1320 Token::Gte => BinOp::Gte,
1321 _ => break,
1322 };
1323 self.advance();
1324 let right = self.parse_addition()?;
1325 left = Expr::BinOp {
1326 left: Box::new(left),
1327 op,
1328 right: Box::new(right),
1329 };
1330 }
1331 Ok(left)
1332 }
1333
1334 fn parse_addition(&mut self) -> Result<Expr, TlError> {
1336 let mut left = self.parse_multiplication()?;
1337 loop {
1338 let op = match self.peek() {
1339 Token::Plus => BinOp::Add,
1340 Token::Minus => BinOp::Sub,
1341 _ => break,
1342 };
1343 self.advance();
1344 let right = self.parse_multiplication()?;
1345 left = Expr::BinOp {
1346 left: Box::new(left),
1347 op,
1348 right: Box::new(right),
1349 };
1350 }
1351 Ok(left)
1352 }
1353
1354 fn parse_multiplication(&mut self) -> Result<Expr, TlError> {
1356 let mut left = self.parse_power()?;
1357 loop {
1358 let op = match self.peek() {
1359 Token::Star => BinOp::Mul,
1360 Token::Slash => BinOp::Div,
1361 Token::Percent => BinOp::Mod,
1362 _ => break,
1363 };
1364 self.advance();
1365 let right = self.parse_power()?;
1366 left = Expr::BinOp {
1367 left: Box::new(left),
1368 op,
1369 right: Box::new(right),
1370 };
1371 }
1372 Ok(left)
1373 }
1374
1375 fn parse_power(&mut self) -> Result<Expr, TlError> {
1377 let left = self.parse_unary()?;
1378 if self.match_token(&Token::Power) {
1379 let right = self.parse_power()?; Ok(Expr::BinOp {
1381 left: Box::new(left),
1382 op: BinOp::Pow,
1383 right: Box::new(right),
1384 })
1385 } else {
1386 Ok(left)
1387 }
1388 }
1389
1390 fn parse_unary(&mut self) -> Result<Expr, TlError> {
1392 if self.match_token(&Token::Yield) {
1393 if self.is_at_end()
1395 || matches!(
1396 self.peek(),
1397 Token::RBrace
1398 | Token::RParen
1399 | Token::Comma
1400 | Token::Semicolon
1401 | Token::Let
1402 | Token::Fn
1403 | Token::If
1404 | Token::While
1405 | Token::For
1406 | Token::Return
1407 | Token::Yield
1408 | Token::Struct
1409 | Token::Enum
1410 | Token::Impl
1411 | Token::Trait
1412 | Token::Import
1413 | Token::Try
1414 | Token::Throw
1415 )
1416 {
1417 return Ok(Expr::Yield(None));
1418 }
1419 let expr = self.parse_expression()?;
1420 return Ok(Expr::Yield(Some(Box::new(expr))));
1421 }
1422 if self.match_token(&Token::Await) {
1423 let expr = self.parse_unary()?;
1424 return Ok(Expr::Await(Box::new(expr)));
1425 }
1426 if self.match_token(&Token::Not) {
1427 let expr = self.parse_unary()?;
1428 return Ok(Expr::UnaryOp {
1429 op: UnaryOp::Not,
1430 expr: Box::new(expr),
1431 });
1432 }
1433 if self.match_token(&Token::Minus) {
1434 let expr = self.parse_unary()?;
1435 return Ok(Expr::UnaryOp {
1436 op: UnaryOp::Neg,
1437 expr: Box::new(expr),
1438 });
1439 }
1440 if self.match_token(&Token::Ampersand) {
1441 let expr = self.parse_unary()?;
1442 return Ok(Expr::UnaryOp {
1443 op: UnaryOp::Ref,
1444 expr: Box::new(expr),
1445 });
1446 }
1447 self.parse_postfix()
1448 }
1449
1450 fn parse_postfix(&mut self) -> Result<Expr, TlError> {
1452 let mut expr = self.parse_primary()?;
1453 loop {
1454 if self.match_token(&Token::Dot) {
1455 let field = self.expect_ident()?;
1456 expr = Expr::Member {
1457 object: Box::new(expr),
1458 field,
1459 };
1460 } else if self.check(&Token::ColonColon) {
1461 if let Expr::Ident(enum_name) = &expr {
1463 let enum_name = enum_name.clone();
1464 self.advance(); let variant = self.expect_ident()?;
1466 let mut args = Vec::new();
1467 if self.match_token(&Token::LParen) {
1468 if !self.check(&Token::RParen) {
1469 args.push(self.parse_expression()?);
1470 while self.match_token(&Token::Comma) {
1471 if self.check(&Token::RParen) {
1472 break;
1473 }
1474 args.push(self.parse_expression()?);
1475 }
1476 }
1477 self.expect(&Token::RParen)?;
1478 }
1479 expr = Expr::EnumVariant {
1480 enum_name,
1481 variant,
1482 args,
1483 };
1484 } else {
1485 break;
1486 }
1487 } else if self.check(&Token::LBrace) {
1488 if let Expr::Ident(name) = &expr {
1490 if self.is_struct_init_ahead() {
1492 let name = name.clone();
1493 self.advance(); let mut fields = Vec::new();
1495 while !self.check(&Token::RBrace) && !self.is_at_end() {
1496 let field_name = self.expect_ident()?;
1497 self.expect(&Token::Colon)?;
1498 let value = self.parse_expression()?;
1499 self.match_token(&Token::Comma);
1500 fields.push((field_name, value));
1501 }
1502 self.expect(&Token::RBrace)?;
1503 expr = Expr::StructInit { name, fields };
1504 } else {
1505 break;
1506 }
1507 } else {
1508 break;
1509 }
1510 } else if self.check(&Token::LParen) {
1511 self.advance();
1512 let args = self.parse_arg_list()?;
1513 self.expect(&Token::RParen)?;
1514 expr = Expr::Call {
1515 function: Box::new(expr),
1516 args,
1517 };
1518 } else if self.match_token(&Token::LBracket) {
1519 let index = self.parse_expression()?;
1520 self.expect(&Token::RBracket)?;
1521 expr = Expr::Index {
1522 object: Box::new(expr),
1523 index: Box::new(index),
1524 };
1525 } else if self.match_token(&Token::Question) {
1526 expr = Expr::Try(Box::new(expr));
1528 } else {
1529 break;
1530 }
1531 }
1532 Ok(expr)
1533 }
1534
1535 fn parse_match_arm(&mut self) -> Result<MatchArm, TlError> {
1540 let pattern = self.parse_pattern()?;
1541 let guard = if self.match_token(&Token::If) {
1542 Some(self.parse_expression()?)
1543 } else {
1544 None
1545 };
1546 self.expect(&Token::FatArrow)?;
1547 let body = self.parse_expression()?;
1548 Ok(MatchArm {
1549 pattern,
1550 guard,
1551 body,
1552 })
1553 }
1554
1555 fn parse_case_arm(&mut self) -> Result<MatchArm, TlError> {
1559 if self.check(&Token::Underscore) {
1561 self.advance();
1562 self.expect(&Token::FatArrow)?;
1563 let body = self.parse_expression()?;
1564 return Ok(MatchArm {
1565 pattern: Pattern::Wildcard,
1566 guard: None,
1567 body,
1568 });
1569 }
1570 let condition = self.parse_expression()?;
1572 self.expect(&Token::FatArrow)?;
1573 let body = self.parse_expression()?;
1574 Ok(MatchArm {
1575 pattern: Pattern::Wildcard,
1576 guard: Some(condition),
1577 body,
1578 })
1579 }
1580
1581 fn parse_pattern(&mut self) -> Result<Pattern, TlError> {
1583 let pat = self.parse_single_pattern()?;
1584 if self.check(&Token::Or) {
1587 let mut patterns = vec![pat];
1588 while self.check(&Token::Or) {
1589 self.advance(); patterns.push(self.parse_single_pattern()?);
1591 }
1592 Ok(Pattern::Or(patterns))
1593 } else {
1594 Ok(pat)
1595 }
1596 }
1597
1598 fn parse_single_pattern(&mut self) -> Result<Pattern, TlError> {
1600 let token = self.peek().clone();
1601 match token {
1602 Token::Underscore => {
1604 self.advance();
1605 Ok(Pattern::Wildcard)
1606 }
1607 Token::Int(n) => {
1609 self.advance();
1610 Ok(Pattern::Literal(Expr::Int(n)))
1611 }
1612 Token::Float(n) => {
1613 self.advance();
1614 Ok(Pattern::Literal(Expr::Float(n)))
1615 }
1616 Token::String(s) => {
1617 self.advance();
1618 Ok(Pattern::Literal(Expr::String(s)))
1619 }
1620 Token::True => {
1621 self.advance();
1622 Ok(Pattern::Literal(Expr::Bool(true)))
1623 }
1624 Token::False => {
1625 self.advance();
1626 Ok(Pattern::Literal(Expr::Bool(false)))
1627 }
1628 Token::None_ => {
1629 self.advance();
1630 Ok(Pattern::Literal(Expr::None))
1631 }
1632 Token::Minus => {
1634 self.advance();
1635 match self.peek().clone() {
1636 Token::Int(n) => {
1637 self.advance();
1638 Ok(Pattern::Literal(Expr::Int(-n)))
1639 }
1640 Token::Float(n) => {
1641 self.advance();
1642 Ok(Pattern::Literal(Expr::Float(-n)))
1643 }
1644 _ => Err(TlError::Parser(ParserError {
1645 message: "Expected number after '-' in pattern".to_string(),
1646 span: self.peek_span(),
1647 hint: None,
1648 })),
1649 }
1650 }
1651 Token::LBracket => {
1653 self.advance(); let mut elements = Vec::new();
1655 let mut rest = None;
1656 while !self.check(&Token::RBracket) && !self.is_at_end() {
1657 if self.check(&Token::DotDotDot) {
1659 self.advance(); let name = self.expect_ident()?;
1661 rest = Some(name);
1662 self.match_token(&Token::Comma); break;
1664 }
1665 elements.push(self.parse_pattern()?);
1666 if !self.match_token(&Token::Comma) {
1667 break;
1668 }
1669 }
1670 self.expect(&Token::RBracket)?;
1671 Ok(Pattern::List { elements, rest })
1672 }
1673 Token::LBrace => {
1675 self.advance(); let mut fields = Vec::new();
1677 while !self.check(&Token::RBrace) && !self.is_at_end() {
1678 let name = self.expect_ident()?;
1679 let sub_pat = if self.match_token(&Token::Colon) {
1680 Some(self.parse_pattern()?)
1681 } else {
1682 None
1683 };
1684 fields.push(StructPatternField {
1685 name,
1686 pattern: sub_pat,
1687 });
1688 if !self.match_token(&Token::Comma) {
1689 break;
1690 }
1691 }
1692 self.expect(&Token::RBrace)?;
1693 Ok(Pattern::Struct { name: None, fields })
1694 }
1695 Token::Ident(name) => {
1697 if self.pos + 1 < self.tokens.len()
1699 && matches!(self.tokens[self.pos + 1].token, Token::ColonColon)
1700 {
1701 let type_name = name.clone();
1702 self.advance(); self.advance(); let variant = self.expect_ident()?;
1705 let mut args = Vec::new();
1707 if self.match_token(&Token::LParen) {
1708 while !self.check(&Token::RParen) && !self.is_at_end() {
1709 args.push(self.parse_pattern()?);
1710 if !self.match_token(&Token::Comma) {
1711 break;
1712 }
1713 }
1714 self.expect(&Token::RParen)?;
1715 }
1716 return Ok(Pattern::Enum {
1717 type_name,
1718 variant,
1719 args,
1720 });
1721 }
1722 if self.pos + 1 < self.tokens.len()
1724 && matches!(self.tokens[self.pos + 1].token, Token::LBrace)
1725 {
1726 if self.pos + 2 < self.tokens.len() {
1729 let third = &self.tokens[self.pos + 2].token;
1730 if matches!(third, Token::Ident(_) | Token::RBrace) {
1731 let struct_name = name.clone();
1732 self.advance(); self.advance(); let mut fields = Vec::new();
1735 while !self.check(&Token::RBrace) && !self.is_at_end() {
1736 let fname = self.expect_ident()?;
1737 let sub_pat = if self.match_token(&Token::Colon) {
1738 Some(self.parse_pattern()?)
1739 } else {
1740 None
1741 };
1742 fields.push(StructPatternField {
1743 name: fname,
1744 pattern: sub_pat,
1745 });
1746 if !self.match_token(&Token::Comma) {
1747 break;
1748 }
1749 }
1750 self.expect(&Token::RBrace)?;
1751 return Ok(Pattern::Struct {
1752 name: Some(struct_name),
1753 fields,
1754 });
1755 }
1756 }
1757 }
1758 self.advance();
1760 Ok(Pattern::Binding(name))
1761 }
1762 _ => Err(TlError::Parser(ParserError {
1763 message: format!("Expected pattern, found `{}`", self.peek()),
1764 span: self.peek_span(),
1765 hint: None,
1766 })),
1767 }
1768 }
1769
1770 fn is_struct_init_ahead(&self) -> bool {
1771 if self.pos + 2 < self.tokens.len() {
1773 matches!(self.tokens[self.pos].token, Token::LBrace)
1774 && matches!(&self.tokens[self.pos + 1].token, Token::Ident(_))
1775 && matches!(self.tokens[self.pos + 2].token, Token::Colon)
1776 } else {
1777 false
1778 }
1779 }
1780
1781 fn parse_primary(&mut self) -> Result<Expr, TlError> {
1783 let token = self.peek().clone();
1784 match token {
1785 Token::Int(n) => {
1786 self.advance();
1787 Ok(Expr::Int(n))
1788 }
1789 Token::Float(n) => {
1790 self.advance();
1791 Ok(Expr::Float(n))
1792 }
1793 Token::DecimalLiteral(s) => {
1794 let s = s.clone();
1795 self.advance();
1796 Ok(Expr::Decimal(s))
1797 }
1798 Token::String(s) => {
1799 let s = s.clone();
1800 self.advance();
1801 Ok(Expr::String(s))
1802 }
1803 Token::True => {
1804 self.advance();
1805 Ok(Expr::Bool(true))
1806 }
1807 Token::False => {
1808 self.advance();
1809 Ok(Expr::Bool(false))
1810 }
1811 Token::None_ => {
1812 self.advance();
1813 Ok(Expr::None)
1814 }
1815 Token::Ident(name) => {
1816 let name = name.clone();
1817 if self.pos + 1 < self.tokens.len()
1819 && self.tokens[self.pos + 1].token == Token::FatArrow
1820 {
1821 self.advance(); self.advance(); let body = self.parse_expression()?;
1824 return Ok(Expr::Closure {
1825 params: vec![Param {
1826 name,
1827 type_ann: None,
1828 }],
1829 return_type: None,
1830 body: ClosureBody::Expr(Box::new(body)),
1831 });
1832 }
1833 self.advance();
1834 Ok(Expr::Ident(name))
1835 }
1836 Token::Self_ => {
1837 self.advance();
1838 Ok(Expr::Ident("self".to_string()))
1839 }
1840 Token::LParen => {
1841 if self.is_closure_ahead() {
1842 self.parse_closure()
1843 } else {
1844 self.advance();
1845 let expr = self.parse_expression()?;
1846 self.expect(&Token::RParen)?;
1847 Ok(expr)
1848 }
1849 }
1850 Token::LBracket => {
1851 self.advance();
1852 let mut elements = Vec::new();
1853 if !self.check(&Token::RBracket) {
1854 elements.push(self.parse_expression()?);
1855 while self.match_token(&Token::Comma) {
1856 if self.check(&Token::RBracket) {
1857 break;
1858 }
1859 elements.push(self.parse_expression()?);
1860 }
1861 }
1862 self.expect(&Token::RBracket)?;
1863 Ok(Expr::List(elements))
1864 }
1865 Token::Case => {
1866 self.advance();
1867 self.expect(&Token::LBrace)?;
1868 let mut arms = Vec::new();
1869 while !self.check(&Token::RBrace) && !self.is_at_end() {
1870 let arm = self.parse_case_arm()?;
1871 self.match_token(&Token::Comma); arms.push(arm);
1873 }
1874 self.expect(&Token::RBrace)?;
1875 Ok(Expr::Case { arms })
1876 }
1877 Token::Match => {
1878 self.advance(); let subject = self.parse_expression()?;
1880 self.expect(&Token::LBrace)?;
1881 let mut arms = Vec::new();
1882 while !self.check(&Token::RBrace) && !self.is_at_end() {
1883 let arm = self.parse_match_arm()?;
1884 self.match_token(&Token::Comma); arms.push(arm);
1886 }
1887 self.expect(&Token::RBrace)?;
1888 Ok(Expr::Match {
1889 subject: Box::new(subject),
1890 arms,
1891 })
1892 }
1893 Token::With => {
1894 self.advance(); self.expect(&Token::LBrace)?;
1896 let mut pairs = Vec::new();
1897 while !self.check(&Token::RBrace) && !self.is_at_end() {
1898 let key_name = self.expect_ident()?;
1899 self.expect(&Token::Assign)?;
1900 let value = self.parse_expression()?;
1901 self.match_token(&Token::Comma); pairs.push((Expr::String(key_name), value));
1903 }
1904 self.expect(&Token::RBrace)?;
1905 Ok(Expr::Call {
1906 function: Box::new(Expr::Ident("with".to_string())),
1907 args: vec![Expr::Map(pairs)],
1908 })
1909 }
1910 Token::Emit => {
1911 self.advance();
1913 Ok(Expr::Ident("emit".to_string()))
1914 }
1915 Token::Underscore => {
1916 self.advance();
1917 Ok(Expr::Ident("_".to_string()))
1918 }
1919 _ => Err(TlError::Parser(ParserError {
1920 message: format!("Unexpected token: `{}`", self.peek()),
1921 span: self.peek_span(),
1922 hint: Some("Expected an expression (literal, variable, or function call)".into()),
1923 })),
1924 }
1925 }
1926
1927 fn is_closure_ahead(&self) -> bool {
1931 let mut i = self.pos + 1; let mut depth = 1;
1934 while i < self.tokens.len() {
1935 match &self.tokens[i].token {
1936 Token::LParen => depth += 1,
1937 Token::RParen => {
1938 depth -= 1;
1939 if depth == 0 {
1940 return i + 1 < self.tokens.len()
1942 && matches!(self.tokens[i + 1].token, Token::FatArrow | Token::Arrow);
1943 }
1944 }
1945 _ if i >= self.tokens.len() - 1 => return false, _ => {}
1947 }
1948 i += 1;
1949 }
1950 false
1951 }
1952
1953 fn parse_closure(&mut self) -> Result<Expr, TlError> {
1955 use tl_ast::ClosureBody;
1956 self.expect(&Token::LParen)?;
1957 let params = self.parse_param_list()?;
1958 self.expect(&Token::RParen)?;
1959
1960 if self.match_token(&Token::FatArrow) {
1961 let body = self.parse_expression()?;
1963 Ok(Expr::Closure {
1964 params,
1965 return_type: None,
1966 body: ClosureBody::Expr(Box::new(body)),
1967 })
1968 } else if self.match_token(&Token::Arrow) {
1969 let return_type = self.parse_type()?;
1971 self.expect(&Token::LBrace)?;
1972 let stmts = self.parse_block_body()?;
1973 let (stmts, expr) = self.extract_tail_expr(stmts);
1975 self.expect(&Token::RBrace)?;
1976 Ok(Expr::Closure {
1977 params,
1978 return_type: Some(return_type),
1979 body: ClosureBody::Block { stmts, expr },
1980 })
1981 } else {
1982 Err(TlError::Parser(ParserError {
1983 message: "Expected `=>` or `->` after closure parameters".to_string(),
1984 span: self.peek_span(),
1985 hint: Some("Use `=>` for expression closures or `->` for block closures".into()),
1986 }))
1987 }
1988 }
1989
1990 fn extract_tail_expr(&self, mut stmts: Vec<Stmt>) -> (Vec<Stmt>, Option<Box<Expr>>) {
1992 if let Some(last) = stmts.last()
1993 && let StmtKind::Expr(_) = &last.kind
1994 && let StmtKind::Expr(e) = stmts.pop().unwrap().kind
1995 {
1996 return (stmts, Some(Box::new(e)));
1997 }
1998 (stmts, None)
1999 }
2000
2001 fn parse_arg_list(&mut self) -> Result<Vec<Expr>, TlError> {
2004 let mut args = Vec::new();
2005 if self.check(&Token::RParen) {
2006 return Ok(args);
2007 }
2008 args.push(self.parse_arg()?);
2009 while self.match_token(&Token::Comma) {
2010 if self.check(&Token::RParen) {
2011 break;
2012 }
2013 args.push(self.parse_arg()?);
2014 }
2015 Ok(args)
2016 }
2017
2018 fn parse_arg(&mut self) -> Result<Expr, TlError> {
2019 if let Token::Ident(name) = self.peek().clone() {
2021 let name = name.clone();
2022 if self.pos + 1 < self.tokens.len() && self.tokens[self.pos + 1].token == Token::Colon {
2023 self.advance(); self.advance(); let value = self.parse_expression()?;
2026 return Ok(Expr::NamedArg {
2027 name,
2028 value: Box::new(value),
2029 });
2030 }
2031 }
2032 self.parse_expression()
2033 }
2034
2035 fn parse_param_list(&mut self) -> Result<Vec<Param>, TlError> {
2036 let mut params = Vec::new();
2037 if self.check(&Token::RParen) {
2038 return Ok(params);
2039 }
2040 params.push(self.parse_param()?);
2041 while self.match_token(&Token::Comma) {
2042 if self.check(&Token::RParen) {
2043 break;
2044 }
2045 params.push(self.parse_param()?);
2046 }
2047 Ok(params)
2048 }
2049
2050 fn parse_param(&mut self) -> Result<Param, TlError> {
2051 let name = if self.check(&Token::Self_) {
2052 self.advance();
2053 "self".to_string()
2054 } else {
2055 self.expect_ident()?
2056 };
2057 let type_ann = if self.match_token(&Token::Colon) {
2058 Some(self.parse_type()?)
2059 } else {
2060 None
2061 };
2062 Ok(Param { name, type_ann })
2063 }
2064
2065 fn parse_type(&mut self) -> Result<TypeExpr, TlError> {
2068 let base = if self.check(&Token::Fn) {
2070 self.advance(); self.expect(&Token::LParen)?;
2072 let mut params = Vec::new();
2073 if !self.check(&Token::RParen) {
2074 params.push(self.parse_type()?);
2075 while self.match_token(&Token::Comma) {
2076 if self.check(&Token::RParen) {
2077 break;
2078 }
2079 params.push(self.parse_type()?);
2080 }
2081 }
2082 self.expect(&Token::RParen)?;
2083 let return_type = if self.match_token(&Token::Arrow) {
2084 self.parse_type()?
2085 } else {
2086 TypeExpr::Named("unit".to_string())
2087 };
2088 TypeExpr::Function {
2089 params,
2090 return_type: Box::new(return_type),
2091 }
2092 } else {
2093 let name = self.expect_ident()?;
2094 if self.match_token(&Token::Lt) {
2095 let mut args = Vec::new();
2096 args.push(self.parse_type()?);
2097 while self.match_token(&Token::Comma) {
2098 args.push(self.parse_type()?);
2099 }
2100 self.expect(&Token::Gt)?;
2101 TypeExpr::Generic { name, args }
2102 } else {
2103 TypeExpr::Named(name)
2104 }
2105 };
2106 if self.match_token(&Token::Question) {
2108 Ok(TypeExpr::Optional(Box::new(base)))
2109 } else {
2110 Ok(base)
2111 }
2112 }
2113
2114 fn parse_struct_decl(&mut self) -> Result<Stmt, TlError> {
2118 let start = self.peek_span().start;
2119 self.advance(); let name = self.expect_ident()?;
2121 let type_params = self.parse_optional_type_params()?;
2122 self.expect(&Token::LBrace)?;
2123 let mut fields = Vec::new();
2124 while !self.check(&Token::RBrace) && !self.is_at_end() {
2125 let field_doc = self.consume_doc_comments();
2126 let field_name = self.expect_ident()?;
2127 self.expect(&Token::Colon)?;
2128 let type_ann = self.parse_type()?;
2129 self.match_token(&Token::Comma);
2130 let annotations = parse_field_annotations(field_doc.as_deref());
2131 fields.push(SchemaField {
2132 name: field_name,
2133 type_ann,
2134 doc_comment: field_doc,
2135 default_value: None,
2136 annotations,
2137 });
2138 }
2139 self.expect(&Token::RBrace)?;
2140 let end = self.previous_span().end;
2141 Ok(make_stmt(
2142 StmtKind::StructDecl {
2143 name,
2144 type_params,
2145 fields,
2146 is_public: false,
2147 },
2148 start,
2149 end,
2150 ))
2151 }
2152
2153 fn parse_enum_decl(&mut self) -> Result<Stmt, TlError> {
2155 let start = self.peek_span().start;
2156 self.advance(); let name = self.expect_ident()?;
2158 let type_params = self.parse_optional_type_params()?;
2159 self.expect(&Token::LBrace)?;
2160 let mut variants = Vec::new();
2161 while !self.check(&Token::RBrace) && !self.is_at_end() {
2162 let variant_name = self.expect_ident()?;
2163 let mut fields = Vec::new();
2164 if self.match_token(&Token::LParen) {
2165 if !self.check(&Token::RParen) {
2166 fields.push(self.parse_type()?);
2167 while self.match_token(&Token::Comma) {
2168 if self.check(&Token::RParen) {
2169 break;
2170 }
2171 fields.push(self.parse_type()?);
2172 }
2173 }
2174 self.expect(&Token::RParen)?;
2175 }
2176 self.match_token(&Token::Comma);
2177 variants.push(EnumVariant {
2178 name: variant_name,
2179 fields,
2180 });
2181 }
2182 self.expect(&Token::RBrace)?;
2183 let end = self.previous_span().end;
2184 Ok(make_stmt(
2185 StmtKind::EnumDecl {
2186 name,
2187 type_params,
2188 variants,
2189 is_public: false,
2190 },
2191 start,
2192 end,
2193 ))
2194 }
2195
2196 fn parse_impl(&mut self) -> Result<Stmt, TlError> {
2198 let start = self.peek_span().start;
2199 self.advance(); let impl_type_params = self.parse_optional_type_params()?;
2203
2204 let first_name = self.expect_ident()?;
2205
2206 if self.check(&Token::For) {
2208 self.advance(); let type_name = self.expect_ident()?;
2210 let _type_args = self.parse_optional_type_params()?;
2212
2213 self.expect(&Token::LBrace)?;
2214 let mut methods = Vec::new();
2215 while !self.check(&Token::RBrace) && !self.is_at_end() {
2216 let doc = self.consume_doc_comments();
2217 if self.check(&Token::Fn) {
2218 let mut method = self.parse_fn_decl()?;
2219 method.doc_comment = doc;
2220 methods.push(method);
2221 } else {
2222 return Err(TlError::Parser(ParserError {
2223 message: "Expected `fn` in impl block".to_string(),
2224 span: self.peek_span(),
2225 hint: None,
2226 }));
2227 }
2228 }
2229 self.expect(&Token::RBrace)?;
2230 let end = self.previous_span().end;
2231 return Ok(make_stmt(
2232 StmtKind::TraitImpl {
2233 trait_name: first_name,
2234 type_name,
2235 type_params: impl_type_params,
2236 methods,
2237 },
2238 start,
2239 end,
2240 ));
2241 }
2242
2243 self.expect(&Token::LBrace)?;
2245 let mut methods = Vec::new();
2246 while !self.check(&Token::RBrace) && !self.is_at_end() {
2247 let doc = self.consume_doc_comments();
2248 if self.check(&Token::Fn) {
2249 let mut method = self.parse_fn_decl()?;
2250 method.doc_comment = doc;
2251 methods.push(method);
2252 } else {
2253 return Err(TlError::Parser(ParserError {
2254 message: "Expected `fn` in impl block".to_string(),
2255 span: self.peek_span(),
2256 hint: None,
2257 }));
2258 }
2259 }
2260 self.expect(&Token::RBrace)?;
2261 let end = self.previous_span().end;
2262 Ok(make_stmt(
2263 StmtKind::ImplBlock {
2264 type_name: first_name,
2265 type_params: impl_type_params,
2266 methods,
2267 },
2268 start,
2269 end,
2270 ))
2271 }
2272
2273 fn parse_type_alias(&mut self, is_public: bool) -> Result<Stmt, TlError> {
2276 let start = self.peek_span().start;
2277 self.advance(); let name = self.expect_ident()?;
2279 let type_params = self.parse_optional_type_params()?;
2280 self.expect(&Token::Assign)?;
2281 let value = self.parse_type()?;
2282 let end = self.previous_span().end;
2283 Ok(make_stmt(
2284 StmtKind::TypeAlias {
2285 name,
2286 type_params,
2287 value,
2288 is_public,
2289 },
2290 start,
2291 end,
2292 ))
2293 }
2294
2295 fn parse_trait_def(&mut self) -> Result<Stmt, TlError> {
2296 let start = self.peek_span().start;
2297 self.advance(); let name = self.expect_ident()?;
2299
2300 let type_params = self.parse_optional_type_params()?;
2302
2303 self.expect(&Token::LBrace)?;
2304 let mut methods = Vec::new();
2305 while !self.check(&Token::RBrace) && !self.is_at_end() {
2306 let _doc = self.consume_doc_comments();
2308 if self.check(&Token::Fn) {
2309 self.advance(); let method_name = self.expect_ident()?;
2311 self.expect(&Token::LParen)?;
2312 let params = self.parse_param_list()?;
2313 self.expect(&Token::RParen)?;
2314 let return_type = if self.match_token(&Token::Arrow) {
2315 Some(self.parse_type()?)
2316 } else {
2317 None
2318 };
2319 methods.push(TraitMethod {
2320 name: method_name,
2321 params,
2322 return_type,
2323 });
2324 } else {
2325 return Err(TlError::Parser(ParserError {
2326 message: "Expected `fn` in trait definition".to_string(),
2327 span: self.peek_span(),
2328 hint: None,
2329 }));
2330 }
2331 }
2332 self.expect(&Token::RBrace)?;
2333 let end = self.previous_span().end;
2334 Ok(make_stmt(
2335 StmtKind::TraitDef {
2336 name,
2337 type_params,
2338 methods,
2339 is_public: false,
2340 },
2341 start,
2342 end,
2343 ))
2344 }
2345
2346 fn parse_optional_type_params(&mut self) -> Result<Vec<String>, TlError> {
2348 let (params, _bounds) = self.parse_optional_type_params_with_bounds()?;
2349 Ok(params)
2350 }
2351
2352 fn parse_optional_type_params_with_bounds(
2355 &mut self,
2356 ) -> Result<(Vec<String>, Vec<TraitBound>), TlError> {
2357 if !self.check(&Token::Lt) {
2358 return Ok((vec![], vec![]));
2359 }
2360 self.advance(); let mut params = Vec::new();
2362 let mut bounds = Vec::new();
2363 loop {
2364 let name = self.expect_ident()?;
2365 if self.match_token(&Token::Colon) {
2367 let mut traits = Vec::new();
2368 traits.push(self.expect_ident()?);
2369 while self.match_token(&Token::Plus) {
2370 traits.push(self.expect_ident()?);
2371 }
2372 bounds.push(TraitBound {
2373 type_param: name.clone(),
2374 traits,
2375 });
2376 }
2377 params.push(name);
2378 if !self.match_token(&Token::Comma) {
2379 break;
2380 }
2381 }
2382 self.expect(&Token::Gt)?;
2383 Ok((params, bounds))
2384 }
2385
2386 fn parse_where_clause(&mut self) -> Result<Vec<TraitBound>, TlError> {
2388 let mut bounds = Vec::new();
2389 loop {
2390 let type_param = self.expect_ident()?;
2391 self.expect(&Token::Colon)?;
2392 let mut traits = Vec::new();
2393 traits.push(self.expect_ident()?);
2394 while self.match_token(&Token::Plus) {
2395 traits.push(self.expect_ident()?);
2396 }
2397 bounds.push(TraitBound { type_param, traits });
2398 if !self.match_token(&Token::Comma) {
2399 break;
2400 }
2401 if self.check(&Token::LBrace) {
2403 break;
2404 }
2405 }
2406 Ok(bounds)
2407 }
2408
2409 fn parse_try_catch(&mut self) -> Result<Stmt, TlError> {
2411 let start = self.peek_span().start;
2412 self.advance(); self.expect(&Token::LBrace)?;
2414 let mut try_body = Vec::new();
2415 while !self.check(&Token::RBrace) && !self.is_at_end() {
2416 try_body.push(self.parse_statement()?);
2417 }
2418 self.expect(&Token::RBrace)?;
2419 self.expect(&Token::Catch)?;
2420 let catch_var = self.expect_ident()?;
2421 self.expect(&Token::LBrace)?;
2422 let mut catch_body = Vec::new();
2423 while !self.check(&Token::RBrace) && !self.is_at_end() {
2424 catch_body.push(self.parse_statement()?);
2425 }
2426 self.expect(&Token::RBrace)?;
2427 let end = self.previous_span().end;
2428 Ok(make_stmt(
2429 StmtKind::TryCatch {
2430 try_body,
2431 catch_var,
2432 catch_body,
2433 },
2434 start,
2435 end,
2436 ))
2437 }
2438
2439 fn parse_throw(&mut self) -> Result<Stmt, TlError> {
2441 let start = self.peek_span().start;
2442 self.advance(); let expr = self.parse_expression()?;
2444 let end = self.previous_span().end;
2445 Ok(make_stmt(StmtKind::Throw(expr), start, end))
2446 }
2447
2448 fn parse_import(&mut self) -> Result<Stmt, TlError> {
2450 let start = self.peek_span().start;
2451 self.advance(); let path = match self.peek().clone() {
2453 Token::String(s) => {
2454 self.advance();
2455 s
2456 }
2457 _ => {
2458 return Err(TlError::Parser(ParserError {
2459 message: "Expected string path after `import`".to_string(),
2460 span: self.peek_span(),
2461 hint: None,
2462 }));
2463 }
2464 };
2465 let alias = if self.match_token(&Token::As) {
2466 Some(self.expect_ident()?)
2467 } else {
2468 None
2469 };
2470 let end = self.previous_span().end;
2471 Ok(make_stmt(StmtKind::Import { path, alias }, start, end))
2472 }
2473
2474 fn parse_test(&mut self) -> Result<Stmt, TlError> {
2476 let start = self.peek_span().start;
2477 self.advance(); let name = match self.peek().clone() {
2479 Token::String(s) => {
2480 self.advance();
2481 s
2482 }
2483 _ => {
2484 return Err(TlError::Parser(ParserError {
2485 message: "Expected string after `test`".to_string(),
2486 span: self.peek_span(),
2487 hint: None,
2488 }));
2489 }
2490 };
2491 self.expect(&Token::LBrace)?;
2492 let mut body = Vec::new();
2493 while !self.check(&Token::RBrace) && !self.is_at_end() {
2494 body.push(self.parse_statement()?);
2495 }
2496 self.expect(&Token::RBrace)?;
2497 let end = self.previous_span().end;
2498 Ok(make_stmt(StmtKind::Test { name, body }, start, end))
2499 }
2500}
2501
2502fn token_name(token: &Token) -> &'static str {
2504 match token {
2505 Token::LParen => "(",
2506 Token::RParen => ")",
2507 Token::LBrace => "{",
2508 Token::RBrace => "}",
2509 Token::LBracket => "[",
2510 Token::RBracket => "]",
2511 Token::Comma => ",",
2512 Token::Colon => ":",
2513 Token::Semicolon => ";",
2514 Token::Assign => "=",
2515 Token::Arrow => "->",
2516 Token::FatArrow => "=>",
2517 Token::Pipe => "|>",
2518 Token::Let => "let",
2519 Token::Fn => "fn",
2520 Token::If => "if",
2521 Token::Else => "else",
2522 Token::Return => "return",
2523 Token::In => "in",
2524 Token::Dot => ".",
2525 Token::Lt => "<",
2526 Token::Gt => ">",
2527 _ => "token",
2528 }
2529}
2530
2531pub fn parse(source: &str) -> Result<Program, TlError> {
2533 let tokens = tl_lexer::tokenize(source)?;
2534 let mut parser = Parser::new(tokens);
2535 parser.parse_program()
2536}
2537
2538fn parse_field_annotations(doc: Option<&str>) -> Vec<tl_ast::Annotation> {
2541 let mut annotations = Vec::new();
2542 if let Some(doc) = doc {
2543 if doc.contains("@sensitive") {
2544 annotations.push(tl_ast::Annotation::Sensitive);
2545 }
2546 if doc.contains("@redact") {
2547 annotations.push(tl_ast::Annotation::Redact);
2548 }
2549 if doc.contains("@pii") {
2550 annotations.push(tl_ast::Annotation::Pii);
2551 }
2552 }
2553 annotations
2554}
2555
2556fn body_contains_yield(stmts: &[Stmt]) -> bool {
2557 for stmt in stmts {
2558 if stmt_contains_yield(stmt) {
2559 return true;
2560 }
2561 }
2562 false
2563}
2564
2565fn stmt_contains_yield(stmt: &Stmt) -> bool {
2566 match &stmt.kind {
2567 StmtKind::Expr(e) | StmtKind::Return(Some(e)) | StmtKind::Throw(e) => {
2568 expr_contains_yield(e)
2569 }
2570 StmtKind::Let { value, .. } => expr_contains_yield(value),
2571 StmtKind::If {
2572 condition,
2573 then_body,
2574 else_ifs,
2575 else_body,
2576 } => {
2577 expr_contains_yield(condition)
2578 || body_contains_yield(then_body)
2579 || else_ifs
2580 .iter()
2581 .any(|(c, b)| expr_contains_yield(c) || body_contains_yield(b))
2582 || else_body.as_ref().is_some_and(|b| body_contains_yield(b))
2583 }
2584 StmtKind::While { condition, body } => {
2585 expr_contains_yield(condition) || body_contains_yield(body)
2586 }
2587 StmtKind::For { iter, body, .. } => expr_contains_yield(iter) || body_contains_yield(body),
2588 StmtKind::TryCatch {
2589 try_body,
2590 catch_body,
2591 ..
2592 } => body_contains_yield(try_body) || body_contains_yield(catch_body),
2593 StmtKind::FnDecl { .. } => false,
2595 _ => false,
2596 }
2597}
2598
2599fn expr_contains_yield(expr: &Expr) -> bool {
2600 match expr {
2601 Expr::Yield(_) => true,
2602 Expr::BinOp { left, right, .. } => expr_contains_yield(left) || expr_contains_yield(right),
2603 Expr::UnaryOp { expr, .. } => expr_contains_yield(expr),
2604 Expr::Call { function, args } => {
2605 expr_contains_yield(function) || args.iter().any(expr_contains_yield)
2606 }
2607 Expr::Pipe { left, right } => expr_contains_yield(left) || expr_contains_yield(right),
2608 Expr::Member { object, .. } => expr_contains_yield(object),
2609 Expr::Index { object, index } => expr_contains_yield(object) || expr_contains_yield(index),
2610 Expr::List(items) => items.iter().any(expr_contains_yield),
2611 Expr::Map(pairs) => pairs
2612 .iter()
2613 .any(|(k, v)| expr_contains_yield(k) || expr_contains_yield(v)),
2614 Expr::Block { stmts, expr } => {
2615 body_contains_yield(stmts) || expr.as_ref().is_some_and(|e| expr_contains_yield(e))
2616 }
2617 Expr::Closure { .. } => false, Expr::Assign { target, value } => expr_contains_yield(target) || expr_contains_yield(value),
2619 Expr::NullCoalesce { expr, default } => {
2620 expr_contains_yield(expr) || expr_contains_yield(default)
2621 }
2622 Expr::Range { start, end } => expr_contains_yield(start) || expr_contains_yield(end),
2623 Expr::Await(e) => expr_contains_yield(e),
2624 Expr::NamedArg { value, .. } => expr_contains_yield(value),
2625 Expr::Case { arms } | Expr::Match { arms, .. } => arms.iter().any(|arm| {
2626 (arm.guard.as_ref().is_some_and(expr_contains_yield)) || expr_contains_yield(&arm.body)
2627 }),
2628 Expr::StructInit { fields, .. } => fields.iter().any(|(_, e)| expr_contains_yield(e)),
2629 Expr::EnumVariant { args, .. } => args.iter().any(expr_contains_yield),
2630 _ => false,
2631 }
2632}
2633
2634#[cfg(test)]
2635mod tests {
2636 use super::*;
2637
2638 #[test]
2639 fn test_parse_let() {
2640 let program = parse("let x = 42").unwrap();
2641 assert_eq!(program.statements.len(), 1);
2642 assert!(matches!(&program.statements[0].kind, StmtKind::Let { name, .. } if name == "x"));
2643 }
2644
2645 #[test]
2646 fn test_parse_fn() {
2647 let program = parse("fn add(a: int64, b: int64) -> int64 { a + b }").unwrap();
2648 assert_eq!(program.statements.len(), 1);
2649 assert!(
2650 matches!(&program.statements[0].kind, StmtKind::FnDecl { name, .. } if name == "add")
2651 );
2652 }
2653
2654 #[test]
2655 fn test_parse_pipe() {
2656 let program = parse("let result = x |> double()").unwrap();
2657 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
2658 assert!(matches!(value, Expr::Pipe { .. }));
2659 } else {
2660 panic!("Expected let statement");
2661 }
2662 }
2663
2664 #[test]
2665 fn test_parse_if_else() {
2666 let program = parse("if x > 5 { x } else { 0 }").unwrap();
2667 assert!(matches!(program.statements[0].kind, StmtKind::If { .. }));
2668 }
2669
2670 #[test]
2671 fn test_parse_nested_arithmetic() {
2672 let program = parse("let x = 1 + 2 * 3").unwrap();
2673 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
2675 assert!(matches!(value, Expr::BinOp { op: BinOp::Add, .. }));
2676 }
2677 }
2678
2679 #[test]
2680 fn test_parse_match() {
2681 let program = parse("match x { 1 => \"one\", 2 => \"two\", _ => \"other\" }").unwrap();
2682 assert_eq!(program.statements.len(), 1);
2683 if let StmtKind::Expr(Expr::Match { subject, arms }) = &program.statements[0].kind {
2684 assert!(matches!(subject.as_ref(), Expr::Ident(n) if n == "x"));
2685 assert_eq!(arms.len(), 3);
2686 } else {
2687 panic!("Expected match expression");
2688 }
2689 }
2690
2691 #[test]
2692 fn test_parse_closure() {
2693 let program = parse("let double = (x) => x * 2").unwrap();
2694 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
2695 assert!(matches!(value, Expr::Closure { .. }));
2696 } else {
2697 panic!("Expected let with closure");
2698 }
2699 }
2700
2701 #[test]
2702 fn test_parse_function_call() {
2703 let program = parse("print(42)").unwrap();
2704 if let StmtKind::Expr(Expr::Call { function, args, .. }) = &program.statements[0].kind {
2705 assert!(matches!(function.as_ref(), Expr::Ident(n) if n == "print"));
2706 assert_eq!(args.len(), 1);
2707 } else {
2708 panic!("Expected function call");
2709 }
2710 }
2711
2712 #[test]
2713 fn test_parse_schema() {
2714 let program = parse("schema User { id: int64, name: string, age: float64 }").unwrap();
2715 if let StmtKind::Schema { name, fields, .. } = &program.statements[0].kind {
2716 assert_eq!(name, "User");
2717 assert_eq!(fields.len(), 3);
2718 assert_eq!(fields[0].name, "id");
2719 assert_eq!(fields[1].name, "name");
2720 assert_eq!(fields[2].name, "age");
2721 } else {
2722 panic!("Expected schema statement");
2723 }
2724 }
2725
2726 #[test]
2727 fn test_parse_pipeline_basic() {
2728 let program = parse(
2729 r#"pipeline etl {
2730 extract { let data = read_csv("input.csv") }
2731 transform { let cleaned = data }
2732 load { write_csv(cleaned, "output.csv") }
2733 }"#,
2734 )
2735 .unwrap();
2736 if let StmtKind::Pipeline {
2737 name,
2738 extract,
2739 transform,
2740 load,
2741 ..
2742 } = &program.statements[0].kind
2743 {
2744 assert_eq!(name, "etl");
2745 assert_eq!(extract.len(), 1);
2746 assert_eq!(transform.len(), 1);
2747 assert_eq!(load.len(), 1);
2748 } else {
2749 panic!("Expected pipeline statement");
2750 }
2751 }
2752
2753 #[test]
2754 fn test_parse_pipeline_with_options() {
2755 let program = parse(
2756 r#"pipeline daily_etl {
2757 schedule: "0 0 * * *",
2758 timeout: "30m",
2759 retries: 3,
2760 extract { let data = read_csv("input.csv") }
2761 transform { let cleaned = data }
2762 load { write_csv(cleaned, "output.csv") }
2763 on_failure { println("Pipeline failed!") }
2764 on_success { println("Pipeline succeeded!") }
2765 }"#,
2766 )
2767 .unwrap();
2768 if let StmtKind::Pipeline {
2769 name,
2770 schedule,
2771 timeout,
2772 retries,
2773 on_failure,
2774 on_success,
2775 ..
2776 } = &program.statements[0].kind
2777 {
2778 assert_eq!(name, "daily_etl");
2779 assert_eq!(schedule.as_deref(), Some("0 0 * * *"));
2780 assert_eq!(timeout.as_deref(), Some("30m"));
2781 assert_eq!(*retries, Some(3));
2782 assert!(on_failure.is_some());
2783 assert!(on_success.is_some());
2784 } else {
2785 panic!("Expected pipeline statement");
2786 }
2787 }
2788
2789 #[test]
2790 fn test_parse_stream_decl() {
2791 let program = parse(
2792 r#"stream events {
2793 source: src,
2794 window: tumbling(5m),
2795 transform: { let x = 1 },
2796 sink: out
2797 }"#,
2798 )
2799 .unwrap();
2800 if let StmtKind::StreamDecl {
2801 name,
2802 source,
2803 window,
2804 sink,
2805 ..
2806 } = &program.statements[0].kind
2807 {
2808 assert_eq!(name, "events");
2809 assert!(matches!(source, Expr::Ident(s) if s == "src"));
2810 assert!(matches!(window, Some(WindowSpec::Tumbling(d)) if d == "5m"));
2811 assert!(matches!(sink, Some(Expr::Ident(s)) if s == "out"));
2812 } else {
2813 panic!("Expected stream declaration");
2814 }
2815 }
2816
2817 #[test]
2818 fn test_parse_stream_sliding_window() {
2819 let program = parse(
2820 r#"stream metrics {
2821 source: input,
2822 window: sliding(10m, 1m),
2823 transform: { let x = 1 }
2824 }"#,
2825 )
2826 .unwrap();
2827 if let StmtKind::StreamDecl { window, .. } = &program.statements[0].kind {
2828 assert!(matches!(window, Some(WindowSpec::Sliding(w, s)) if w == "10m" && s == "1m"));
2829 } else {
2830 panic!("Expected stream declaration");
2831 }
2832 }
2833
2834 #[test]
2835 fn test_parse_stream_session_window() {
2836 let program = parse(
2837 r#"stream sessions {
2838 source: clicks,
2839 window: session(30m),
2840 transform: { let x = 1 }
2841 }"#,
2842 )
2843 .unwrap();
2844 if let StmtKind::StreamDecl { window, .. } = &program.statements[0].kind {
2845 assert!(matches!(window, Some(WindowSpec::Session(d)) if d == "30m"));
2846 } else {
2847 panic!("Expected stream declaration");
2848 }
2849 }
2850
2851 #[test]
2852 fn test_parse_source_decl() {
2853 let program = parse(
2854 r#"source kafka_in = connector kafka {
2855 topic: "events",
2856 group: "my_group"
2857 }"#,
2858 )
2859 .unwrap();
2860 if let StmtKind::SourceDecl {
2861 name,
2862 connector_type,
2863 config,
2864 } = &program.statements[0].kind
2865 {
2866 assert_eq!(name, "kafka_in");
2867 assert_eq!(connector_type, "kafka");
2868 assert_eq!(config.len(), 2);
2869 assert_eq!(config[0].0, "topic");
2870 assert_eq!(config[1].0, "group");
2871 } else {
2872 panic!("Expected source declaration");
2873 }
2874 }
2875
2876 #[test]
2877 fn test_parse_sink_decl() {
2878 let program = parse(
2879 r#"sink output = connector channel {
2880 buffer: 100
2881 }"#,
2882 )
2883 .unwrap();
2884 if let StmtKind::SinkDecl {
2885 name,
2886 connector_type,
2887 config,
2888 } = &program.statements[0].kind
2889 {
2890 assert_eq!(name, "output");
2891 assert_eq!(connector_type, "channel");
2892 assert_eq!(config.len(), 1);
2893 assert_eq!(config[0].0, "buffer");
2894 } else {
2895 panic!("Expected sink declaration");
2896 }
2897 }
2898
2899 #[test]
2900 fn test_parse_pipeline_with_duration_tokens() {
2901 let program = parse(
2902 r#"pipeline fast {
2903 timeout: 30s,
2904 extract { let x = 1 }
2905 transform { let y = x }
2906 load { println(y) }
2907 }"#,
2908 )
2909 .unwrap();
2910 if let StmtKind::Pipeline { timeout, .. } = &program.statements[0].kind {
2911 assert_eq!(timeout.as_deref(), Some("30s"));
2912 } else {
2913 panic!("Expected pipeline statement");
2914 }
2915 }
2916
2917 #[test]
2918 fn test_parse_stream_with_watermark() {
2919 let program = parse(
2920 r#"stream delayed {
2921 source: input,
2922 watermark: 10s,
2923 transform: { let x = 1 }
2924 }"#,
2925 )
2926 .unwrap();
2927 if let StmtKind::StreamDecl { watermark, .. } = &program.statements[0].kind {
2928 assert_eq!(watermark.as_deref(), Some("10s"));
2929 } else {
2930 panic!("Expected stream declaration");
2931 }
2932 }
2933
2934 #[test]
2935 fn test_parse_with_block() {
2936 let program = parse("with { doubled = age * 2, name = first }").unwrap();
2937 if let StmtKind::Expr(Expr::Call { function, args }) = &program.statements[0].kind {
2938 assert!(matches!(function.as_ref(), Expr::Ident(n) if n == "with"));
2939 assert_eq!(args.len(), 1);
2940 if let Expr::Map(pairs) = &args[0] {
2941 assert_eq!(pairs.len(), 2);
2942 } else {
2943 panic!("Expected Map arg");
2944 }
2945 } else {
2946 panic!("Expected with call expression");
2947 }
2948 }
2949
2950 #[test]
2951 fn test_parse_struct_decl() {
2952 let program = parse("struct Point { x: float64, y: float64 }").unwrap();
2953 if let StmtKind::StructDecl { name, fields, .. } = &program.statements[0].kind {
2954 assert_eq!(name, "Point");
2955 assert_eq!(fields.len(), 2);
2956 assert_eq!(fields[0].name, "x");
2957 assert!(matches!(&fields[0].type_ann, TypeExpr::Named(t) if t == "float64"));
2958 assert_eq!(fields[1].name, "y");
2959 assert!(matches!(&fields[1].type_ann, TypeExpr::Named(t) if t == "float64"));
2960 } else {
2961 panic!("Expected struct declaration");
2962 }
2963 }
2964
2965 #[test]
2966 fn test_parse_struct_init() {
2967 let program = parse("let p = Point { x: 1.0, y: 2.0 }").unwrap();
2968 if let StmtKind::Let { name, value, .. } = &program.statements[0].kind {
2969 assert_eq!(name, "p");
2970 if let Expr::StructInit {
2971 name: struct_name,
2972 fields,
2973 } = value
2974 {
2975 assert_eq!(struct_name, "Point");
2976 assert_eq!(fields.len(), 2);
2977 assert_eq!(fields[0].0, "x");
2978 assert!(matches!(&fields[0].1, Expr::Float(v) if *v == 1.0));
2979 assert_eq!(fields[1].0, "y");
2980 assert!(matches!(&fields[1].1, Expr::Float(v) if *v == 2.0));
2981 } else {
2982 panic!("Expected StructInit expression");
2983 }
2984 } else {
2985 panic!("Expected let statement");
2986 }
2987 }
2988
2989 #[test]
2990 fn test_parse_enum_decl() {
2991 let program = parse("enum Color { Red, Green, Blue }").unwrap();
2992 if let StmtKind::EnumDecl { name, variants, .. } = &program.statements[0].kind {
2993 assert_eq!(name, "Color");
2994 assert_eq!(variants.len(), 3);
2995 assert_eq!(variants[0].name, "Red");
2996 assert!(variants[0].fields.is_empty());
2997 assert_eq!(variants[1].name, "Green");
2998 assert!(variants[1].fields.is_empty());
2999 assert_eq!(variants[2].name, "Blue");
3000 assert!(variants[2].fields.is_empty());
3001 } else {
3002 panic!("Expected enum declaration");
3003 }
3004 }
3005
3006 #[test]
3007 fn test_parse_enum_variant() {
3008 let program = parse("Color::Red").unwrap();
3010 if let StmtKind::Expr(Expr::EnumVariant {
3011 enum_name,
3012 variant,
3013 args,
3014 }) = &program.statements[0].kind
3015 {
3016 assert_eq!(enum_name, "Color");
3017 assert_eq!(variant, "Red");
3018 assert!(args.is_empty());
3019 } else {
3020 panic!("Expected enum variant expression");
3021 }
3022
3023 let program = parse("Color::Custom(1, 2, 3)").unwrap();
3025 if let StmtKind::Expr(Expr::EnumVariant {
3026 enum_name,
3027 variant,
3028 args,
3029 }) = &program.statements[0].kind
3030 {
3031 assert_eq!(enum_name, "Color");
3032 assert_eq!(variant, "Custom");
3033 assert_eq!(args.len(), 3);
3034 assert!(matches!(&args[0], Expr::Int(1)));
3035 assert!(matches!(&args[1], Expr::Int(2)));
3036 assert!(matches!(&args[2], Expr::Int(3)));
3037 } else {
3038 panic!("Expected enum variant expression with args");
3039 }
3040 }
3041
3042 #[test]
3043 fn test_parse_impl_block() {
3044 let program = parse("impl Point { fn area(self) { self.x * self.y } }").unwrap();
3045 if let StmtKind::ImplBlock {
3046 type_name, methods, ..
3047 } = &program.statements[0].kind
3048 {
3049 assert_eq!(type_name, "Point");
3050 assert_eq!(methods.len(), 1);
3051 if let StmtKind::FnDecl {
3052 name, params, body, ..
3053 } = &methods[0].kind
3054 {
3055 assert_eq!(name, "area");
3056 assert_eq!(params.len(), 1);
3057 assert_eq!(params[0].name, "self");
3058 assert_eq!(body.len(), 1);
3059 } else {
3060 panic!("Expected fn declaration inside impl block");
3061 }
3062 } else {
3063 panic!("Expected impl block");
3064 }
3065 }
3066
3067 #[test]
3068 fn test_parse_try_catch() {
3069 let program = parse("try { 1 + 2 } catch e { println(e) }").unwrap();
3070 if let StmtKind::TryCatch {
3071 try_body,
3072 catch_var,
3073 catch_body,
3074 } = &program.statements[0].kind
3075 {
3076 assert_eq!(try_body.len(), 1);
3077 assert_eq!(catch_var, "e");
3078 assert_eq!(catch_body.len(), 1);
3079 if let StmtKind::Expr(Expr::BinOp { op, .. }) = &try_body[0].kind {
3081 assert_eq!(*op, BinOp::Add);
3082 } else {
3083 panic!("Expected binary op in try body");
3084 }
3085 if let StmtKind::Expr(Expr::Call { function, args }) = &catch_body[0].kind {
3087 assert!(matches!(function.as_ref(), Expr::Ident(n) if n == "println"));
3088 assert_eq!(args.len(), 1);
3089 } else {
3090 panic!("Expected function call in catch body");
3091 }
3092 } else {
3093 panic!("Expected try/catch statement");
3094 }
3095 }
3096
3097 #[test]
3098 fn test_parse_throw() {
3099 let program = parse(r#"throw "error""#).unwrap();
3100 if let StmtKind::Throw(expr) = &program.statements[0].kind {
3101 assert!(matches!(expr, Expr::String(s) if s == "error"));
3102 } else {
3103 panic!("Expected throw statement");
3104 }
3105 }
3106
3107 #[test]
3108 fn test_parse_import() {
3109 let program = parse(r#"import "utils.tl""#).unwrap();
3111 if let StmtKind::Import { path, alias } = &program.statements[0].kind {
3112 assert_eq!(path, "utils.tl");
3113 assert!(alias.is_none());
3114 } else {
3115 panic!("Expected import statement");
3116 }
3117
3118 let program = parse(r#"import "math.tl" as math"#).unwrap();
3120 if let StmtKind::Import { path, alias } = &program.statements[0].kind {
3121 assert_eq!(path, "math.tl");
3122 assert_eq!(alias.as_deref(), Some("math"));
3123 } else {
3124 panic!("Expected import statement with alias");
3125 }
3126 }
3127
3128 #[test]
3129 fn test_parse_test() {
3130 let program = parse(r#"test "my test" { assert(true) }"#).unwrap();
3131 if let StmtKind::Test { name, body } = &program.statements[0].kind {
3132 assert_eq!(name, "my test");
3133 assert_eq!(body.len(), 1);
3134 if let StmtKind::Expr(Expr::Call { function, args }) = &body[0].kind {
3135 assert!(matches!(function.as_ref(), Expr::Ident(n) if n == "assert"));
3136 assert_eq!(args.len(), 1);
3137 assert!(matches!(&args[0], Expr::Bool(true)));
3138 } else {
3139 panic!("Expected function call in test body");
3140 }
3141 } else {
3142 panic!("Expected test statement");
3143 }
3144 }
3145
3146 #[test]
3147 fn test_parse_method_call() {
3148 let program = parse(r#""hello".split(" ")"#).unwrap();
3149 if let StmtKind::Expr(Expr::Call { function, args }) = &program.statements[0].kind {
3150 if let Expr::Member { object, field } = function.as_ref() {
3152 assert!(matches!(object.as_ref(), Expr::String(s) if s == "hello"));
3153 assert_eq!(field, "split");
3154 } else {
3155 panic!("Expected member access as call function");
3156 }
3157 assert_eq!(args.len(), 1);
3158 assert!(matches!(&args[0], Expr::String(s) if s == " "));
3159 } else {
3160 panic!("Expected method call expression");
3161 }
3162 }
3163
3164 #[test]
3167 fn test_parse_await_expr() {
3168 let program = parse("await x").unwrap();
3169 if let StmtKind::Expr(Expr::Await(inner)) = &program.statements[0].kind {
3170 assert!(matches!(inner.as_ref(), Expr::Ident(s) if s == "x"));
3171 } else {
3172 panic!("Expected Await expression, got {:?}", program.statements[0]);
3173 }
3174 }
3175
3176 #[test]
3177 fn test_parse_await_spawn() {
3178 let program = parse("await spawn(f)").unwrap();
3179 if let StmtKind::Expr(Expr::Await(inner)) = &program.statements[0].kind {
3180 assert!(matches!(inner.as_ref(), Expr::Call { .. }));
3181 } else {
3182 panic!("Expected Await(Call(...))");
3183 }
3184 }
3185
3186 #[test]
3187 fn test_parse_yield_expr() {
3188 let program = parse("yield 42").unwrap();
3189 if let StmtKind::Expr(Expr::Yield(Some(inner))) = &program.statements[0].kind {
3190 assert!(matches!(inner.as_ref(), Expr::Int(42)));
3191 } else {
3192 panic!("Expected Yield(Some(Int(42)))");
3193 }
3194 }
3195
3196 #[test]
3197 fn test_parse_bare_yield() {
3198 let program = parse("fn gen() { yield }").unwrap();
3199 if let StmtKind::FnDecl {
3200 body, is_generator, ..
3201 } = &program.statements[0].kind
3202 {
3203 assert!(*is_generator);
3204 if let StmtKind::Expr(Expr::Yield(None)) = &body[0].kind {
3205 } else {
3207 panic!("Expected bare Yield(None), got {:?}", body[0]);
3208 }
3209 } else {
3210 panic!("Expected FnDecl");
3211 }
3212 }
3213
3214 #[test]
3215 fn test_parse_generator_fn() {
3216 let program = parse("fn gen() { yield 1\nyield 2 }").unwrap();
3217 if let StmtKind::FnDecl {
3218 name,
3219 is_generator,
3220 body,
3221 ..
3222 } = &program.statements[0].kind
3223 {
3224 assert_eq!(name, "gen");
3225 assert!(*is_generator);
3226 assert_eq!(body.len(), 2);
3227 } else {
3228 panic!("Expected FnDecl");
3229 }
3230 }
3231
3232 #[test]
3233 fn test_parse_non_generator_fn() {
3234 let program = parse("fn add(a, b) { return a }").unwrap();
3235 if let StmtKind::FnDecl { is_generator, .. } = &program.statements[0].kind {
3236 assert!(!*is_generator);
3237 } else {
3238 panic!("Expected FnDecl");
3239 }
3240 }
3241
3242 #[test]
3245 fn test_parse_pub_fn() {
3246 let program = parse("pub fn foo() { 1 }").unwrap();
3247 if let StmtKind::FnDecl {
3248 name, is_public, ..
3249 } = &program.statements[0].kind
3250 {
3251 assert_eq!(name, "foo");
3252 assert!(*is_public);
3253 } else {
3254 panic!("Expected pub FnDecl");
3255 }
3256 }
3257
3258 #[test]
3259 fn test_parse_pub_struct() {
3260 let program = parse("pub struct Foo { x: int }").unwrap();
3261 if let StmtKind::StructDecl {
3262 name, is_public, ..
3263 } = &program.statements[0].kind
3264 {
3265 assert_eq!(name, "Foo");
3266 assert!(*is_public);
3267 } else {
3268 panic!("Expected pub StructDecl");
3269 }
3270 }
3271
3272 #[test]
3273 fn test_parse_use_single() {
3274 let program = parse("use data.transforms.clean").unwrap();
3275 if let StmtKind::Use { item, is_public } = &program.statements[0].kind {
3276 assert!(!*is_public);
3277 if let UseItem::Single(path) = item {
3278 assert_eq!(path, &["data", "transforms", "clean"]);
3279 } else {
3280 panic!("Expected UseItem::Single");
3281 }
3282 } else {
3283 panic!("Expected Use statement");
3284 }
3285 }
3286
3287 #[test]
3288 fn test_parse_use_group() {
3289 let program = parse("use data.transforms.{a, b}").unwrap();
3290 if let StmtKind::Use { item, .. } = &program.statements[0].kind {
3291 if let UseItem::Group(prefix, names) = item {
3292 assert_eq!(prefix, &["data", "transforms"]);
3293 assert_eq!(names, &["a", "b"]);
3294 } else {
3295 panic!("Expected UseItem::Group");
3296 }
3297 } else {
3298 panic!("Expected Use statement");
3299 }
3300 }
3301
3302 #[test]
3303 fn test_parse_use_wildcard() {
3304 let program = parse("use data.transforms.*").unwrap();
3305 if let StmtKind::Use { item, .. } = &program.statements[0].kind {
3306 if let UseItem::Wildcard(path) = item {
3307 assert_eq!(path, &["data", "transforms"]);
3308 } else {
3309 panic!("Expected UseItem::Wildcard");
3310 }
3311 } else {
3312 panic!("Expected Use statement");
3313 }
3314 }
3315
3316 #[test]
3317 fn test_parse_use_aliased() {
3318 let program = parse("use data.postgres as pg").unwrap();
3319 if let StmtKind::Use { item, .. } = &program.statements[0].kind {
3320 if let UseItem::Aliased(path, alias) = item {
3321 assert_eq!(path, &["data", "postgres"]);
3322 assert_eq!(alias, "pg");
3323 } else {
3324 panic!("Expected UseItem::Aliased");
3325 }
3326 } else {
3327 panic!("Expected Use statement");
3328 }
3329 }
3330
3331 #[test]
3332 fn test_parse_pub_use() {
3333 let program = parse("pub use data.clean").unwrap();
3334 if let StmtKind::Use { item, is_public } = &program.statements[0].kind {
3335 assert!(*is_public);
3336 assert!(matches!(item, UseItem::Single(p) if p == &["data", "clean"]));
3337 } else {
3338 panic!("Expected pub Use statement");
3339 }
3340 }
3341
3342 #[test]
3343 fn test_parse_pub_mod() {
3344 let program = parse("pub mod transforms").unwrap();
3345 if let StmtKind::ModDecl { name, is_public } = &program.statements[0].kind {
3346 assert_eq!(name, "transforms");
3347 assert!(*is_public);
3348 } else {
3349 panic!("Expected pub ModDecl");
3350 }
3351 }
3352
3353 #[test]
3354 fn test_parse_mod() {
3355 let program = parse("mod quality").unwrap();
3356 if let StmtKind::ModDecl { name, is_public } = &program.statements[0].kind {
3357 assert_eq!(name, "quality");
3358 assert!(!*is_public);
3359 } else {
3360 panic!("Expected ModDecl");
3361 }
3362 }
3363
3364 #[test]
3365 fn test_fn_default_not_public() {
3366 let program = parse("fn foo() { 1 }").unwrap();
3367 if let StmtKind::FnDecl { is_public, .. } = &program.statements[0].kind {
3368 assert!(!*is_public);
3369 } else {
3370 panic!("Expected FnDecl");
3371 }
3372 }
3373
3374 #[test]
3377 fn test_generic_fn() {
3378 let program = parse("fn identity<T>(x: T) -> T { x }").unwrap();
3379 if let StmtKind::FnDecl {
3380 name,
3381 type_params,
3382 params,
3383 return_type,
3384 ..
3385 } = &program.statements[0].kind
3386 {
3387 assert_eq!(name, "identity");
3388 assert_eq!(type_params, &vec!["T".to_string()]);
3389 assert_eq!(params.len(), 1);
3390 assert!(return_type.is_some());
3391 } else {
3392 panic!("Expected FnDecl");
3393 }
3394 }
3395
3396 #[test]
3397 fn test_generic_struct() {
3398 let program = parse("struct Pair<A, B> { first: A, second: B }").unwrap();
3399 if let StmtKind::StructDecl {
3400 name,
3401 type_params,
3402 fields,
3403 ..
3404 } = &program.statements[0].kind
3405 {
3406 assert_eq!(name, "Pair");
3407 assert_eq!(type_params, &vec!["A".to_string(), "B".to_string()]);
3408 assert_eq!(fields.len(), 2);
3409 } else {
3410 panic!("Expected StructDecl");
3411 }
3412 }
3413
3414 #[test]
3415 fn test_generic_enum() {
3416 let program = parse("enum MyOption<T> { Some(T), Nothing }").unwrap();
3417 if let StmtKind::EnumDecl {
3418 name,
3419 type_params,
3420 variants,
3421 ..
3422 } = &program.statements[0].kind
3423 {
3424 assert_eq!(name, "MyOption");
3425 assert_eq!(type_params, &vec!["T".to_string()]);
3426 assert_eq!(variants.len(), 2);
3427 assert_eq!(variants[0].name, "Some");
3428 assert_eq!(variants[1].name, "Nothing");
3429 } else {
3430 panic!("Expected EnumDecl");
3431 }
3432 }
3433
3434 #[test]
3435 fn test_inline_trait_bound() {
3436 let program = parse("fn foo<T: Comparable>(x: T) { x }").unwrap();
3437 if let StmtKind::FnDecl {
3438 type_params,
3439 bounds,
3440 ..
3441 } = &program.statements[0].kind
3442 {
3443 assert_eq!(type_params, &vec!["T".to_string()]);
3444 assert_eq!(bounds.len(), 1);
3445 assert_eq!(bounds[0].type_param, "T");
3446 assert_eq!(bounds[0].traits, vec!["Comparable".to_string()]);
3447 } else {
3448 panic!("Expected FnDecl");
3449 }
3450 }
3451
3452 #[test]
3453 fn test_where_clause() {
3454 let program = parse("fn foo<T>(x: T) where T: Comparable + Hashable { x }").unwrap();
3455 if let StmtKind::FnDecl {
3456 type_params,
3457 bounds,
3458 ..
3459 } = &program.statements[0].kind
3460 {
3461 assert_eq!(type_params, &vec!["T".to_string()]);
3462 assert_eq!(bounds.len(), 1);
3463 assert_eq!(bounds[0].type_param, "T");
3464 assert_eq!(
3465 bounds[0].traits,
3466 vec!["Comparable".to_string(), "Hashable".to_string()]
3467 );
3468 } else {
3469 panic!("Expected FnDecl");
3470 }
3471 }
3472
3473 #[test]
3474 fn test_trait_def() {
3475 let program = parse("trait Display { fn show(self) -> string }").unwrap();
3476 if let StmtKind::TraitDef {
3477 name,
3478 type_params,
3479 methods,
3480 is_public,
3481 } = &program.statements[0].kind
3482 {
3483 assert_eq!(name, "Display");
3484 assert!(type_params.is_empty());
3485 assert_eq!(methods.len(), 1);
3486 assert_eq!(methods[0].name, "show");
3487 assert!(!*is_public);
3488 } else {
3489 panic!("Expected TraitDef");
3490 }
3491 }
3492
3493 #[test]
3494 fn test_trait_impl() {
3495 let program =
3496 parse("impl Display for Point { fn show(self) -> string { \"point\" } }").unwrap();
3497 if let StmtKind::TraitImpl {
3498 trait_name,
3499 type_name,
3500 methods,
3501 ..
3502 } = &program.statements[0].kind
3503 {
3504 assert_eq!(trait_name, "Display");
3505 assert_eq!(type_name, "Point");
3506 assert_eq!(methods.len(), 1);
3507 } else {
3508 panic!("Expected TraitImpl");
3509 }
3510 }
3511
3512 #[test]
3513 fn test_generic_trait_impl() {
3514 let program =
3515 parse("impl<T> Display for Box<T> { fn show(self) -> string { \"box\" } }").unwrap();
3516 if let StmtKind::TraitImpl {
3517 trait_name,
3518 type_name,
3519 type_params,
3520 methods,
3521 } = &program.statements[0].kind
3522 {
3523 assert_eq!(trait_name, "Display");
3524 assert_eq!(type_name, "Box");
3525 assert_eq!(type_params, &vec!["T".to_string()]);
3526 assert_eq!(methods.len(), 1);
3527 } else {
3528 panic!("Expected TraitImpl");
3529 }
3530 }
3531
3532 #[test]
3533 fn test_pub_trait() {
3534 let program = parse("pub trait Serializable { fn serialize(self) -> string }").unwrap();
3535 if let StmtKind::TraitDef {
3536 name, is_public, ..
3537 } = &program.statements[0].kind
3538 {
3539 assert_eq!(name, "Serializable");
3540 assert!(*is_public);
3541 } else {
3542 panic!("Expected TraitDef");
3543 }
3544 }
3545
3546 #[test]
3547 fn test_multiple_type_params() {
3548 let program = parse("fn zip<A, B>(a: list<A>, b: list<B>) { a }").unwrap();
3549 if let StmtKind::FnDecl { type_params, .. } = &program.statements[0].kind {
3550 assert_eq!(type_params, &vec!["A".to_string(), "B".to_string()]);
3551 } else {
3552 panic!("Expected FnDecl");
3553 }
3554 }
3555
3556 #[test]
3557 fn test_existing_code_no_type_params() {
3558 let program = parse("fn add(a, b) { a + b }").unwrap();
3560 if let StmtKind::FnDecl {
3561 type_params,
3562 bounds,
3563 ..
3564 } = &program.statements[0].kind
3565 {
3566 assert!(type_params.is_empty());
3567 assert!(bounds.is_empty());
3568 } else {
3569 panic!("Expected FnDecl");
3570 }
3571 }
3572
3573 #[test]
3574 fn test_trait_with_multiple_methods() {
3575 let program =
3576 parse("trait Container { fn len(self) -> int fn is_empty(self) -> bool }").unwrap();
3577 if let StmtKind::TraitDef { name, methods, .. } = &program.statements[0].kind {
3578 assert_eq!(name, "Container");
3579 assert_eq!(methods.len(), 2);
3580 assert_eq!(methods[0].name, "len");
3581 assert_eq!(methods[1].name, "is_empty");
3582 } else {
3583 panic!("Expected TraitDef");
3584 }
3585 }
3586
3587 #[test]
3588 fn test_generic_impl_block() {
3589 let program = parse("impl<T> Box { fn get(self) -> T { self.val } }").unwrap();
3590 if let StmtKind::ImplBlock {
3591 type_name,
3592 type_params,
3593 ..
3594 } = &program.statements[0].kind
3595 {
3596 assert_eq!(type_name, "Box");
3597 assert_eq!(type_params, &vec!["T".to_string()]);
3598 } else {
3599 panic!("Expected ImplBlock");
3600 }
3601 }
3602
3603 #[test]
3606 fn test_parse_match_wildcard() {
3607 let program = parse("match x { _ => 1 }").unwrap();
3608 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3609 assert!(matches!(arms[0].pattern, Pattern::Wildcard));
3610 } else {
3611 panic!("Expected match expression");
3612 }
3613 }
3614
3615 #[test]
3616 fn test_parse_match_literal() {
3617 let program = parse("match x { 1 => \"one\", 2 => \"two\", _ => \"other\" }").unwrap();
3618 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3619 assert_eq!(arms.len(), 3);
3620 assert!(matches!(arms[0].pattern, Pattern::Literal(Expr::Int(1))));
3621 assert!(matches!(arms[1].pattern, Pattern::Literal(Expr::Int(2))));
3622 assert!(matches!(arms[2].pattern, Pattern::Wildcard));
3623 } else {
3624 panic!("Expected match expression");
3625 }
3626 }
3627
3628 #[test]
3629 fn test_parse_match_binding() {
3630 let program = parse("match x { val => val + 1 }").unwrap();
3631 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3632 if let Pattern::Binding(name) = &arms[0].pattern {
3633 assert_eq!(name, "val");
3634 } else {
3635 panic!("Expected binding pattern");
3636 }
3637 } else {
3638 panic!("Expected match expression");
3639 }
3640 }
3641
3642 #[test]
3643 fn test_parse_match_enum_variant() {
3644 let program = parse("match x { Color::Red => 1, Color::Blue => 2 }").unwrap();
3645 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3646 if let Pattern::Enum {
3647 type_name,
3648 variant,
3649 args,
3650 } = &arms[0].pattern
3651 {
3652 assert_eq!(type_name, "Color");
3653 assert_eq!(variant, "Red");
3654 assert!(args.is_empty());
3655 } else {
3656 panic!("Expected enum pattern");
3657 }
3658 } else {
3659 panic!("Expected match expression");
3660 }
3661 }
3662
3663 #[test]
3664 fn test_parse_match_enum_with_args() {
3665 let program =
3666 parse("match x { Shape::Circle(r) => r, Shape::Rect(w, h) => w * h }").unwrap();
3667 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3668 if let Pattern::Enum { variant, args, .. } = &arms[0].pattern {
3669 assert_eq!(variant, "Circle");
3670 assert_eq!(args.len(), 1);
3671 assert!(matches!(args[0], Pattern::Binding(_)));
3672 } else {
3673 panic!("Expected enum pattern with args");
3674 }
3675 } else {
3676 panic!("Expected match expression");
3677 }
3678 }
3679
3680 #[test]
3681 fn test_parse_match_guard() {
3682 let program = parse("match x { n if n > 0 => \"pos\", _ => \"other\" }").unwrap();
3683 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3684 assert!(arms[0].guard.is_some());
3685 assert!(matches!(arms[0].pattern, Pattern::Binding(_)));
3686 assert!(arms[1].guard.is_none());
3687 } else {
3688 panic!("Expected match expression");
3689 }
3690 }
3691
3692 #[test]
3693 fn test_parse_match_or_pattern() {
3694 let program = parse("match x { 1 or 2 or 3 => \"small\", _ => \"big\" }").unwrap();
3695 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3696 if let Pattern::Or(pats) = &arms[0].pattern {
3697 assert_eq!(pats.len(), 3);
3698 } else {
3699 panic!("Expected OR pattern");
3700 }
3701 } else {
3702 panic!("Expected match expression");
3703 }
3704 }
3705
3706 #[test]
3707 fn test_parse_list_pattern() {
3708 let program = parse("match x { [a, b] => a + b, _ => 0 }").unwrap();
3709 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3710 if let Pattern::List { elements, rest } = &arms[0].pattern {
3711 assert_eq!(elements.len(), 2);
3712 assert!(rest.is_none());
3713 } else {
3714 panic!("Expected list pattern");
3715 }
3716 } else {
3717 panic!("Expected match expression");
3718 }
3719 }
3720
3721 #[test]
3722 fn test_parse_list_rest_pattern() {
3723 let program = parse("match x { [head, ...tail] => head, _ => 0 }").unwrap();
3724 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3725 if let Pattern::List { elements, rest } = &arms[0].pattern {
3726 assert_eq!(elements.len(), 1);
3727 assert_eq!(rest.as_deref(), Some("tail"));
3728 } else {
3729 panic!("Expected list pattern with rest");
3730 }
3731 } else {
3732 panic!("Expected match expression");
3733 }
3734 }
3735
3736 #[test]
3737 fn test_parse_struct_pattern() {
3738 let program = parse("match p { Point { x, y } => x + y, _ => 0 }").unwrap();
3739 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3740 if let Pattern::Struct { name, fields } = &arms[0].pattern {
3741 assert_eq!(name.as_deref(), Some("Point"));
3742 assert_eq!(fields.len(), 2);
3743 assert_eq!(fields[0].name, "x");
3744 assert_eq!(fields[1].name, "y");
3745 } else {
3746 panic!("Expected struct pattern");
3747 }
3748 } else {
3749 panic!("Expected match expression");
3750 }
3751 }
3752
3753 #[test]
3754 fn test_parse_negative_literal_pattern() {
3755 let program = parse("match x { -5 => \"neg five\", _ => \"other\" }").unwrap();
3756 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3757 if let Pattern::Literal(Expr::Int(-5)) = &arms[0].pattern {
3758 } else {
3760 panic!(
3761 "Expected negative literal pattern, got {:?}",
3762 arms[0].pattern
3763 );
3764 }
3765 } else {
3766 panic!("Expected match expression");
3767 }
3768 }
3769
3770 #[test]
3771 fn test_parse_let_destructure_list() {
3772 let program = parse("let [a, b, c] = [1, 2, 3]").unwrap();
3773 if let StmtKind::LetDestructure { pattern, .. } = &program.statements[0].kind {
3774 if let Pattern::List { elements, rest } = pattern {
3775 assert_eq!(elements.len(), 3);
3776 assert!(rest.is_none());
3777 } else {
3778 panic!("Expected list pattern");
3779 }
3780 } else {
3781 panic!("Expected LetDestructure");
3782 }
3783 }
3784
3785 #[test]
3786 fn test_parse_let_destructure_struct() {
3787 let program = parse("let { x, y } = point").unwrap();
3788 if let StmtKind::LetDestructure { pattern, .. } = &program.statements[0].kind {
3789 if let Pattern::Struct { name, fields } = pattern {
3790 assert!(name.is_none());
3791 assert_eq!(fields.len(), 2);
3792 } else {
3793 panic!("Expected struct pattern");
3794 }
3795 } else {
3796 panic!("Expected LetDestructure");
3797 }
3798 }
3799
3800 #[test]
3801 fn test_parse_case_with_match_arm() {
3802 let program = parse("case { x > 10 => \"big\", _ => \"small\" }").unwrap();
3803 if let StmtKind::Expr(Expr::Case { arms }) = &program.statements[0].kind {
3804 assert_eq!(arms.len(), 2);
3805 assert!(matches!(arms[0].pattern, Pattern::Wildcard));
3807 assert!(arms[0].guard.is_some());
3808 assert!(matches!(arms[1].pattern, Pattern::Wildcard));
3810 assert!(arms[1].guard.is_none());
3811 } else {
3812 panic!("Expected case expression");
3813 }
3814 }
3815
3816 #[test]
3817 fn test_parse_backward_compat_match() {
3818 let program = parse("match x { 1 => \"one\", 2 => \"two\", _ => \"other\" }").unwrap();
3820 if let StmtKind::Expr(Expr::Match { arms, .. }) = &program.statements[0].kind {
3821 assert_eq!(arms.len(), 3);
3822 } else {
3823 panic!("Expected match expression");
3824 }
3825 }
3826
3827 #[test]
3830 fn test_parse_expr_closure_still_works() {
3831 let program = parse("let f = (x) => x * 2").unwrap();
3832 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
3833 if let Expr::Closure {
3834 params,
3835 body,
3836 return_type,
3837 } = value
3838 {
3839 assert_eq!(params.len(), 1);
3840 assert_eq!(params[0].name, "x");
3841 assert!(return_type.is_none());
3842 assert!(matches!(body, ClosureBody::Expr(_)));
3843 } else {
3844 panic!("Expected closure");
3845 }
3846 } else {
3847 panic!("Expected let");
3848 }
3849 }
3850
3851 #[test]
3852 fn test_parse_block_body_closure() {
3853 let program = parse("let f = (x: int64) -> int64 { let y = x * 2\n y + 1 }").unwrap();
3854 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
3855 if let Expr::Closure {
3856 params,
3857 body,
3858 return_type,
3859 } = value
3860 {
3861 assert_eq!(params.len(), 1);
3862 assert_eq!(params[0].name, "x");
3863 assert!(return_type.is_some());
3864 if let ClosureBody::Block { stmts, expr } = body {
3865 assert_eq!(stmts.len(), 1); assert!(expr.is_some()); } else {
3868 panic!("Expected block body");
3869 }
3870 } else {
3871 panic!("Expected closure");
3872 }
3873 } else {
3874 panic!("Expected let");
3875 }
3876 }
3877
3878 #[test]
3879 fn test_is_closure_ahead_arrow() {
3880 let program = parse("let f = (x) -> int64 { x + 1 }").unwrap();
3882 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
3883 assert!(matches!(value, Expr::Closure { .. }));
3884 } else {
3885 panic!("Expected let with closure");
3886 }
3887 }
3888
3889 #[test]
3890 fn test_parse_block_body_closure_no_params() {
3891 let program = parse("let f = () -> int64 { 42 }").unwrap();
3892 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
3893 if let Expr::Closure { params, body, .. } = value {
3894 assert_eq!(params.len(), 0);
3895 if let ClosureBody::Block { stmts, expr } = body {
3896 assert!(stmts.is_empty());
3897 assert!(expr.is_some());
3898 } else {
3899 panic!("Expected block body");
3900 }
3901 } else {
3902 panic!("Expected closure");
3903 }
3904 } else {
3905 panic!("Expected let");
3906 }
3907 }
3908
3909 #[test]
3910 fn test_parse_type_alias_simple() {
3911 let program = parse("type Mapper = fn(int64) -> int64").unwrap();
3912 if let StmtKind::TypeAlias {
3913 name,
3914 type_params,
3915 value,
3916 is_public,
3917 } = &program.statements[0].kind
3918 {
3919 assert_eq!(name, "Mapper");
3920 assert!(type_params.is_empty());
3921 assert!(!is_public);
3922 assert!(matches!(value, TypeExpr::Function { .. }));
3923 } else {
3924 panic!("Expected TypeAlias");
3925 }
3926 }
3927
3928 #[test]
3929 fn test_parse_type_alias_generic() {
3930 let program = parse("type Pair<T> = list<T>").unwrap();
3931 if let StmtKind::TypeAlias {
3932 name, type_params, ..
3933 } = &program.statements[0].kind
3934 {
3935 assert_eq!(name, "Pair");
3936 assert_eq!(type_params, &["T"]);
3937 } else {
3938 panic!("Expected TypeAlias");
3939 }
3940 }
3941
3942 #[test]
3943 fn test_parse_pub_type_alias() {
3944 let program = parse("pub type Predicate = fn(string) -> bool").unwrap();
3945 if let StmtKind::TypeAlias {
3946 name, is_public, ..
3947 } = &program.statements[0].kind
3948 {
3949 assert_eq!(name, "Predicate");
3950 assert!(is_public);
3951 } else {
3952 panic!("Expected TypeAlias");
3953 }
3954 }
3955
3956 #[test]
3957 fn test_parse_shorthand_closure() {
3958 let program = parse("let f = x => x * 2").unwrap();
3959 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
3960 if let Expr::Closure {
3961 params,
3962 body,
3963 return_type,
3964 } = value
3965 {
3966 assert_eq!(params.len(), 1);
3967 assert_eq!(params[0].name, "x");
3968 assert!(return_type.is_none());
3969 assert!(matches!(body, ClosureBody::Expr(_)));
3970 } else {
3971 panic!("Expected closure");
3972 }
3973 } else {
3974 panic!("Expected let");
3975 }
3976 }
3977
3978 #[test]
3979 fn test_parse_shorthand_closure_in_call() {
3980 let program = parse("map(nums, x => x + 1)").unwrap();
3982 if let StmtKind::Expr(Expr::Call { args, .. }) = &program.statements[0].kind {
3983 assert_eq!(args.len(), 2);
3984 assert!(matches!(&args[1], Expr::Closure { .. }));
3985 } else {
3986 panic!("Expected call with closure arg");
3987 }
3988 }
3989
3990 #[test]
3993 fn test_doc_comment_on_fn() {
3994 let program = parse("/// Adds two numbers\nfn add(a, b) { a + b }").unwrap();
3995 assert_eq!(
3996 program.statements[0].doc_comment.as_deref(),
3997 Some("Adds two numbers")
3998 );
3999 }
4000
4001 #[test]
4002 fn test_doc_comment_on_struct() {
4003 let program = parse("/// A 2D point\nstruct Point { x: int, y: int }").unwrap();
4004 assert_eq!(
4005 program.statements[0].doc_comment.as_deref(),
4006 Some("A 2D point")
4007 );
4008 }
4009
4010 #[test]
4011 fn test_doc_comment_on_enum() {
4012 let program = parse("/// Color values\nenum Color { Red, Green, Blue }").unwrap();
4013 assert_eq!(
4014 program.statements[0].doc_comment.as_deref(),
4015 Some("Color values")
4016 );
4017 }
4018
4019 #[test]
4020 fn test_doc_comment_on_trait() {
4021 let program =
4022 parse("/// Display trait\ntrait Display { fn show(self) -> string }").unwrap();
4023 assert_eq!(
4024 program.statements[0].doc_comment.as_deref(),
4025 Some("Display trait")
4026 );
4027 }
4028
4029 #[test]
4030 fn test_doc_comment_on_pub_fn() {
4031 let program = parse("/// Public function\npub fn greet() { print(\"hi\") }").unwrap();
4032 assert_eq!(
4033 program.statements[0].doc_comment.as_deref(),
4034 Some("Public function")
4035 );
4036 }
4037
4038 #[test]
4039 fn test_multiline_doc_comment() {
4040 let source = "/// First line\n/// Second line\n/// Third line\nfn foo() {}";
4041 let program = parse(source).unwrap();
4042 assert_eq!(
4043 program.statements[0].doc_comment.as_deref(),
4044 Some("First line\nSecond line\nThird line")
4045 );
4046 }
4047
4048 #[test]
4049 fn test_no_doc_comment() {
4050 let program = parse("fn foo() {}").unwrap();
4051 assert!(program.statements[0].doc_comment.is_none());
4052 }
4053
4054 #[test]
4055 fn test_inner_doc_comment_module() {
4056 let source = "//! This module does stuff\n//! More info\nfn foo() {}";
4057 let program = parse(source).unwrap();
4058 assert_eq!(
4059 program.module_doc.as_deref(),
4060 Some("This module does stuff\nMore info")
4061 );
4062 }
4063
4064 #[test]
4065 fn test_doc_comment_not_on_expr() {
4066 let source = "/// Some doc\n42";
4068 let program = parse(source).unwrap();
4069 assert_eq!(
4071 program.statements[0].doc_comment.as_deref(),
4072 Some("Some doc")
4073 );
4074 }
4075
4076 #[test]
4077 fn test_doc_comment_on_let() {
4078 let program = parse("/// The answer\nlet x = 42").unwrap();
4079 assert_eq!(
4080 program.statements[0].doc_comment.as_deref(),
4081 Some("The answer")
4082 );
4083 }
4084
4085 #[test]
4086 fn test_doc_comment_on_schema() {
4087 let program = parse("/// User schema\nschema User { name: string, age: int }").unwrap();
4088 assert_eq!(
4089 program.statements[0].doc_comment.as_deref(),
4090 Some("User schema")
4091 );
4092 }
4093
4094 #[test]
4097 fn test_parse_versioned_schema() {
4098 let source = "/// User schema\n/// @version 1\nschema User { name: string }";
4099 let program = parse(source).unwrap();
4100 if let StmtKind::Schema { name, version, .. } = &program.statements[0].kind {
4101 assert_eq!(name, "User");
4102 assert_eq!(*version, Some(1));
4103 } else {
4104 panic!("Expected Schema statement");
4105 }
4106 }
4107
4108 #[test]
4109 fn test_parse_schema_field_doc_comments() {
4110 let source = "schema User {\n /// User's name\n /// @since 1\n name: string\n}";
4111 let program = parse(source).unwrap();
4112 if let StmtKind::Schema { fields, .. } = &program.statements[0].kind {
4113 assert_eq!(fields[0].name, "name");
4114 assert!(fields[0].doc_comment.is_some());
4115 assert!(fields[0].doc_comment.as_ref().unwrap().contains("@since"));
4116 } else {
4117 panic!("Expected Schema statement");
4118 }
4119 }
4120
4121 #[test]
4122 fn test_parse_schema_field_default_value() {
4123 let source = "schema User { name: string = \"unknown\", age: int64 }";
4124 let program = parse(source).unwrap();
4125 if let StmtKind::Schema { fields, .. } = &program.statements[0].kind {
4126 assert_eq!(fields.len(), 2);
4127 assert!(fields[0].default_value.is_some());
4128 assert!(fields[1].default_value.is_none());
4129 } else {
4130 panic!("Expected Schema statement");
4131 }
4132 }
4133
4134 #[test]
4135 fn test_parse_migrate_add_column() {
4136 let source = "migrate User from 1 to 2 { add_column(email: string) }";
4137 let program = parse(source).unwrap();
4138 if let StmtKind::Migrate {
4139 schema_name,
4140 from_version,
4141 to_version,
4142 operations,
4143 } = &program.statements[0].kind
4144 {
4145 assert_eq!(schema_name, "User");
4146 assert_eq!(*from_version, 1);
4147 assert_eq!(*to_version, 2);
4148 assert_eq!(operations.len(), 1);
4149 assert!(matches!(&operations[0], MigrateOp::AddColumn { name, .. } if name == "email"));
4150 } else {
4151 panic!("Expected Migrate statement");
4152 }
4153 }
4154
4155 #[test]
4156 fn test_parse_migrate_drop_column() {
4157 let source = "migrate User from 2 to 3 { drop_column(legacy) }";
4158 let program = parse(source).unwrap();
4159 if let StmtKind::Migrate { operations, .. } = &program.statements[0].kind {
4160 assert!(matches!(&operations[0], MigrateOp::DropColumn { name } if name == "legacy"));
4161 } else {
4162 panic!("Expected Migrate statement");
4163 }
4164 }
4165
4166 #[test]
4167 fn test_parse_migrate_rename_column() {
4168 let source = "migrate User from 1 to 2 { rename_column(old_name, new_name) }";
4169 let program = parse(source).unwrap();
4170 if let StmtKind::Migrate { operations, .. } = &program.statements[0].kind {
4171 assert!(
4172 matches!(&operations[0], MigrateOp::RenameColumn { from, to } if from == "old_name" && to == "new_name")
4173 );
4174 } else {
4175 panic!("Expected Migrate statement");
4176 }
4177 }
4178
4179 #[test]
4180 fn test_parse_migrate_alter_type() {
4181 let source = "migrate User from 1 to 2 { alter_type(age, float64) }";
4182 let program = parse(source).unwrap();
4183 if let StmtKind::Migrate { operations, .. } = &program.statements[0].kind {
4184 assert!(
4185 matches!(&operations[0], MigrateOp::AlterType { column, .. } if column == "age")
4186 );
4187 } else {
4188 panic!("Expected Migrate statement");
4189 }
4190 }
4191
4192 #[test]
4193 fn test_parse_migrate_multiple_operations() {
4194 let source = "migrate User from 1 to 2 {\n add_column(email: string)\n drop_column(legacy)\n rename_column(fname, first_name)\n}";
4195 let program = parse(source).unwrap();
4196 if let StmtKind::Migrate { operations, .. } = &program.statements[0].kind {
4197 assert_eq!(operations.len(), 3);
4198 assert!(matches!(&operations[0], MigrateOp::AddColumn { .. }));
4199 assert!(matches!(&operations[1], MigrateOp::DropColumn { .. }));
4200 assert!(matches!(&operations[2], MigrateOp::RenameColumn { .. }));
4201 } else {
4202 panic!("Expected Migrate statement");
4203 }
4204 }
4205
4206 #[test]
4207 fn test_parse_migrate_error_no_versions() {
4208 let result = parse("migrate User { add_column(x: int64) }");
4209 assert!(result.is_err());
4210 }
4211
4212 #[test]
4213 fn test_parse_migrate_error_invalid_op() {
4214 let result = parse("migrate User from 1 to 2 { invalid_op(x) }");
4215 assert!(result.is_err());
4216 }
4217
4218 #[test]
4219 fn test_parse_migrate_add_column_with_default() {
4220 let source = "migrate User from 1 to 2 { add_column(email: string, default: \"\") }";
4221 let program = parse(source).unwrap();
4222 if let StmtKind::Migrate { operations, .. } = &program.statements[0].kind {
4223 if let MigrateOp::AddColumn { name, default, .. } = &operations[0] {
4224 assert_eq!(name, "email");
4225 assert!(default.is_some());
4226 } else {
4227 panic!("Expected AddColumn");
4228 }
4229 } else {
4230 panic!("Expected Migrate statement");
4231 }
4232 }
4233
4234 #[test]
4235 fn test_parse_schema_version_in_doc() {
4236 let source = "/// @version 5\nschema Events { ts: int64 }";
4237 let program = parse(source).unwrap();
4238 if let StmtKind::Schema { version, .. } = &program.statements[0].kind {
4239 assert_eq!(*version, Some(5));
4240 } else {
4241 panic!("Expected Schema statement");
4242 }
4243 }
4244
4245 #[test]
4248 fn test_parse_decimal_literal() {
4249 let source = "let x = 3.14d";
4250 let program = parse(source).unwrap();
4251 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
4252 match value {
4253 Expr::Decimal(s) => assert_eq!(s, "3.14"),
4255 _ => panic!("Expected Expr::Decimal, got {value:?}"),
4256 }
4257 } else {
4258 panic!("Expected Let statement");
4259 }
4260 }
4261
4262 #[test]
4263 fn test_parse_decimal_underscore() {
4264 let source = "let x = 1_000.50d";
4265 let program = parse(source).unwrap();
4266 if let StmtKind::Let { value, .. } = &program.statements[0].kind {
4267 match value {
4268 Expr::Decimal(s) => assert_eq!(s, "1000.50"),
4270 _ => panic!("Expected Expr::Decimal"),
4271 }
4272 } else {
4273 panic!("Expected Let statement");
4274 }
4275 }
4276
4277 #[test]
4278 fn test_parse_async_fn() {
4279 let source = "async fn fetch() { return 42 }";
4280 let program = parse(source).unwrap();
4281 if let StmtKind::FnDecl { name, is_async, .. } = &program.statements[0].kind {
4282 assert_eq!(name, "fetch");
4283 assert!(*is_async);
4284 } else {
4285 panic!("Expected FnDecl statement");
4286 }
4287 }
4288
4289 #[test]
4290 fn test_parse_async_fn_with_params() {
4291 let source = "async fn get(url, timeout) { return url }";
4292 let program = parse(source).unwrap();
4293 if let StmtKind::FnDecl {
4294 name,
4295 is_async,
4296 params,
4297 ..
4298 } = &program.statements[0].kind
4299 {
4300 assert_eq!(name, "get");
4301 assert!(*is_async);
4302 assert_eq!(params.len(), 2);
4303 } else {
4304 panic!("Expected FnDecl statement");
4305 }
4306 }
4307
4308 #[test]
4309 fn test_parse_sensitive_annotation() {
4310 let source = r#"
4311/// @sensitive
4312schema Secret {
4313 password: string
4314}
4315"#;
4316 let program = parse(source).unwrap();
4317 if let StmtKind::Schema { fields, .. } = &program.statements[0].kind {
4318 assert!(!fields.is_empty());
4319 } else {
4321 panic!("Expected Schema statement");
4322 }
4323 }
4324}