1use bock_ast::{
10 Annotation, AnnotationArg, Arg, AssignOp, AssociatedType, BinOp, Block, ClassDecl, ConstDecl,
11 EffectDecl, EnumDecl, EnumVariant, Expr, FnDecl, ForLoop, GenericParam, GuardStmt, HandlerPair,
12 HandlingBlock, Ident, ImplBlock, ImportDecl, ImportItems, ImportedName, InterpolationPart,
13 Item, LetStmt, Literal, MatchArm, Module, ModuleHandleDecl, ModulePath, NodeId,
14 Param, Pattern, RecordDecl, RecordDeclField, RecordField, RecordPatternField, RecordSpread,
15 Stmt, TraitDecl, TypeAliasDecl, TypeConstraint, TypeExpr, TypePath, UnaryOp, Visibility,
16 WhileLoop,
17};
18use bock_errors::{DiagnosticBag, DiagnosticCode, Span};
19use bock_lexer::{Token, TokenKind};
20use bock_source::SourceFile;
21
22#[derive(Debug, Clone, PartialEq)]
24enum OpTag {
25 Assign(AssignOp),
26 Pipe,
27 Compose,
28 Range,
29 RangeInclusive,
30 Binary(BinOp),
31 Is,
32}
33
34pub struct Parser<'src> {
38 tokens: Vec<Token>,
39 pos: usize,
40 source: &'src SourceFile,
41 diagnostics: DiagnosticBag,
42 next_id: NodeId,
43 consecutive_errors: usize,
45}
46
47impl<'src> Parser<'src> {
48 #[must_use]
52 pub fn new(tokens: Vec<Token>, source: &'src SourceFile) -> Self {
53 assert!(
54 !tokens.is_empty(),
55 "token list must contain at least an EOF token"
56 );
57 Self {
58 tokens,
59 pos: 0,
60 source,
61 diagnostics: DiagnosticBag::new(),
62 next_id: 0,
63 consecutive_errors: 0,
64 }
65 }
66
67 pub fn parse_module(&mut self) -> Module {
69 let start_span = self.peek().span;
70
71 self.skip_newlines();
74 let mut doc = Vec::new();
75 while self.at(TokenKind::ModuleDocComment) {
76 let tok = self.advance();
77 if let Some(text) = tok.literal {
78 doc.push(text);
79 }
80 self.skip_newlines();
81 }
82 self.skip_newlines();
83
84 let path = if self.at(TokenKind::Module) {
86 Some(self.parse_module_decl())
87 } else {
88 None
89 };
90 self.skip_newlines();
91
92 while self.at(TokenKind::ModuleDocComment) {
96 let tok = self.advance();
97 if let Some(text) = tok.literal {
98 doc.push(text);
99 }
100 self.skip_newlines();
101 }
102 self.skip_newlines();
103
104 let mut imports = Vec::new();
106 loop {
107 self.skip_newlines();
108 if self.at(TokenKind::Use) {
109 imports.push(self.parse_import_decl(Visibility::Private));
110 } else if self.at_visibility() && self.peek_kind_at(1) == Some(TokenKind::Use) {
111 let vis = self.parse_visibility();
112 imports.push(self.parse_import_decl(vis));
113 } else {
114 break;
115 }
116 }
117 self.skip_newlines();
118
119 let items = self.parse_items();
121
122 let end_span = self.peek().span;
123 Module {
124 id: self.alloc_id(),
125 span: Span::merge(start_span, end_span),
126 doc,
127 path,
128 imports,
129 items,
130 }
131 }
132
133 #[must_use]
135 pub fn diagnostics(&self) -> &DiagnosticBag {
136 &self.diagnostics
137 }
138
139 pub(crate) fn peek(&self) -> &Token {
143 &self.tokens[self.pos]
144 }
145
146 pub(crate) fn advance(&mut self) -> Token {
148 let tok = self.tokens[self.pos].clone();
149 if self.pos + 1 < self.tokens.len() {
150 self.pos += 1;
151 }
152 tok
153 }
154
155 #[must_use]
157 pub(crate) fn at(&self, kind: TokenKind) -> bool {
158 self.peek().kind == kind
159 }
160
161 pub(crate) fn expect(&mut self, kind: TokenKind) -> Result<Token, ()> {
163 if self.at(kind.clone()) {
164 Ok(self.advance())
165 } else {
166 let span = self.peek().span;
167 let found = self.peek().kind.clone();
168 self.diagnostics.error(
169 DiagnosticCode {
170 prefix: 'E',
171 number: 2000,
172 },
173 format!("expected `{kind}`, found `{found}`"),
174 span,
175 );
176 Err(())
177 }
178 }
179
180 pub(crate) fn skip_newlines(&mut self) {
182 while self.at(TokenKind::Newline) {
183 let _ = self.advance();
184 }
185 }
186
187 fn peek_past_newlines_kind(&self) -> Option<TokenKind> {
190 let mut i = self.pos;
191 while i < self.tokens.len() && self.tokens[i].kind == TokenKind::Newline {
192 i += 1;
193 }
194 self.tokens.get(i).map(|t| t.kind.clone())
195 }
196
197 fn alloc_id(&mut self) -> NodeId {
200 let id = self.next_id;
201 self.next_id += 1;
202 id
203 }
204
205 fn peek_kind_at(&self, offset: usize) -> Option<TokenKind> {
207 self.tokens.get(self.pos + offset).map(|t| t.kind.clone())
208 }
209
210 fn at_visibility(&self) -> bool {
211 matches!(self.peek().kind, TokenKind::Public | TokenKind::Internal)
212 }
213
214 fn at_decl_start(&self) -> bool {
216 matches!(
217 self.peek().kind,
218 TokenKind::Fn
219 | TokenKind::Async
220 | TokenKind::Record
221 | TokenKind::Enum
222 | TokenKind::Class
223 | TokenKind::Trait
224 | TokenKind::Platform
225 | TokenKind::Impl
226 | TokenKind::Effect
227 | TokenKind::Const
228 | TokenKind::Type
229 | TokenKind::Use
230 | TokenKind::Handle
231 | TokenKind::At
232 | TokenKind::Public
233 | TokenKind::Internal
234 )
235 }
236
237 fn synchronize(&mut self) -> Span {
242 let start = self.peek().span;
243 let mut end = start;
244 while !self.at(TokenKind::Eof) {
245 let kind = self.peek().kind.clone();
246 match kind {
247 TokenKind::Semicolon | TokenKind::RBrace => {
249 let _ = self.advance(); end = self.peek().span;
251 break;
252 }
253 TokenKind::Newline => {
254 let _ = self.advance();
255 if self.at_decl_start() || self.at(TokenKind::Eof) {
257 break;
258 }
259 }
260 _ if self.at_decl_start() => break,
261 _ => {
262 end = self.peek().span;
263 let _ = self.advance();
264 }
265 }
266 }
267 Span::merge(start, end)
268 }
269
270 fn synchronize_to_top_level(&mut self) -> Span {
275 let start = self.peek().span;
276 let mut end = start;
277 while !self.at(TokenKind::Eof) {
278 self.skip_newlines();
279 if self.at(TokenKind::Eof) || self.at_decl_start() {
280 break;
281 }
282 end = self.peek().span;
283 let _ = self.advance();
284 }
285 Span::merge(start, end)
286 }
287
288 fn parse_visibility(&mut self) -> Visibility {
289 match self.peek().kind {
290 TokenKind::Public => {
291 let _ = self.advance();
292 Visibility::Public
293 }
294 TokenKind::Internal => {
295 let _ = self.advance();
296 Visibility::Internal
297 }
298 _ => Visibility::Private,
299 }
300 }
301
302 fn parse_module_decl(&mut self) -> ModulePath {
306 let _ = self.advance(); let path = self.parse_module_path();
308 if self.at(TokenKind::Newline) {
309 let _ = self.advance();
310 }
311 path
312 }
313
314 fn parse_module_path(&mut self) -> ModulePath {
316 let start = self.peek().span;
317 let mut segments = Vec::new();
318
319 if let Some(seg) = self.try_parse_path_segment() {
320 segments.push(seg);
321 }
322
323 while self.at(TokenKind::Dot) {
325 match self.peek_kind_at(1) {
326 Some(TokenKind::Ident) | Some(TokenKind::TypeIdent) => {
327 let _ = self.advance(); if let Some(seg) = self.try_parse_path_segment() {
329 segments.push(seg);
330 }
331 }
332 _ => break,
333 }
334 }
335
336 let end = segments.last().map(|s| s.span).unwrap_or(start);
337 ModulePath {
338 span: Span::merge(start, end),
339 segments,
340 }
341 }
342
343 fn try_parse_path_segment(&mut self) -> Option<Ident> {
345 if matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
346 let tok = self.advance();
347 Some(Ident {
348 name: tok.literal.unwrap_or_default(),
349 span: tok.span,
350 })
351 } else {
352 let span = self.peek().span;
353 let found = self.peek().kind.clone();
354 self.diagnostics.error(
355 DiagnosticCode {
356 prefix: 'E',
357 number: 2001,
358 },
359 format!("expected identifier in path, found `{found}`"),
360 span,
361 );
362 None
363 }
364 }
365
366 fn parse_import_decl(&mut self, vis: Visibility) -> ImportDecl {
370 let start = self.peek().span;
371 let _ = self.advance(); let path = self.parse_import_base_path();
375
376 let items = self.parse_import_items();
378
379 if self.at(TokenKind::Newline) {
380 let _ = self.advance();
381 }
382
383 let end = self.peek().span;
384 ImportDecl {
385 id: self.alloc_id(),
386 span: Span::merge(start, end),
387 visibility: vis,
388 path,
389 items,
390 }
391 }
392
393 fn parse_import_base_path(&mut self) -> ModulePath {
397 let start = self.peek().span;
398 let mut segments = Vec::new();
399
400 if let Some(seg) = self.try_parse_path_segment() {
401 segments.push(seg);
402 }
403
404 while self.at(TokenKind::Dot) {
405 match self.peek_kind_at(1) {
406 Some(TokenKind::LBrace) | Some(TokenKind::Star) => break,
408 Some(TokenKind::Ident) | Some(TokenKind::TypeIdent) => {
410 let _ = self.advance(); if let Some(seg) = self.try_parse_path_segment() {
412 segments.push(seg);
413 }
414 }
415 _ => break,
416 }
417 }
418
419 let end = segments.last().map(|s| s.span).unwrap_or(start);
420 ModulePath {
421 span: Span::merge(start, end),
422 segments,
423 }
424 }
425
426 fn parse_import_items(&mut self) -> ImportItems {
435 if !self.at(TokenKind::Dot) {
436 return ImportItems::Module;
437 }
438
439 match self.peek_kind_at(1) {
440 Some(TokenKind::Star) => {
441 let _ = self.advance(); let _ = self.advance(); ImportItems::Glob
444 }
445 Some(TokenKind::LBrace) => {
446 let _ = self.advance(); let _ = self.advance(); let names = self.parse_named_import_list();
449 let _ = self.expect(TokenKind::RBrace);
450 ImportItems::Named(names)
451 }
452 Some(TokenKind::Ident) | Some(TokenKind::TypeIdent) => {
453 let _ = self.advance(); let tok = self.advance(); let span = tok.span;
456 let name = Ident {
457 name: tok.literal.unwrap_or_default(),
458 span,
459 };
460 ImportItems::Named(vec![ImportedName {
461 span,
462 name,
463 alias: None,
464 }])
465 }
466 _ => ImportItems::Module,
467 }
468 }
469
470 fn parse_named_import_list(&mut self) -> Vec<ImportedName> {
472 let mut names = Vec::new();
473 self.skip_newlines();
474
475 while !self.at(TokenKind::RBrace) && !self.at(TokenKind::Eof) {
476 if !matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
477 break;
478 }
479 let tok = self.advance();
480 let start_span = tok.span;
481 let name = Ident {
482 name: tok.literal.unwrap_or_default(),
483 span: tok.span,
484 };
485
486 let alias = if self.at(TokenKind::Ident) && self.peek().literal.as_deref() == Some("as")
488 {
489 let _ = self.advance(); if matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
491 let alias_tok = self.advance();
492 Some(Ident {
493 name: alias_tok.literal.unwrap_or_default(),
494 span: alias_tok.span,
495 })
496 } else {
497 None
498 }
499 } else {
500 None
501 };
502
503 let end_span = alias.as_ref().map(|a| a.span).unwrap_or(start_span);
504 names.push(ImportedName {
505 span: Span::merge(start_span, end_span),
506 name,
507 alias,
508 });
509
510 self.skip_newlines();
511 if self.at(TokenKind::Comma) {
512 let _ = self.advance();
513 self.skip_newlines();
514 } else {
515 break;
516 }
517 }
518
519 names
520 }
521
522 fn parse_items(&mut self) -> Vec<Item> {
526 let mut items = Vec::new();
527
528 loop {
529 self.skip_newlines();
530 if self.at(TokenKind::Eof) {
531 break;
532 }
533
534 while self.at(TokenKind::DocComment) || self.at(TokenKind::ModuleDocComment) {
538 let _ = self.advance();
539 self.skip_newlines();
540 }
541 if self.at(TokenKind::Eof) {
542 break;
543 }
544
545 let mut annotations = Vec::new();
547 while self.at(TokenKind::At) {
548 annotations.push(self.parse_annotation());
549 self.skip_newlines();
550 }
551
552 let vis = if self.at_visibility() {
554 self.parse_visibility()
555 } else {
556 Visibility::Private
557 };
558
559 let error_count_before = self.diagnostics.error_count();
560
561 let item = match self.peek().kind.clone() {
563 TokenKind::Fn | TokenKind::Async => Item::Fn(self.parse_fn_decl(annotations, vis)),
564 TokenKind::Record => Item::Record(self.parse_record_decl(annotations, vis)),
565 TokenKind::Enum => Item::Enum(self.parse_enum_decl(annotations, vis)),
566 TokenKind::Class => Item::Class(self.parse_class_decl(annotations, vis)),
567 TokenKind::Trait => Item::Trait(self.parse_trait_decl(annotations, vis, false)),
568 TokenKind::Platform => {
569 Item::PlatformTrait(self.parse_platform_trait_decl(annotations, vis))
571 }
572 TokenKind::Impl => Item::Impl(self.parse_impl_block(annotations)),
573 TokenKind::Effect => Item::Effect(self.parse_effect_decl(annotations, vis)),
574 TokenKind::Handle => Item::ModuleHandle(self.parse_module_handle_decl()),
575 TokenKind::Type => Item::TypeAlias(self.parse_type_alias_decl(annotations, vis)),
576 TokenKind::Const => Item::Const(self.parse_const_decl(annotations, vis)),
577 _ => {
578 if self.at(TokenKind::Eof) {
579 break;
580 }
581 let span = self.peek().span;
583 let found = self.peek().kind.clone();
584 self.diagnostics.error(
585 DiagnosticCode {
586 prefix: 'E',
587 number: 2050,
588 },
589 format!("unexpected token `{found}` at top level"),
590 span,
591 );
592 self.consecutive_errors += 1;
593 let error_span = if self.consecutive_errors >= 3 {
594 self.consecutive_errors = 0;
596 self.synchronize_to_top_level()
597 } else {
598 self.synchronize()
599 };
600 let id = self.alloc_id();
601 items.push(Item::Error {
602 id,
603 span: error_span,
604 });
605 continue;
606 }
607 };
608
609 if self.diagnostics.error_count() == error_count_before {
611 self.consecutive_errors = 0;
612 } else {
613 self.consecutive_errors += 1;
614 }
615
616 items.push(item);
617 }
618
619 items
620 }
621
622 fn parse_annotation(&mut self) -> Annotation {
626 let start = self.peek().span;
627 let _ = self.advance(); let name_span = self.peek().span;
630 let name = if matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
631 let tok = self.advance();
632 Ident {
633 name: tok.literal.unwrap_or_default(),
634 span: tok.span,
635 }
636 } else {
637 self.diagnostics.error(
638 DiagnosticCode {
639 prefix: 'E',
640 number: 2002,
641 },
642 format!("expected annotation name, found `{}`", self.peek().kind),
643 name_span,
644 );
645 Ident {
646 name: String::new(),
647 span: name_span,
648 }
649 };
650
651 let mut args = Vec::new();
652 if self.at(TokenKind::LParen) {
653 let _ = self.advance(); self.skip_newlines();
655 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
656 let label = if self.at(TokenKind::Ident)
658 && self.peek_kind_at(1) == Some(TokenKind::Colon)
659 {
660 let lbl_tok = self.advance();
661 let _ = self.advance(); Some(Ident {
663 name: lbl_tok.literal.unwrap_or_default(),
664 span: lbl_tok.span,
665 })
666 } else {
667 None
668 };
669 args.push(AnnotationArg {
670 label,
671 value: self.parse_expr_stub(),
672 });
673 self.skip_newlines();
674 if self.at(TokenKind::Comma) {
675 let _ = self.advance();
676 self.skip_newlines();
677 } else {
678 break;
679 }
680 }
681 let _ = self.expect(TokenKind::RParen);
682 }
683
684 let end = self.peek().span;
685 Annotation {
686 id: self.alloc_id(),
687 span: Span::merge(start, end),
688 name,
689 args,
690 }
691 }
692
693 fn parse_generic_params(&mut self) -> Vec<GenericParam> {
697 if !self.at(TokenKind::LBracket) {
698 return Vec::new();
699 }
700 let _ = self.advance(); let mut params = Vec::new();
703 self.skip_newlines();
704
705 while !self.at(TokenKind::RBracket) && !self.at(TokenKind::Eof) {
706 if !matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
707 break;
708 }
709 let id = self.alloc_id();
710 let start = self.peek().span;
711 let tok = self.advance();
712 let name = Ident {
713 name: tok.literal.unwrap_or_default(),
714 span: tok.span,
715 };
716
717 let bounds = if self.at(TokenKind::Colon) {
719 let _ = self.advance();
720 vec![self.parse_type_path()]
721 } else {
722 Vec::new()
723 };
724
725 let end = bounds.last().map(|b| b.span).unwrap_or(name.span);
726 params.push(GenericParam {
727 id,
728 span: Span::merge(start, end),
729 name,
730 bounds,
731 });
732
733 self.skip_newlines();
734 if self.at(TokenKind::Comma) {
735 let _ = self.advance();
736 self.skip_newlines();
737 } else {
738 break;
739 }
740 }
741
742 let _ = self.expect(TokenKind::RBracket);
743 params
744 }
745
746 fn parse_where_clause(&mut self) -> Vec<TypeConstraint> {
748 if !self.at(TokenKind::Where) {
749 return Vec::new();
750 }
751 let _ = self.advance(); let _ = self.expect(TokenKind::LParen);
754 let mut constraints = Vec::new();
755 self.skip_newlines();
756
757 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
758 if !matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
759 break;
760 }
761 let id = self.alloc_id();
762 let start = self.peek().span;
763 let tok = self.advance();
764 let param = Ident {
765 name: tok.literal.unwrap_or_default(),
766 span: tok.span,
767 };
768
769 let _ = self.expect(TokenKind::Colon);
770 let bounds = vec![self.parse_type_path()];
771
772 let end = bounds.last().map(|b| b.span).unwrap_or(param.span);
773 constraints.push(TypeConstraint {
774 id,
775 span: Span::merge(start, end),
776 param,
777 bounds,
778 });
779
780 self.skip_newlines();
781 if self.at(TokenKind::Comma) {
782 let _ = self.advance();
783 self.skip_newlines();
784 } else {
785 break;
786 }
787 }
788
789 let _ = self.expect(TokenKind::RParen);
790 constraints
791 }
792
793 fn parse_type_expr(&mut self) -> TypeExpr {
797 let id = self.alloc_id();
798 let start = self.peek().span;
799
800 let base = match self.peek().kind.clone() {
801 TokenKind::LParen => {
802 let _ = self.advance(); self.skip_newlines();
804
805 if self.at(TokenKind::RParen) {
806 let end = self.advance().span;
808 TypeExpr::Tuple {
809 id,
810 span: Span::merge(start, end),
811 elems: vec![],
812 }
813 } else {
814 let mut elems = Vec::new();
815 elems.push(self.parse_type_expr());
816 self.skip_newlines();
817 while self.at(TokenKind::Comma) {
818 let _ = self.advance();
819 self.skip_newlines();
820 if self.at(TokenKind::RParen) {
821 break;
822 }
823 elems.push(self.parse_type_expr());
824 self.skip_newlines();
825 }
826 let end = self
827 .expect(TokenKind::RParen)
828 .map(|t| t.span)
829 .unwrap_or(start);
830
831 if self.at(TokenKind::ThinArrow) {
833 let _ = self.advance();
834 let ret = self.parse_type_expr();
835 TypeExpr::Function {
836 id,
837 span: Span::merge(start, ret.span()),
838 params: elems,
839 ret: Box::new(ret),
840 effects: vec![],
841 }
842 } else if elems.len() == 1 {
843 elems.remove(0)
845 } else {
846 TypeExpr::Tuple {
847 id,
848 span: Span::merge(start, end),
849 elems,
850 }
851 }
852 }
853 }
854
855 TokenKind::SelfLower | TokenKind::SelfUpper => {
856 let tok = self.advance();
857 TypeExpr::SelfType { id, span: tok.span }
858 }
859
860 TokenKind::Ident | TokenKind::TypeIdent => {
861 if self.peek().literal.as_deref() == Some("Fn")
863 && self.peek_kind_at(1) == Some(TokenKind::LParen)
864 {
865 let _ = self.advance(); let _ = self.advance(); self.skip_newlines();
868 let mut params = Vec::new();
869 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
870 params.push(self.parse_type_expr());
871 self.skip_newlines();
872 if self.at(TokenKind::Comma) {
873 let _ = self.advance();
874 self.skip_newlines();
875 } else {
876 break;
877 }
878 }
879 let _ = self.expect(TokenKind::RParen);
880 let _ = self.expect(TokenKind::ThinArrow);
881 let ret = self.parse_type_expr();
882 let effects = self.parse_effect_clause();
884 let end = effects
885 .last()
886 .map(|e: &TypePath| e.span)
887 .unwrap_or(ret.span());
888 TypeExpr::Function {
889 id,
890 span: Span::merge(start, end),
891 params,
892 ret: Box::new(ret),
893 effects,
894 }
895 } else {
896 let path = self.parse_type_path();
897 let args = if self.at(TokenKind::LBracket) {
899 let _ = self.advance();
900 let mut args = Vec::new();
901 self.skip_newlines();
902 while !self.at(TokenKind::RBracket) && !self.at(TokenKind::Eof) {
903 args.push(self.parse_type_expr());
904 self.skip_newlines();
905 if self.at(TokenKind::Comma) {
906 let _ = self.advance();
907 self.skip_newlines();
908 } else {
909 break;
910 }
911 }
912 let _ = self.expect(TokenKind::RBracket);
913 args
914 } else {
915 Vec::new()
916 };
917 let span = path.span;
918 TypeExpr::Named {
919 id,
920 span,
921 path,
922 args,
923 }
924 }
925 }
926
927 _ => {
928 self.diagnostics.error(
929 DiagnosticCode {
930 prefix: 'E',
931 number: 2010,
932 },
933 format!("expected type expression, found `{}`", self.peek().kind),
934 start,
935 );
936 TypeExpr::Named {
937 id,
938 span: start,
939 path: TypePath {
940 segments: vec![],
941 span: start,
942 },
943 args: vec![],
944 }
945 }
946 };
947
948 if self.at(TokenKind::Question) {
950 let q = self.advance();
951 let id2 = self.alloc_id();
952 TypeExpr::Optional {
953 id: id2,
954 span: Span::merge(base.span(), q.span),
955 inner: Box::new(base),
956 }
957 } else {
958 base
959 }
960 }
961
962 fn parse_type_path(&mut self) -> TypePath {
964 let start = self.peek().span;
965 let mut segments = Vec::new();
966
967 if matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
968 let tok = self.advance();
969 segments.push(Ident {
970 name: tok.literal.unwrap_or_default(),
971 span: tok.span,
972 });
973 }
974
975 while self.at(TokenKind::Dot) {
976 match self.peek_kind_at(1) {
977 Some(TokenKind::TypeIdent) | Some(TokenKind::Ident) => {
978 let _ = self.advance(); let tok = self.advance();
980 segments.push(Ident {
981 name: tok.literal.unwrap_or_default(),
982 span: tok.span,
983 });
984 }
985 _ => break,
986 }
987 }
988
989 let end = segments.last().map(|s| s.span).unwrap_or(start);
990 TypePath {
991 segments,
992 span: Span::merge(start, end),
993 }
994 }
995
996 pub(crate) fn parse_expr(&mut self) -> Expr {
1000 self.parse_prec(0)
1001 }
1002
1003 fn parse_expr_stub(&mut self) -> Expr {
1005 self.parse_expr()
1006 }
1007
1008 fn parse_prec(&mut self, min_prec: u8) -> Expr {
1011 let mut left = self.parse_unary();
1013
1014 let mut seen_comparison = false;
1019
1020 loop {
1021 if self.at(TokenKind::Newline) {
1025 match self.peek_past_newlines_kind() {
1026 Some(TokenKind::Pipe) => self.skip_newlines(),
1027 _ => break,
1028 }
1029 }
1030
1031 let Some((op_prec, right_prec, op_tok)) = self.binary_op_info() else {
1032 break;
1033 };
1034 if op_prec < min_prec {
1035 break;
1036 }
1037
1038 if op_prec == 7 {
1040 if seen_comparison {
1041 break;
1042 }
1043 seen_comparison = true;
1044 }
1045
1046 if op_tok == OpTag::Is {
1048 let _ = self.advance(); self.skip_newlines(); let ty = self.parse_type_expr();
1051 let id = self.alloc_id();
1052 let span = Span::merge(left.span(), ty.span());
1053 left = Expr::Is {
1054 id,
1055 span,
1056 expr: Box::new(left),
1057 type_expr: ty,
1058 };
1059 continue; }
1061
1062 if matches!(op_tok, OpTag::Range | OpTag::RangeInclusive) {
1064 let inclusive = op_tok == OpTag::RangeInclusive;
1065 let _ = self.advance(); self.skip_newlines(); let right = self.parse_prec(op_prec + 1);
1068 let id = self.alloc_id();
1069 let span = Span::merge(left.span(), right.span());
1070 left = Expr::Range {
1071 id,
1072 span,
1073 lo: Box::new(left),
1074 hi: Box::new(right),
1075 inclusive,
1076 };
1077 break; }
1079
1080 let _ = self.advance(); self.skip_newlines();
1083
1084 let right = self.parse_prec(right_prec);
1085 let id = self.alloc_id();
1086 let span = Span::merge(left.span(), right.span());
1087
1088 left = match op_tok {
1089 OpTag::Assign(op) => Expr::Assign {
1090 id,
1091 span,
1092 op,
1093 target: Box::new(left),
1094 value: Box::new(right),
1095 },
1096 OpTag::Pipe => Expr::Pipe {
1097 id,
1098 span,
1099 left: Box::new(left),
1100 right: Box::new(right),
1101 },
1102 OpTag::Compose => Expr::Compose {
1103 id,
1104 span,
1105 left: Box::new(left),
1106 right: Box::new(right),
1107 },
1108 OpTag::Binary(op) => Expr::Binary {
1109 id,
1110 span,
1111 op,
1112 left: Box::new(left),
1113 right: Box::new(right),
1114 },
1115 OpTag::Is | OpTag::Range | OpTag::RangeInclusive => unreachable!(),
1116 };
1117
1118 }
1121
1122 left
1123 }
1124
1125 fn binary_op_info(&self) -> Option<(u8, u8, OpTag)> {
1128 let kind = &self.peek().kind;
1145 let (prec, right_prec, tag) = match kind {
1146 TokenKind::Assign => (1, 1, OpTag::Assign(AssignOp::Assign)),
1148 TokenKind::PlusEq => (1, 1, OpTag::Assign(AssignOp::AddAssign)),
1149 TokenKind::MinusEq => (1, 1, OpTag::Assign(AssignOp::SubAssign)),
1150 TokenKind::StarEq => (1, 1, OpTag::Assign(AssignOp::MulAssign)),
1151 TokenKind::SlashEq => (1, 1, OpTag::Assign(AssignOp::DivAssign)),
1152 TokenKind::PercentEq => (1, 1, OpTag::Assign(AssignOp::RemAssign)),
1153 TokenKind::Pipe => (2, 3, OpTag::Pipe),
1155 TokenKind::Shr | TokenKind::Compose => (3, 4, OpTag::Compose),
1157 TokenKind::DotDot => (4, 5, OpTag::Range),
1159 TokenKind::DotDotEq => (4, 5, OpTag::RangeInclusive),
1160 TokenKind::Or => (5, 6, OpTag::Binary(BinOp::Or)),
1162 TokenKind::And => (6, 7, OpTag::Binary(BinOp::And)),
1164 TokenKind::Eq => (7, 8, OpTag::Binary(BinOp::Eq)),
1166 TokenKind::Neq => (7, 8, OpTag::Binary(BinOp::Ne)),
1167 TokenKind::Lt => (7, 8, OpTag::Binary(BinOp::Lt)),
1168 TokenKind::Gt => (7, 8, OpTag::Binary(BinOp::Gt)),
1169 TokenKind::Lte => (7, 8, OpTag::Binary(BinOp::Le)),
1170 TokenKind::Gte => (7, 8, OpTag::Binary(BinOp::Ge)),
1171 TokenKind::Is => (7, 8, OpTag::Is),
1172 TokenKind::BitOr => (8, 9, OpTag::Binary(BinOp::BitOr)),
1174 TokenKind::BitXor => (9, 10, OpTag::Binary(BinOp::BitXor)),
1175 TokenKind::BitAnd => (10, 11, OpTag::Binary(BinOp::BitAnd)),
1176 TokenKind::Plus => (11, 12, OpTag::Binary(BinOp::Add)),
1178 TokenKind::Minus => (11, 12, OpTag::Binary(BinOp::Sub)),
1179 TokenKind::Star => (12, 13, OpTag::Binary(BinOp::Mul)),
1181 TokenKind::Slash => (12, 13, OpTag::Binary(BinOp::Div)),
1182 TokenKind::Percent => (12, 13, OpTag::Binary(BinOp::Rem)),
1183 TokenKind::Power => (13, 13, OpTag::Binary(BinOp::Pow)),
1185 _ => return None,
1186 };
1187 Some((prec, right_prec, tag))
1188 }
1189
1190 fn parse_unary(&mut self) -> Expr {
1192 let id = self.alloc_id();
1193 let span = self.peek().span;
1194
1195 match self.peek().kind.clone() {
1196 TokenKind::Minus => {
1197 let _ = self.advance();
1198 let operand = self.parse_unary();
1199 let span = Span::merge(span, operand.span());
1200 Expr::Unary {
1201 id,
1202 span,
1203 op: UnaryOp::Neg,
1204 operand: Box::new(operand),
1205 }
1206 }
1207 TokenKind::Not => {
1208 let _ = self.advance();
1209 let operand = self.parse_unary();
1210 let span = Span::merge(span, operand.span());
1211 Expr::Unary {
1212 id,
1213 span,
1214 op: UnaryOp::Not,
1215 operand: Box::new(operand),
1216 }
1217 }
1218 TokenKind::BitNot => {
1219 let _ = self.advance();
1220 let operand = self.parse_unary();
1221 let span = Span::merge(span, operand.span());
1222 Expr::Unary {
1223 id,
1224 span,
1225 op: UnaryOp::BitNot,
1226 operand: Box::new(operand),
1227 }
1228 }
1229 _ => self.parse_postfix(),
1230 }
1231 }
1232
1233 fn parse_postfix(&mut self) -> Expr {
1235 let mut expr = self.parse_primary();
1236
1237 loop {
1238 if self.at(TokenKind::Newline) {
1241 match self.peek_past_newlines_kind() {
1242 Some(TokenKind::Dot) => self.skip_newlines(),
1243 _ => break,
1244 }
1245 }
1246
1247 match self.peek().kind.clone() {
1248 TokenKind::Question => {
1250 let end_span = self.advance().span;
1251 let id = self.alloc_id();
1252 let span = Span::merge(expr.span(), end_span);
1253 expr = Expr::Try {
1254 id,
1255 span,
1256 expr: Box::new(expr),
1257 };
1258 }
1259 TokenKind::Dot => {
1261 match self.peek_kind_at(1) {
1262 Some(TokenKind::Await) => {
1263 let _ = self.advance(); let end_span = self.advance().span; let id = self.alloc_id();
1266 let span = Span::merge(expr.span(), end_span);
1267 expr = Expr::Await {
1268 id,
1269 span,
1270 expr: Box::new(expr),
1271 };
1272 }
1273 Some(TokenKind::Ident) | Some(TokenKind::TypeIdent) => {
1274 let _ = self.advance(); let tok = self.advance(); let field = Ident {
1277 name: tok.literal.unwrap_or_default(),
1278 span: tok.span,
1279 };
1280 let type_args = self.parse_optional_type_args();
1282 if self.at(TokenKind::LParen) {
1283 let _ = self.advance(); let args = self.parse_arg_list();
1285 let _ = self.expect(TokenKind::RParen);
1286 let id = self.alloc_id();
1287 let span = Span::merge(expr.span(), self.peek().span);
1288 expr = Expr::MethodCall {
1289 id,
1290 span,
1291 receiver: Box::new(expr),
1292 method: field,
1293 type_args,
1294 args,
1295 };
1296 } else {
1297 let id = self.alloc_id();
1298 let span = Span::merge(expr.span(), field.span);
1299 expr = Expr::FieldAccess {
1300 id,
1301 span,
1302 object: Box::new(expr),
1303 field,
1304 };
1305 }
1306 }
1307 _ => break,
1308 }
1309 }
1310 TokenKind::LParen => {
1312 let _ = self.advance(); let type_args = Vec::new(); let args = self.parse_arg_list();
1315 let end_span = self
1316 .expect(TokenKind::RParen)
1317 .map(|t| t.span)
1318 .unwrap_or_else(|_| self.peek().span);
1319 let id = self.alloc_id();
1320 let span = Span::merge(expr.span(), end_span);
1321 expr = Expr::Call {
1322 id,
1323 span,
1324 callee: Box::new(expr),
1325 args,
1326 type_args,
1327 };
1328 }
1329 TokenKind::LBracket => {
1331 if Self::expr_is_simple_type_name(&expr)
1337 && self.is_type_args_before_dot()
1338 {
1339 let _ = self.advance(); self.skip_newlines();
1341 while !self.at(TokenKind::RBracket) && !self.at(TokenKind::Eof) {
1342 let _ = self.parse_type_expr();
1343 self.skip_newlines();
1344 if self.at(TokenKind::Comma) {
1345 let _ = self.advance();
1346 self.skip_newlines();
1347 } else {
1348 break;
1349 }
1350 }
1351 let _ = self.expect(TokenKind::RBracket);
1352 continue;
1353 }
1354 let _ = self.advance(); let index = self.parse_expr();
1356 let end_span = self
1357 .expect(TokenKind::RBracket)
1358 .map(|t| t.span)
1359 .unwrap_or_else(|_| self.peek().span);
1360 let id = self.alloc_id();
1361 let span = Span::merge(expr.span(), end_span);
1362 expr = Expr::Index {
1363 id,
1364 span,
1365 object: Box::new(expr),
1366 index: Box::new(index),
1367 };
1368 }
1369 TokenKind::LBrace if self.expr_is_type_path(&expr) => {
1371 let path = self.expr_to_type_path(&expr);
1372 let record = self.parse_record_construct(expr.span(), path);
1373 expr = record;
1374 }
1375 _ => break,
1376 }
1377 }
1378
1379 expr
1380 }
1381
1382 fn expr_is_type_path(&self, expr: &Expr) -> bool {
1391 match expr {
1392 Expr::Identifier { name, .. } => Self::is_type_name(&name.name),
1393 Expr::FieldAccess { object, field, .. } => {
1394 Self::is_type_name(&field.name) && self.expr_is_type_path(object)
1395 }
1396 _ => false,
1397 }
1398 }
1399
1400 fn is_type_name(name: &str) -> bool {
1406 name.starts_with(|c: char| c.is_uppercase())
1407 && (name.len() == 1 || name.contains(|c: char| c.is_lowercase()))
1408 }
1409
1410 fn expr_is_simple_type_name(expr: &Expr) -> bool {
1414 matches!(expr, Expr::Identifier { name, .. } if Self::is_type_name(&name.name))
1415 }
1416
1417 fn is_type_args_before_dot(&self) -> bool {
1422 let mut offset = 1; loop {
1424 while self.peek_kind_at(offset) == Some(TokenKind::Newline) {
1425 offset += 1;
1426 }
1427 match self.peek_kind_at(offset) {
1428 Some(TokenKind::TypeIdent) => offset += 1,
1429 _ => return false,
1430 }
1431 while self.peek_kind_at(offset) == Some(TokenKind::Newline) {
1432 offset += 1;
1433 }
1434 match self.peek_kind_at(offset) {
1435 Some(TokenKind::Comma) => {
1436 offset += 1;
1437 }
1438 Some(TokenKind::RBracket) => {
1439 offset += 1;
1440 if self.peek_kind_at(offset) != Some(TokenKind::Dot) {
1441 return false;
1442 }
1443 offset += 1;
1444 return matches!(
1445 self.peek_kind_at(offset),
1446 Some(TokenKind::Ident) | Some(TokenKind::TypeIdent)
1447 );
1448 }
1449 _ => return false,
1450 }
1451 }
1452 }
1453
1454 fn expr_to_type_path(&self, expr: &Expr) -> TypePath {
1456 match expr {
1457 Expr::Identifier { name, span, .. } => TypePath {
1458 segments: vec![name.clone()],
1459 span: *span,
1460 },
1461 Expr::FieldAccess {
1462 object,
1463 field,
1464 span,
1465 ..
1466 } => {
1467 let mut path = self.expr_to_type_path(object);
1468 path.segments.push(field.clone());
1469 path.span = *span;
1470 path
1471 }
1472 _ => TypePath {
1473 segments: vec![],
1474 span: expr.span(),
1475 },
1476 }
1477 }
1478
1479 fn parse_optional_type_args(&mut self) -> Vec<TypeExpr> {
1481 if self.at(TokenKind::LBracket) && !self.is_index_bracket() {
1482 let _ = self.advance(); let mut args = Vec::new();
1484 self.skip_newlines();
1485 while !self.at(TokenKind::RBracket) && !self.at(TokenKind::Eof) {
1486 args.push(self.parse_type_expr());
1487 self.skip_newlines();
1488 if self.at(TokenKind::Comma) {
1489 let _ = self.advance();
1490 self.skip_newlines();
1491 } else {
1492 break;
1493 }
1494 }
1495 let _ = self.expect(TokenKind::RBracket);
1496 args
1497 } else {
1498 Vec::new()
1499 }
1500 }
1501
1502 fn is_index_bracket(&self) -> bool {
1508 let mut offset = 1; loop {
1511 while self.peek_kind_at(offset) == Some(TokenKind::Newline) {
1513 offset += 1;
1514 }
1515
1516 match self.peek_kind_at(offset) {
1518 Some(TokenKind::TypeIdent) => offset += 1,
1519 _ => return true, }
1521
1522 while self.peek_kind_at(offset) == Some(TokenKind::Newline) {
1524 offset += 1;
1525 }
1526
1527 match self.peek_kind_at(offset) {
1529 Some(TokenKind::Comma) => offset += 1,
1530 Some(TokenKind::RBracket) => {
1531 offset += 1;
1532 return !matches!(self.peek_kind_at(offset), Some(TokenKind::LParen));
1534 }
1535 _ => return true,
1536 }
1537 }
1538 }
1539
1540 fn parse_arg_list(&mut self) -> Vec<Arg> {
1542 let mut args = Vec::new();
1543 self.skip_newlines();
1544
1545 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
1546 let start = self.peek().span;
1547
1548 let mutable = if self.at(TokenKind::Mut) {
1550 let _ = self.advance();
1551 true
1552 } else {
1553 false
1554 };
1555
1556 let (label, value) =
1558 if self.at(TokenKind::Ident) && self.peek_kind_at(1) == Some(TokenKind::Colon) {
1559 let tok = self.advance();
1560 let label = Ident {
1561 name: tok.literal.unwrap_or_default(),
1562 span: tok.span,
1563 };
1564 let _ = self.advance(); let value = self.parse_expr();
1566 (Some(label), value)
1567 } else {
1568 let value = self.parse_expr();
1569 (None, value)
1570 };
1571
1572 let end = value.span();
1573 args.push(Arg {
1574 span: Span::merge(start, end),
1575 label,
1576 mutable,
1577 value,
1578 });
1579
1580 self.skip_newlines();
1581 if self.at(TokenKind::Comma) {
1582 let _ = self.advance();
1583 self.skip_newlines();
1584 } else {
1585 break;
1586 }
1587 }
1588
1589 args
1590 }
1591
1592 fn parse_record_construct(&mut self, start: Span, path: TypePath) -> Expr {
1594 let _ = self.advance(); let mut fields = Vec::new();
1596 let mut spread = None;
1597
1598 self.skip_newlines();
1599 while !self.at(TokenKind::RBrace) && !self.at(TokenKind::Eof) {
1600 if self.at(TokenKind::DotDot) {
1602 let spread_start = self.advance().span; let expr = self.parse_expr();
1604 let span = Span::merge(spread_start, expr.span());
1605 spread = Some(Box::new(RecordSpread { span, expr }));
1606 self.skip_newlines();
1607 break;
1608 }
1609
1610 let field_span = self.peek().span;
1612 if !self.at(TokenKind::Ident) {
1613 break;
1614 }
1615 let tok = self.advance();
1616 let name = Ident {
1617 name: tok.literal.unwrap_or_default(),
1618 span: tok.span,
1619 };
1620
1621 let value = if self.at(TokenKind::Colon) {
1622 let _ = self.advance(); Some(self.parse_expr())
1624 } else {
1625 None };
1627
1628 let field_end = value.as_ref().map(|v| v.span()).unwrap_or(field_span);
1629 fields.push(RecordField {
1630 span: Span::merge(field_span, field_end),
1631 name,
1632 value,
1633 });
1634
1635 self.skip_newlines();
1636 if self.at(TokenKind::Comma) {
1637 let _ = self.advance();
1638 self.skip_newlines();
1639 }
1640 }
1641
1642 let end_span = self
1643 .expect(TokenKind::RBrace)
1644 .map(|t| t.span)
1645 .unwrap_or(start);
1646 let id = self.alloc_id();
1647 Expr::RecordConstruct {
1648 id,
1649 span: Span::merge(start, end_span),
1650 path,
1651 fields,
1652 spread,
1653 }
1654 }
1655
1656 fn parse_primary(&mut self) -> Expr {
1659 let id = self.alloc_id();
1660 let span = self.peek().span;
1661
1662 match self.peek().kind.clone() {
1663 TokenKind::IntLiteral => {
1665 let tok = self.advance();
1666 Expr::Literal {
1667 id,
1668 span,
1669 lit: Literal::Int(tok.literal.unwrap_or_default()),
1670 }
1671 }
1672 TokenKind::FloatLiteral => {
1673 let tok = self.advance();
1674 Expr::Literal {
1675 id,
1676 span,
1677 lit: Literal::Float(tok.literal.unwrap_or_default()),
1678 }
1679 }
1680 TokenKind::StringLiteral
1681 | TokenKind::RawStringLiteral
1682 | TokenKind::MultiLineStringLiteral
1683 | TokenKind::RawMultiLineStringLiteral => {
1684 let tok = self.advance();
1685 Expr::Literal {
1686 id,
1687 span,
1688 lit: Literal::String(tok.literal.unwrap_or_default()),
1689 }
1690 }
1691 TokenKind::BoolLiteral => {
1692 let tok = self.advance();
1693 let value = self.source.slice(tok.span) == "true";
1695 Expr::Literal {
1696 id,
1697 span,
1698 lit: Literal::Bool(value),
1699 }
1700 }
1701 TokenKind::CharLiteral => {
1702 let tok = self.advance();
1703 Expr::Literal {
1704 id,
1705 span,
1706 lit: Literal::Char(tok.literal.unwrap_or_default()),
1707 }
1708 }
1709 TokenKind::StringLiteralPart | TokenKind::InterpolationStart => {
1711 self.parse_interpolation(id, span)
1712 }
1713 TokenKind::Ident => {
1715 let tok = self.advance();
1716 let name = Ident {
1717 name: tok.literal.unwrap_or_default(),
1718 span: tok.span,
1719 };
1720 Expr::Identifier {
1721 id,
1722 span: tok.span,
1723 name,
1724 }
1725 }
1726 TokenKind::TypeIdent
1727 | TokenKind::Ok_
1728 | TokenKind::Err_
1729 | TokenKind::Some_
1730 | TokenKind::None_ => {
1731 let tok = self.advance();
1732 let name = Ident {
1734 name: tok.literal.unwrap_or_else(|| tok.kind.to_string()),
1735 span: tok.span,
1736 };
1737 Expr::Identifier {
1738 id,
1739 span: tok.span,
1740 name,
1741 }
1742 }
1743 TokenKind::SelfLower => {
1744 let tok = self.advance();
1745 let name = Ident {
1746 name: "self".into(),
1747 span: tok.span,
1748 };
1749 Expr::Identifier {
1750 id,
1751 span: tok.span,
1752 name,
1753 }
1754 }
1755 TokenKind::SelfUpper => {
1756 let tok = self.advance();
1757 let name = Ident {
1758 name: "Self".into(),
1759 span: tok.span,
1760 };
1761 Expr::Identifier {
1762 id,
1763 span: tok.span,
1764 name,
1765 }
1766 }
1767 TokenKind::Underscore => {
1769 let _ = self.advance();
1770 Expr::Placeholder { id, span }
1771 }
1772 TokenKind::Unreachable => {
1774 let _ = self.advance();
1775 if self.at(TokenKind::LParen) {
1777 if let Some(next) = self.tokens.get(self.pos + 1) {
1778 if next.kind == TokenKind::RParen {
1779 let _ = self.advance(); let _ = self.advance(); }
1782 }
1783 }
1784 Expr::Unreachable { id, span }
1785 }
1786 TokenKind::Return => {
1788 let _ = self.advance();
1789 let value = if !self.at_stmt_terminator() {
1790 Some(Box::new(self.parse_expr()))
1791 } else {
1792 None
1793 };
1794 let end = value.as_ref().map(|v| v.span()).unwrap_or(span);
1795 Expr::Return {
1796 id,
1797 span: Span::merge(span, end),
1798 value,
1799 }
1800 }
1801 TokenKind::Break => {
1803 let _ = self.advance();
1804 let value = if !self.at_stmt_terminator() {
1805 Some(Box::new(self.parse_expr()))
1806 } else {
1807 None
1808 };
1809 let end = value.as_ref().map(|v| v.span()).unwrap_or(span);
1810 Expr::Break {
1811 id,
1812 span: Span::merge(span, end),
1813 value,
1814 }
1815 }
1816 TokenKind::Continue => {
1818 let _ = self.advance();
1819 Expr::Continue { id, span }
1820 }
1821 TokenKind::Await => {
1823 let _ = self.advance();
1824 let inner = self.parse_unary();
1825 let end = inner.span();
1826 Expr::Await {
1827 id,
1828 span: Span::merge(span, end),
1829 expr: Box::new(inner),
1830 }
1831 }
1832 TokenKind::If => self.parse_if_expr(),
1834 TokenKind::Match => self.parse_match_expr(),
1836 TokenKind::Loop => self.parse_loop_expr(),
1838 TokenKind::LParen => {
1840 if self.is_lambda_start() {
1841 self.parse_lambda()
1842 } else {
1843 self.parse_paren_or_tuple()
1844 }
1845 }
1846 TokenKind::LBracket => self.parse_list_literal(),
1848 TokenKind::Hash => {
1850 if self.peek_kind_at(1) == Some(TokenKind::LBrace) {
1851 self.parse_set_literal()
1852 } else {
1853 let _ = self.advance();
1855 self.diagnostics.error(
1856 DiagnosticCode {
1857 prefix: 'E',
1858 number: 2022,
1859 },
1860 "expected `{` after `#` for set literal".to_string(),
1861 span,
1862 );
1863 Expr::Literal {
1864 id,
1865 span,
1866 lit: Literal::Unit,
1867 }
1868 }
1869 }
1870 TokenKind::LBrace => {
1872 if self.is_map_literal_start() {
1873 self.parse_map_literal()
1874 } else {
1875 let block = self.parse_block();
1876 let block_span = block.span;
1877 Expr::Block {
1878 id: self.alloc_id(),
1879 span: block_span,
1880 block,
1881 }
1882 }
1883 }
1884 _ => {
1885 self.diagnostics.error(
1886 DiagnosticCode {
1887 prefix: 'E',
1888 number: 2020,
1889 },
1890 format!("expected expression, found `{}`", self.peek().kind),
1891 span,
1892 );
1893 if !self.at(TokenKind::Eof) {
1895 let _ = self.advance();
1896 }
1897 Expr::Literal {
1898 id,
1899 span,
1900 lit: Literal::Unit,
1901 }
1902 }
1903 }
1904 }
1905
1906 fn parse_interpolation(&mut self, id: NodeId, span: Span) -> Expr {
1908 let mut parts = Vec::new();
1909 let mut end = span;
1910
1911 loop {
1912 match self.peek().kind.clone() {
1913 TokenKind::StringLiteralPart => {
1914 let tok = self.advance();
1915 end = tok.span;
1916 parts.push(InterpolationPart::Literal(tok.literal.unwrap_or_default()));
1917 }
1918 TokenKind::InterpolationStart => {
1919 let _ = self.advance(); let expr = self.parse_expr();
1921 end = expr.span();
1922 parts.push(InterpolationPart::Expr(expr));
1923 if self.at(TokenKind::InterpolationEnd) || self.at(TokenKind::RBrace) {
1925 end = self.advance().span;
1926 }
1927 }
1928 _ => break,
1929 }
1930 }
1931
1932 Expr::Interpolation {
1933 id,
1934 span: Span::merge(span, end),
1935 parts,
1936 }
1937 }
1938
1939 fn is_lambda_start(&self) -> bool {
1941 let mut i = self.pos + 1; let mut depth = 1usize;
1944
1945 while i < self.tokens.len() {
1946 match &self.tokens[i].kind {
1947 TokenKind::LParen => depth += 1,
1948 TokenKind::RParen => {
1949 depth -= 1;
1950 if depth == 0 {
1951 i += 1;
1952 break;
1953 }
1954 }
1955 TokenKind::Eof => return false,
1956 _ => {}
1957 }
1958 i += 1;
1959 }
1960
1961 while i < self.tokens.len() && self.tokens[i].kind == TokenKind::Newline {
1963 i += 1;
1964 }
1965
1966 matches!(
1967 self.tokens.get(i).map(|t| &t.kind),
1968 Some(TokenKind::FatArrow)
1969 )
1970 }
1971
1972 fn parse_lambda(&mut self) -> Expr {
1974 let start = self.peek().span;
1975 let _ = self.advance(); let params = self.parse_lambda_param_list();
1977 let _ = self.expect(TokenKind::RParen);
1978 let _ = self.expect(TokenKind::FatArrow);
1979
1980 let body = if self.at(TokenKind::LBrace) {
1982 let block = self.parse_block();
1983 let bspan = block.span;
1984 Expr::Block {
1985 id: self.alloc_id(),
1986 span: bspan,
1987 block,
1988 }
1989 } else {
1990 self.parse_expr()
1991 };
1992
1993 let id = self.alloc_id();
1994 let span = Span::merge(start, body.span());
1995 Expr::Lambda {
1996 id,
1997 span,
1998 params,
1999 body: Box::new(body),
2000 }
2001 }
2002
2003 fn parse_lambda_param_list(&mut self) -> Vec<Param> {
2005 let mut params = Vec::new();
2006 self.skip_newlines();
2007
2008 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
2009 let id = self.alloc_id();
2010 let start = self.peek().span;
2011
2012 let pattern = match self.peek().kind.clone() {
2013 TokenKind::Ident => {
2014 let tok = self.advance();
2015 let span = tok.span;
2016 Pattern::Bind {
2017 id: self.alloc_id(),
2018 span,
2019 name: Ident {
2020 name: tok.literal.unwrap_or_default(),
2021 span,
2022 },
2023 }
2024 }
2025 TokenKind::Underscore => {
2026 let tok = self.advance();
2027 Pattern::Wildcard {
2028 id: self.alloc_id(),
2029 span: tok.span,
2030 }
2031 }
2032 TokenKind::Mut => {
2033 let _ = self.advance(); let tok = if self.at(TokenKind::Ident) {
2035 self.advance()
2036 } else {
2037 return params; };
2039 let span = tok.span;
2040 Pattern::MutBind {
2041 id: self.alloc_id(),
2042 span,
2043 name: Ident {
2044 name: tok.literal.unwrap_or_default(),
2045 span,
2046 },
2047 }
2048 }
2049 _ => break,
2050 };
2051
2052 let ty = if self.at(TokenKind::Colon) {
2053 let _ = self.advance();
2054 Some(self.parse_type_expr())
2055 } else {
2056 None
2057 };
2058
2059 let end = self.peek().span;
2060 params.push(Param {
2061 id,
2062 span: Span::merge(start, end),
2063 pattern,
2064 ty,
2065 default: None,
2066 });
2067
2068 self.skip_newlines();
2069 if self.at(TokenKind::Comma) {
2070 let _ = self.advance();
2071 self.skip_newlines();
2072 } else {
2073 break;
2074 }
2075 }
2076
2077 params
2078 }
2079
2080 fn parse_paren_or_tuple(&mut self) -> Expr {
2082 let start = self.peek().span;
2083 let _ = self.advance(); self.skip_newlines();
2086
2087 if self.at(TokenKind::RParen) {
2089 let end = self.advance().span;
2090 let id = self.alloc_id();
2091 return Expr::Literal {
2092 id,
2093 span: Span::merge(start, end),
2094 lit: Literal::Unit,
2095 };
2096 }
2097
2098 let first = self.parse_expr();
2099 self.skip_newlines();
2100
2101 if self.at(TokenKind::Comma) {
2102 let mut elems = vec![first];
2104 while self.at(TokenKind::Comma) {
2105 let _ = self.advance();
2106 self.skip_newlines();
2107 if self.at(TokenKind::RParen) {
2108 break;
2109 }
2110 elems.push(self.parse_expr());
2111 self.skip_newlines();
2112 }
2113 let end = self
2114 .expect(TokenKind::RParen)
2115 .map(|t| t.span)
2116 .unwrap_or(start);
2117 let id = self.alloc_id();
2118 Expr::TupleLiteral {
2119 id,
2120 span: Span::merge(start, end),
2121 elems,
2122 }
2123 } else {
2124 let end = self
2126 .expect(TokenKind::RParen)
2127 .map(|t| t.span)
2128 .unwrap_or(start);
2129 let mut e = first;
2130 if let Some(new_span) = Some(Span::merge(start, end)) {
2132 match &mut e {
2133 Expr::Literal { span, .. }
2134 | Expr::Identifier { span, .. }
2135 | Expr::Binary { span, .. }
2136 | Expr::Unary { span, .. } => *span = new_span,
2137 _ => {}
2138 }
2139 }
2140 e
2141 }
2142 }
2143
2144 fn parse_list_literal(&mut self) -> Expr {
2146 let start = self.peek().span;
2147 let _ = self.advance(); let mut elems = Vec::new();
2149 self.skip_newlines();
2150
2151 while !self.at(TokenKind::RBracket) && !self.at(TokenKind::Eof) {
2152 elems.push(self.parse_expr());
2153 self.skip_newlines();
2154 if self.at(TokenKind::Comma) {
2155 let _ = self.advance();
2156 self.skip_newlines();
2157 } else {
2158 break;
2159 }
2160 }
2161
2162 let end = self
2163 .expect(TokenKind::RBracket)
2164 .map(|t| t.span)
2165 .unwrap_or(start);
2166 let id = self.alloc_id();
2167 Expr::ListLiteral {
2168 id,
2169 span: Span::merge(start, end),
2170 elems,
2171 }
2172 }
2173
2174 fn parse_set_literal(&mut self) -> Expr {
2176 let start = self.peek().span;
2177 let _ = self.advance(); let _ = self.advance(); let mut elems = Vec::new();
2180 self.skip_newlines();
2181
2182 while !self.at(TokenKind::RBrace) && !self.at(TokenKind::Eof) {
2183 elems.push(self.parse_expr());
2184 self.skip_newlines();
2185 if self.at(TokenKind::Comma) {
2186 let _ = self.advance();
2187 self.skip_newlines();
2188 } else {
2189 break;
2190 }
2191 }
2192
2193 let end = self
2194 .expect(TokenKind::RBrace)
2195 .map(|t| t.span)
2196 .unwrap_or(start);
2197 let id = self.alloc_id();
2198 Expr::SetLiteral {
2199 id,
2200 span: Span::merge(start, end),
2201 elems,
2202 }
2203 }
2204
2205 fn is_empty_brace(&self) -> bool {
2208 if self.peek().kind != TokenKind::LBrace {
2209 return false;
2210 }
2211 let mut i = self.pos + 1;
2212 while i < self.tokens.len() && self.tokens[i].kind == TokenKind::Newline {
2213 i += 1;
2214 }
2215 i < self.tokens.len() && self.tokens[i].kind == TokenKind::RBrace
2216 }
2217
2218 fn is_map_type_annotation(ty: &Option<TypeExpr>) -> bool {
2220 matches!(ty, Some(TypeExpr::Named { path, .. })
2221 if path.segments.last().map(|s| s.name.as_str()) == Some("Map"))
2222 }
2223
2224 fn is_map_literal_start(&self) -> bool {
2226 let mut i = self.pos + 1;
2228 while i < self.tokens.len() && self.tokens[i].kind == TokenKind::Newline {
2229 i += 1;
2230 }
2231 if i >= self.tokens.len() {
2232 return false;
2233 }
2234 let is_map_key_start = matches!(
2236 &self.tokens[i].kind,
2237 TokenKind::StringLiteral
2238 | TokenKind::RawStringLiteral
2239 | TokenKind::RawMultiLineStringLiteral
2240 | TokenKind::IntLiteral
2241 | TokenKind::FloatLiteral
2242 | TokenKind::Ident
2243 | TokenKind::TypeIdent
2244 );
2245 if !is_map_key_start || i + 1 >= self.tokens.len() {
2246 return false;
2247 }
2248 self.tokens[i + 1].kind == TokenKind::Colon
2249 }
2250
2251 fn parse_map_literal(&mut self) -> Expr {
2253 let start = self.peek().span;
2254 let _ = self.advance(); let mut entries = Vec::new();
2256 self.skip_newlines();
2257
2258 while !self.at(TokenKind::RBrace) && !self.at(TokenKind::Eof) {
2259 let key = self.parse_expr();
2260 let _ = self.expect(TokenKind::Colon);
2261 let val = self.parse_expr();
2262 entries.push((key, val));
2263 self.skip_newlines();
2264 if self.at(TokenKind::Comma) {
2265 let _ = self.advance();
2266 self.skip_newlines();
2267 } else {
2268 break;
2269 }
2270 }
2271
2272 let end = self
2273 .expect(TokenKind::RBrace)
2274 .map(|t| t.span)
2275 .unwrap_or(start);
2276 let id = self.alloc_id();
2277 Expr::MapLiteral {
2278 id,
2279 span: Span::merge(start, end),
2280 entries,
2281 }
2282 }
2283
2284 fn parse_if_expr(&mut self) -> Expr {
2286 let start = self.peek().span;
2287 let _ = self.advance(); let _ = self.expect(TokenKind::LParen);
2290
2291 let (let_pattern, condition) = if self.at(TokenKind::Let) {
2293 let _ = self.advance(); let pat = self.parse_pattern();
2295 let _ = self.expect(TokenKind::Assign);
2296 let cond = self.parse_expr();
2297 (Some(pat), cond)
2298 } else {
2299 (None, self.parse_expr())
2300 };
2301
2302 let _ = self.expect(TokenKind::RParen);
2303 self.skip_newlines();
2304
2305 let then_block = self.parse_block();
2306
2307 if self.at(TokenKind::Newline)
2310 && self.peek_past_newlines_kind() == Some(TokenKind::Else)
2311 {
2312 self.skip_newlines();
2313 }
2314
2315 let else_block = if self.at(TokenKind::Else) {
2317 let _ = self.advance(); self.skip_newlines();
2319 if self.at(TokenKind::If) {
2320 Some(Box::new(self.parse_if_expr()))
2322 } else {
2323 let block = self.parse_block();
2324 let bspan = block.span;
2325 Some(Box::new(Expr::Block {
2326 id: self.alloc_id(),
2327 span: bspan,
2328 block,
2329 }))
2330 }
2331 } else {
2332 None
2333 };
2334
2335 let end = else_block
2336 .as_ref()
2337 .map(|e| e.span())
2338 .unwrap_or(then_block.span);
2339 let id = self.alloc_id();
2340 Expr::If {
2341 id,
2342 span: Span::merge(start, end),
2343 let_pattern,
2344 condition: Box::new(condition),
2345 then_block,
2346 else_block,
2347 }
2348 }
2349
2350 fn parse_match_expr(&mut self) -> Expr {
2352 let start = self.peek().span;
2353 let _ = self.advance(); let scrutinee = self.parse_expr();
2356 self.skip_newlines();
2357
2358 let _ = self.expect(TokenKind::LBrace);
2359 let mut arms = Vec::new();
2360
2361 loop {
2362 self.skip_newlines();
2363 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
2364 break;
2365 }
2366 let arm_start = self.peek().span;
2368 let pattern = self.parse_pattern();
2369
2370 let guard = if self.at(TokenKind::If) {
2372 let _ = self.advance(); let _ = self.expect(TokenKind::LParen);
2374 let g = self.parse_expr();
2375 let _ = self.expect(TokenKind::RParen);
2376 Some(g)
2377 } else {
2378 None
2379 };
2380
2381 let _ = self.expect(TokenKind::FatArrow);
2382 self.skip_newlines();
2383
2384 let body = if self.at(TokenKind::LBrace) {
2386 let block = self.parse_block();
2387 let bspan = block.span;
2388 Expr::Block {
2389 id: self.alloc_id(),
2390 span: bspan,
2391 block,
2392 }
2393 } else {
2394 self.parse_expr()
2395 };
2396
2397 let arm_end = body.span();
2398 arms.push(MatchArm {
2399 id: self.alloc_id(),
2400 span: Span::merge(arm_start, arm_end),
2401 pattern,
2402 guard,
2403 body,
2404 });
2405
2406 self.skip_newlines();
2407 if self.at(TokenKind::Comma) {
2409 let _ = self.advance();
2410 }
2411 }
2412
2413 let end = self
2414 .expect(TokenKind::RBrace)
2415 .map(|t| t.span)
2416 .unwrap_or(start);
2417 let id = self.alloc_id();
2418 Expr::Match {
2419 id,
2420 span: Span::merge(start, end),
2421 scrutinee: Box::new(scrutinee),
2422 arms,
2423 }
2424 }
2425
2426 pub(crate) fn parse_pattern(&mut self) -> Pattern {
2428 let first = self.parse_simple_pattern();
2430
2431 if self.at(TokenKind::BitOr) {
2432 let start = first.span();
2433 let mut alternatives = vec![first];
2434 while self.at(TokenKind::BitOr) {
2435 let _ = self.advance(); self.skip_newlines();
2437 alternatives.push(self.parse_simple_pattern());
2438 }
2439 let end = alternatives.last().map(|p| p.span()).unwrap_or(start);
2440 Pattern::Or {
2441 id: self.alloc_id(),
2442 span: Span::merge(start, end),
2443 alternatives,
2444 }
2445 } else {
2446 first
2447 }
2448 }
2449
2450 fn parse_simple_pattern(&mut self) -> Pattern {
2452 let id = self.alloc_id();
2453 let span = self.peek().span;
2454
2455 match self.peek().kind.clone() {
2456 TokenKind::Underscore => {
2458 let _ = self.advance();
2459 Pattern::Wildcard { id, span }
2460 }
2461 TokenKind::Mut => {
2463 let _ = self.advance(); let tok = if self.at(TokenKind::Ident) {
2465 self.advance()
2466 } else {
2467 return Pattern::Wildcard { id, span };
2468 };
2469 let name = Ident {
2470 name: tok.literal.unwrap_or_default(),
2471 span: tok.span,
2472 };
2473 Pattern::MutBind {
2474 id,
2475 span: Span::merge(span, tok.span),
2476 name,
2477 }
2478 }
2479 TokenKind::DotDot => {
2481 let _ = self.advance();
2482 Pattern::Rest { id, span }
2483 }
2484 TokenKind::IntLiteral => {
2486 let tok = self.advance();
2487 let lit = Literal::Int(tok.literal.unwrap_or_default());
2488 let pat = Pattern::Literal {
2489 id,
2490 span: tok.span,
2491 lit,
2492 };
2493 self.try_parse_range_pattern(pat)
2495 }
2496 TokenKind::Minus => {
2497 let _ = self.advance();
2499 if self.at(TokenKind::IntLiteral) {
2500 let tok = self.advance();
2501 let lit = Literal::Int(format!("-{}", tok.literal.unwrap_or_default()));
2502 let pat = Pattern::Literal {
2503 id,
2504 span: Span::merge(span, tok.span),
2505 lit,
2506 };
2507 self.try_parse_range_pattern(pat)
2508 } else if self.at(TokenKind::FloatLiteral) {
2509 let tok = self.advance();
2510 let lit = Literal::Float(format!("-{}", tok.literal.unwrap_or_default()));
2511 Pattern::Literal {
2512 id,
2513 span: Span::merge(span, tok.span),
2514 lit,
2515 }
2516 } else {
2517 Pattern::Wildcard { id, span }
2518 }
2519 }
2520 TokenKind::FloatLiteral => {
2521 let tok = self.advance();
2522 Pattern::Literal {
2523 id,
2524 span: tok.span,
2525 lit: Literal::Float(tok.literal.unwrap_or_default()),
2526 }
2527 }
2528 TokenKind::StringLiteral
2529 | TokenKind::RawStringLiteral
2530 | TokenKind::MultiLineStringLiteral
2531 | TokenKind::RawMultiLineStringLiteral => {
2532 let tok = self.advance();
2533 Pattern::Literal {
2534 id,
2535 span: tok.span,
2536 lit: Literal::String(tok.literal.unwrap_or_default()),
2537 }
2538 }
2539 TokenKind::BoolLiteral => {
2540 let tok = self.advance();
2541 let val = self.source.slice(tok.span) == "true";
2542 Pattern::Literal {
2543 id,
2544 span: tok.span,
2545 lit: Literal::Bool(val),
2546 }
2547 }
2548 TokenKind::TypeIdent
2550 | TokenKind::Ok_
2551 | TokenKind::Err_
2552 | TokenKind::Some_
2553 | TokenKind::None_ => {
2554 let tok = self.advance();
2555 let name = tok
2558 .literal
2559 .unwrap_or_else(|| tok.kind.to_string());
2560 let path_name = Ident {
2561 name,
2562 span: tok.span,
2563 };
2564 let path = TypePath {
2565 segments: vec![path_name],
2566 span: tok.span,
2567 };
2568
2569 if self.at(TokenKind::LParen) {
2570 let _ = self.advance();
2572 let mut fields = Vec::new();
2573 self.skip_newlines();
2574 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
2575 fields.push(self.parse_pattern());
2576 self.skip_newlines();
2577 if self.at(TokenKind::Comma) {
2578 let _ = self.advance();
2579 self.skip_newlines();
2580 } else {
2581 break;
2582 }
2583 }
2584 let end = self
2585 .expect(TokenKind::RParen)
2586 .map(|t| t.span)
2587 .unwrap_or(span);
2588 Pattern::Constructor {
2589 id,
2590 span: Span::merge(span, end),
2591 path,
2592 fields,
2593 }
2594 } else if self.at(TokenKind::LBrace) {
2595 let _ = self.advance();
2597 let mut fields = Vec::new();
2598 let mut rest = false;
2599 self.skip_newlines();
2600 while !self.at(TokenKind::RBrace) && !self.at(TokenKind::Eof) {
2601 if self.at(TokenKind::DotDot) {
2602 let _ = self.advance(); rest = true;
2604 self.skip_newlines();
2605 break;
2606 } else if self.at(TokenKind::Ident) {
2607 let ftok = self.advance();
2608 let fname = Ident {
2609 name: ftok.literal.unwrap_or_default(),
2610 span: ftok.span,
2611 };
2612 let fpat = if self.at(TokenKind::Colon) {
2613 let _ = self.advance();
2614 Some(self.parse_pattern())
2615 } else {
2616 None };
2618 fields.push(RecordPatternField {
2619 span: fname.span,
2620 name: fname,
2621 pattern: fpat,
2622 });
2623 } else {
2624 break;
2625 }
2626 self.skip_newlines();
2627 if self.at(TokenKind::Comma) {
2628 let _ = self.advance();
2629 self.skip_newlines();
2630 } else {
2631 break;
2632 }
2633 }
2634 let end = self
2635 .expect(TokenKind::RBrace)
2636 .map(|t| t.span)
2637 .unwrap_or(span);
2638 Pattern::Record {
2639 id,
2640 span: Span::merge(span, end),
2641 path,
2642 fields,
2643 rest,
2644 }
2645 } else {
2646 Pattern::Constructor {
2648 id,
2649 span: path.span,
2650 path,
2651 fields: vec![],
2652 }
2653 }
2654 }
2655 TokenKind::Ident => {
2657 let tok = self.advance();
2658 let name = Ident {
2659 name: tok.literal.unwrap_or_default(),
2660 span: tok.span,
2661 };
2662 Pattern::Bind {
2663 id,
2664 span: tok.span,
2665 name,
2666 }
2667 }
2668 TokenKind::LParen => {
2670 let _ = self.advance();
2671 let mut elems = Vec::new();
2672 self.skip_newlines();
2673 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
2674 elems.push(self.parse_pattern());
2675 self.skip_newlines();
2676 if self.at(TokenKind::Comma) {
2677 let _ = self.advance();
2678 self.skip_newlines();
2679 } else {
2680 break;
2681 }
2682 }
2683 let end = self
2684 .expect(TokenKind::RParen)
2685 .map(|t| t.span)
2686 .unwrap_or(span);
2687 if elems.len() == 1 {
2688 elems.remove(0) } else {
2690 Pattern::Tuple {
2691 id,
2692 span: Span::merge(span, end),
2693 elems,
2694 }
2695 }
2696 }
2697 TokenKind::LBracket => {
2699 let _ = self.advance();
2700 let mut elems = Vec::new();
2701 let mut rest = None;
2702 self.skip_newlines();
2703
2704 while !self.at(TokenKind::RBracket) && !self.at(TokenKind::Eof) {
2705 if self.at(TokenKind::DotDot) {
2706 let rest_start = self.peek().span;
2707 let _ = self.advance(); if self.at(TokenKind::Ident) {
2709 let tok = self.advance();
2710 let name = Ident {
2711 name: tok.literal.unwrap_or_default(),
2712 span: tok.span,
2713 };
2714 rest = Some(Box::new(Pattern::Bind {
2715 id: self.alloc_id(),
2716 span: Span::merge(rest_start, tok.span),
2717 name,
2718 }));
2719 } else {
2720 rest = Some(Box::new(Pattern::Rest {
2721 id: self.alloc_id(),
2722 span: rest_start,
2723 }));
2724 }
2725 self.skip_newlines();
2726 break;
2727 }
2728 elems.push(self.parse_pattern());
2729 self.skip_newlines();
2730 if self.at(TokenKind::Comma) {
2731 let _ = self.advance();
2732 self.skip_newlines();
2733 } else {
2734 break;
2735 }
2736 }
2737
2738 let end = self
2739 .expect(TokenKind::RBracket)
2740 .map(|t| t.span)
2741 .unwrap_or(span);
2742 Pattern::List {
2743 id,
2744 span: Span::merge(span, end),
2745 elems,
2746 rest,
2747 }
2748 }
2749 _ => {
2750 self.diagnostics.error(
2751 DiagnosticCode {
2752 prefix: 'E',
2753 number: 2021,
2754 },
2755 format!("expected pattern, found `{}`", self.peek().kind),
2756 span,
2757 );
2758 if !self.at(TokenKind::Eof) {
2759 let _ = self.advance();
2760 }
2761 Pattern::Wildcard { id, span }
2762 }
2763 }
2764 }
2765
2766 fn try_parse_range_pattern(&mut self, lo: Pattern) -> Pattern {
2768 if self.at(TokenKind::DotDot) || self.at(TokenKind::DotDotEq) {
2769 let inclusive = self.at(TokenKind::DotDotEq);
2770 let _ = self.advance();
2771 let hi = self.parse_simple_pattern();
2772 let span = Span::merge(lo.span(), hi.span());
2773 Pattern::Range {
2774 id: self.alloc_id(),
2775 span,
2776 lo: Box::new(lo),
2777 hi: Box::new(hi),
2778 inclusive,
2779 }
2780 } else {
2781 lo
2782 }
2783 }
2784
2785 fn at_stmt_terminator(&self) -> bool {
2787 matches!(
2788 self.peek().kind,
2789 TokenKind::Newline | TokenKind::Semicolon | TokenKind::RBrace | TokenKind::Eof
2790 )
2791 }
2792
2793 fn parse_block(&mut self) -> Block {
2797 let start = self.peek().span;
2798 if self.expect(TokenKind::LBrace).is_err() {
2799 return Block {
2800 id: self.alloc_id(),
2801 span: start,
2802 stmts: vec![],
2803 tail: None,
2804 };
2805 }
2806
2807 let mut stmts = Vec::new();
2808 let mut tail: Option<Box<Expr>> = None;
2809
2810 loop {
2811 self.skip_newlines();
2812 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
2813 break;
2814 }
2815 if self.at(TokenKind::Semicolon) {
2817 let _ = self.advance();
2818 continue;
2819 }
2820
2821 let _stmt_start = self.peek().span;
2822
2823 match self.peek().kind.clone() {
2825 TokenKind::Let => {
2826 stmts.push(Stmt::Let(self.parse_let_stmt()));
2827 self.skip_newlines();
2828 continue;
2829 }
2830 TokenKind::For => {
2831 stmts.push(Stmt::For(self.parse_for_loop()));
2832 self.skip_newlines();
2833 continue;
2834 }
2835 TokenKind::While => {
2836 stmts.push(Stmt::While(self.parse_while_loop()));
2837 self.skip_newlines();
2838 continue;
2839 }
2840 TokenKind::Loop => {
2841 let expr = self.parse_loop_expr();
2842 self.skip_newlines();
2843 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
2844 tail = Some(Box::new(expr));
2845 break;
2846 }
2847 stmts.push(Stmt::Expr(expr));
2848 continue;
2849 }
2850 TokenKind::Guard => {
2851 stmts.push(Stmt::Guard(self.parse_guard_stmt()));
2852 self.skip_newlines();
2853 continue;
2854 }
2855 TokenKind::Handling => {
2856 stmts.push(Stmt::Handling(self.parse_handling_block()));
2857 self.skip_newlines();
2858 continue;
2859 }
2860 _ => {}
2861 }
2862
2863 let expr = self.parse_expr();
2865
2866 self.skip_newlines();
2869
2870 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
2871 tail = Some(Box::new(expr));
2873 break;
2874 }
2875
2876 if self.at(TokenKind::Semicolon) {
2878 let _ = self.advance();
2879 }
2880
2881 stmts.push(Stmt::Expr(expr));
2882 }
2883
2884 let fallback_end = stmts
2885 .last()
2886 .map(|s| match s {
2887 Stmt::Expr(e) => e.span(),
2888 Stmt::Let(l) => l.span,
2889 _ => start,
2890 })
2891 .or_else(|| tail.as_ref().map(|t| t.span()))
2892 .unwrap_or(start);
2893 let end = self
2894 .expect(TokenKind::RBrace)
2895 .map(|t| t.span)
2896 .unwrap_or(fallback_end);
2897 Block {
2898 id: self.alloc_id(),
2899 span: Span::merge(start, end),
2900 stmts,
2901 tail,
2902 }
2903 }
2904
2905 fn parse_let_stmt(&mut self) -> LetStmt {
2907 let id = self.alloc_id();
2908 let start = self.peek().span;
2909 let _ = self.advance(); let pattern = if self.at(TokenKind::Mut) {
2912 let mut_span = self.advance().span; if self.at(TokenKind::Ident) {
2914 let tok = self.advance();
2915 let name = Ident {
2916 name: tok.literal.unwrap_or_default(),
2917 span: tok.span,
2918 };
2919 Pattern::MutBind {
2920 id: self.alloc_id(),
2921 span: Span::merge(mut_span, tok.span),
2922 name,
2923 }
2924 } else {
2925 self.parse_pattern()
2926 }
2927 } else {
2928 self.parse_pattern()
2929 };
2930
2931 let ty = if self.at(TokenKind::Colon) {
2932 let _ = self.advance();
2933 Some(self.parse_type_expr())
2934 } else {
2935 None
2936 };
2937
2938 let _ = self.expect(TokenKind::Assign);
2939 let value = if self.is_empty_brace() && Self::is_map_type_annotation(&ty) {
2940 let open = self.advance().span; self.skip_newlines();
2943 let close_span = self
2944 .expect(TokenKind::RBrace)
2945 .map(|t| t.span)
2946 .unwrap_or(open);
2947 Expr::MapLiteral {
2948 id: self.alloc_id(),
2949 span: Span::merge(open, close_span),
2950 entries: vec![],
2951 }
2952 } else {
2953 self.parse_expr()
2954 };
2955 let end = value.span();
2956
2957 LetStmt {
2958 id,
2959 span: Span::merge(start, end),
2960 pattern,
2961 ty,
2962 value,
2963 }
2964 }
2965
2966 fn parse_for_loop(&mut self) -> ForLoop {
2968 let id = self.alloc_id();
2969 let start = self.peek().span;
2970 let _ = self.advance(); let pattern = self.parse_pattern();
2973 let _ = self.expect(TokenKind::In);
2974 let iterable = self.parse_expr();
2975 self.skip_newlines();
2976 let body = self.parse_block();
2977
2978 let end = body.span;
2979 ForLoop {
2980 id,
2981 span: Span::merge(start, end),
2982 pattern,
2983 iterable,
2984 body,
2985 }
2986 }
2987
2988 fn parse_while_loop(&mut self) -> WhileLoop {
2990 let id = self.alloc_id();
2991 let start = self.peek().span;
2992 let _ = self.advance(); let _ = self.expect(TokenKind::LParen);
2995 let condition = self.parse_expr();
2996 let _ = self.expect(TokenKind::RParen);
2997 self.skip_newlines();
2998 let body = self.parse_block();
2999
3000 let end = body.span;
3001 WhileLoop {
3002 id,
3003 span: Span::merge(start, end),
3004 condition,
3005 body,
3006 }
3007 }
3008
3009
3010 fn parse_loop_expr(&mut self) -> Expr {
3012 let id = self.alloc_id();
3013 let start = self.peek().span;
3014 let _ = self.advance(); self.skip_newlines();
3016 let body = self.parse_block();
3017 let end = body.span;
3018 Expr::Loop {
3019 id,
3020 span: Span::merge(start, end),
3021 body,
3022 }
3023 }
3024
3025 fn parse_guard_stmt(&mut self) -> GuardStmt {
3027 let id = self.alloc_id();
3028 let start = self.peek().span;
3029 let _ = self.advance(); let _ = self.expect(TokenKind::LParen);
3031
3032 let (let_pattern, condition) = if self.at(TokenKind::Let) {
3034 let _ = self.advance(); let pat = self.parse_pattern();
3036 let _ = self.expect(TokenKind::Assign);
3037 let cond = self.parse_expr();
3038 (Some(pat), cond)
3039 } else {
3040 (None, self.parse_expr())
3041 };
3042
3043 let _ = self.expect(TokenKind::RParen);
3044 let _ = self.expect(TokenKind::Else);
3045 self.skip_newlines();
3046 let else_block = self.parse_block();
3047 let end = else_block.span;
3048 GuardStmt {
3049 id,
3050 span: Span::merge(start, end),
3051 let_pattern,
3052 condition,
3053 else_block,
3054 }
3055 }
3056
3057 fn parse_handling_block(&mut self) -> HandlingBlock {
3059 let id = self.alloc_id();
3060 let start = self.peek().span;
3061 let _ = self.advance(); let _ = self.expect(TokenKind::LParen);
3063
3064 let mut handlers = Vec::new();
3065 self.skip_newlines();
3066 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
3067 let h_start = self.peek().span;
3068 let effect = self.parse_type_path();
3069 let _ = self.expect(TokenKind::With);
3070 let handler = self.parse_expr();
3071 let h_end = handler.span();
3072 handlers.push(HandlerPair {
3073 span: Span::merge(h_start, h_end),
3074 effect,
3075 handler,
3076 });
3077 self.skip_newlines();
3078 if self.at(TokenKind::Comma) {
3079 let _ = self.advance();
3080 self.skip_newlines();
3081 } else {
3082 break;
3083 }
3084 }
3085 let _ = self.expect(TokenKind::RParen);
3086 self.skip_newlines();
3087 let body = self.parse_block();
3088 let end = body.span;
3089 HandlingBlock {
3090 id,
3091 span: Span::merge(start, end),
3092 handlers,
3093 body,
3094 }
3095 }
3096
3097 fn parse_fn_decl(&mut self, annotations: Vec<Annotation>, vis: Visibility) -> FnDecl {
3105 let start = self.peek().span;
3106
3107 let is_async = if self.at(TokenKind::Async) {
3109 let _ = self.advance();
3110 true
3111 } else {
3112 false
3113 };
3114
3115 let _ = self.expect(TokenKind::Fn); let name_span = self.peek().span;
3119 let name = if self.at(TokenKind::Ident) {
3120 let tok = self.advance();
3121 Ident {
3122 name: tok.literal.unwrap_or_default(),
3123 span: tok.span,
3124 }
3125 } else {
3126 self.diagnostics.error(
3127 DiagnosticCode {
3128 prefix: 'E',
3129 number: 2030,
3130 },
3131 format!("expected function name, found `{}`", self.peek().kind),
3132 name_span,
3133 );
3134 Ident {
3135 name: String::new(),
3136 span: name_span,
3137 }
3138 };
3139
3140 let generic_params = self.parse_generic_params();
3142
3143 let _ = self.expect(TokenKind::LParen);
3145 let params = self.parse_param_list();
3146 let _ = self.expect(TokenKind::RParen);
3147
3148 let return_type = if self.at(TokenKind::ThinArrow) {
3150 let _ = self.advance();
3151 Some(self.parse_type_expr())
3152 } else {
3153 None
3154 };
3155
3156 if self.peek_past_newlines_kind() == Some(TokenKind::With) {
3158 self.skip_newlines();
3159 }
3160 let effect_clause = self.parse_effect_clause();
3161
3162 if self.peek_past_newlines_kind() == Some(TokenKind::Where) {
3164 self.skip_newlines();
3165 }
3166 let where_clause = self.parse_where_clause();
3167
3168 self.skip_newlines();
3169
3170 let body = self.parse_block();
3172 let end = body.span;
3173
3174 FnDecl {
3175 id: self.alloc_id(),
3176 span: Span::merge(start, end),
3177 annotations,
3178 visibility: vis,
3179 is_async,
3180 name,
3181 generic_params,
3182 params,
3183 return_type,
3184 effect_clause,
3185 where_clause,
3186 body: Some(body),
3187 }
3188 }
3189
3190 fn parse_param_list(&mut self) -> Vec<Param> {
3192 let mut params = Vec::new();
3193 self.skip_newlines();
3194
3195 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
3196 params.push(self.parse_param());
3197 self.skip_newlines();
3198 if self.at(TokenKind::Comma) {
3199 let _ = self.advance();
3200 self.skip_newlines();
3201 } else {
3202 break;
3203 }
3204 }
3205
3206 params
3207 }
3208
3209 fn parse_param(&mut self) -> Param {
3211 let id = self.alloc_id();
3212 let start = self.peek().span;
3213
3214 let pattern = match self.peek().kind.clone() {
3216 TokenKind::Mut => {
3217 let _ = self.advance(); match self.peek().kind.clone() {
3219 TokenKind::Ident => {
3220 let tok = self.advance();
3221 let span = tok.span;
3222 Pattern::MutBind {
3223 id: self.alloc_id(),
3224 span,
3225 name: Ident {
3226 name: tok.literal.unwrap_or_default(),
3227 span,
3228 },
3229 }
3230 }
3231 TokenKind::SelfLower => {
3232 let tok = self.advance();
3233 Pattern::MutBind {
3234 id: self.alloc_id(),
3235 span: tok.span,
3236 name: Ident {
3237 name: "self".into(),
3238 span: tok.span,
3239 },
3240 }
3241 }
3242 _ => {
3243 self.diagnostics.error(
3244 DiagnosticCode {
3245 prefix: 'E',
3246 number: 2031,
3247 },
3248 format!("expected parameter name after `mut`, found `{}`", self.peek().kind),
3249 start,
3250 );
3251 Pattern::Wildcard {
3252 id: self.alloc_id(),
3253 span: start,
3254 }
3255 }
3256 }
3257 }
3258 TokenKind::Ident => {
3259 let tok = self.advance();
3260 let span = tok.span;
3261 Pattern::Bind {
3262 id: self.alloc_id(),
3263 span,
3264 name: Ident {
3265 name: tok.literal.unwrap_or_default(),
3266 span,
3267 },
3268 }
3269 }
3270 TokenKind::SelfLower => {
3271 let tok = self.advance();
3272 Pattern::Bind {
3273 id: self.alloc_id(),
3274 span: tok.span,
3275 name: Ident {
3276 name: "self".into(),
3277 span: tok.span,
3278 },
3279 }
3280 }
3281 TokenKind::Underscore => {
3282 let tok = self.advance();
3283 Pattern::Wildcard {
3284 id: self.alloc_id(),
3285 span: tok.span,
3286 }
3287 }
3288 _ => {
3289 self.diagnostics.error(
3290 DiagnosticCode {
3291 prefix: 'E',
3292 number: 2031,
3293 },
3294 format!("expected parameter name, found `{}`", self.peek().kind),
3295 start,
3296 );
3297 Pattern::Wildcard {
3298 id: self.alloc_id(),
3299 span: start,
3300 }
3301 }
3302 };
3303
3304 let ty = if self.at(TokenKind::Colon) {
3306 let _ = self.advance();
3307 Some(self.parse_type_expr())
3308 } else {
3309 None
3310 };
3311
3312 let default = if self.at(TokenKind::Assign) {
3314 let _ = self.advance();
3315 Some(self.parse_expr_stub())
3316 } else {
3317 None
3318 };
3319
3320 let end = self.peek().span;
3321 Param {
3322 id,
3323 span: Span::merge(start, end),
3324 pattern,
3325 ty,
3326 default,
3327 }
3328 }
3329
3330 fn parse_effect_clause(&mut self) -> Vec<TypePath> {
3332 if !self.at(TokenKind::With) {
3333 return Vec::new();
3334 }
3335 let _ = self.advance(); let mut effects = Vec::new();
3338 effects.push(self.parse_type_path());
3339
3340 while self.at(TokenKind::Comma) {
3341 let _ = self.advance();
3342 self.skip_newlines();
3343 effects.push(self.parse_type_path());
3344 }
3345
3346 effects
3347 }
3348
3349 fn parse_type_alias_decl(
3353 &mut self,
3354 annotations: Vec<Annotation>,
3355 vis: Visibility,
3356 ) -> TypeAliasDecl {
3357 let start = self.peek().span;
3358 let _ = self.advance(); let name_span = self.peek().span;
3362 let name = if self.at(TokenKind::TypeIdent) {
3363 let tok = self.advance();
3364 Ident {
3365 name: tok.literal.unwrap_or_default(),
3366 span: tok.span,
3367 }
3368 } else if self.at(TokenKind::Ident) {
3369 let tok = self.advance();
3371 Ident {
3372 name: tok.literal.unwrap_or_default(),
3373 span: tok.span,
3374 }
3375 } else {
3376 self.diagnostics.error(
3377 DiagnosticCode {
3378 prefix: 'E',
3379 number: 2060,
3380 },
3381 format!("expected type alias name, found `{}`", self.peek().kind),
3382 name_span,
3383 );
3384 Ident {
3385 name: String::new(),
3386 span: name_span,
3387 }
3388 };
3389
3390 let generic_params = self.parse_generic_params();
3392
3393 let _ = self.expect(TokenKind::Assign);
3395
3396 let ty = self.parse_type_expr();
3398
3399 let where_clause = self.parse_where_clause();
3401
3402 let end = if !where_clause.is_empty() {
3403 where_clause
3404 .last()
3405 .expect("where_clause confirmed non-empty")
3406 .span
3407 } else {
3408 ty.span()
3409 };
3410
3411 TypeAliasDecl {
3412 id: self.alloc_id(),
3413 span: Span::merge(start, end),
3414 annotations,
3415 visibility: vis,
3416 name,
3417 generic_params,
3418 ty,
3419 where_clause,
3420 }
3421 }
3422
3423 fn parse_const_decl(&mut self, annotations: Vec<Annotation>, vis: Visibility) -> ConstDecl {
3427 let start = self.peek().span;
3428 let _ = self.advance(); let name_span = self.peek().span;
3432 let name = if matches!(self.peek().kind, TokenKind::Ident | TokenKind::TypeIdent) {
3433 let tok = self.advance();
3434 Ident {
3435 name: tok.literal.unwrap_or_default(),
3436 span: tok.span,
3437 }
3438 } else {
3439 self.diagnostics.error(
3440 DiagnosticCode {
3441 prefix: 'E',
3442 number: 2061,
3443 },
3444 format!("expected constant name, found `{}`", self.peek().kind),
3445 name_span,
3446 );
3447 Ident {
3448 name: String::new(),
3449 span: name_span,
3450 }
3451 };
3452
3453 let _ = self.expect(TokenKind::Colon);
3455
3456 let ty = self.parse_type_expr();
3458
3459 let _ = self.expect(TokenKind::Assign);
3461
3462 let value = self.parse_expr();
3464
3465 let end = value.span();
3466
3467 ConstDecl {
3468 id: self.alloc_id(),
3469 span: Span::merge(start, end),
3470 annotations,
3471 visibility: vis,
3472 name,
3473 ty,
3474 value,
3475 }
3476 }
3477
3478 fn parse_record_decl(&mut self, annotations: Vec<Annotation>, vis: Visibility) -> RecordDecl {
3486 let start = self.peek().span;
3487 let _ = self.advance(); let name_span = self.peek().span;
3490 let name = if self.at(TokenKind::TypeIdent) {
3491 let tok = self.advance();
3492 Ident {
3493 name: tok.literal.unwrap_or_default(),
3494 span: tok.span,
3495 }
3496 } else {
3497 self.diagnostics.error(
3498 DiagnosticCode {
3499 prefix: 'E',
3500 number: 2040,
3501 },
3502 format!("expected record name, found `{}`", self.peek().kind),
3503 name_span,
3504 );
3505 Ident {
3506 name: String::new(),
3507 span: name_span,
3508 }
3509 };
3510
3511 let generic_params = self.parse_generic_params();
3512 let where_clause = self.parse_where_clause();
3513
3514 self.skip_newlines();
3515 let _ = self.expect(TokenKind::LBrace);
3516 let fields = self.parse_record_fields();
3517 let end = self
3518 .expect(TokenKind::RBrace)
3519 .map(|t| t.span)
3520 .unwrap_or(start);
3521
3522 RecordDecl {
3523 id: self.alloc_id(),
3524 span: Span::merge(start, end),
3525 annotations,
3526 visibility: vis,
3527 name,
3528 generic_params,
3529 where_clause,
3530 fields,
3531 }
3532 }
3533
3534 fn parse_record_fields(&mut self) -> Vec<RecordDeclField> {
3536 let mut fields = Vec::new();
3537
3538 loop {
3539 self.skip_newlines();
3540 while self.at(TokenKind::DocComment) {
3543 let _ = self.advance();
3544 self.skip_newlines();
3545 }
3546 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
3547 break;
3548 }
3549 if !self.at(TokenKind::Ident) {
3550 break;
3551 }
3552
3553 let id = self.alloc_id();
3554 let start = self.peek().span;
3555 let tok = self.advance();
3556 let name = Ident {
3557 name: tok.literal.unwrap_or_default(),
3558 span: tok.span,
3559 };
3560
3561 let _ = self.expect(TokenKind::Colon);
3562 let ty = self.parse_type_expr();
3563
3564 let default = if self.at(TokenKind::Assign) {
3565 let _ = self.advance();
3566 Some(self.parse_expr_stub())
3567 } else {
3568 None
3569 };
3570
3571 let end = self.peek().span;
3572 fields.push(RecordDeclField {
3573 id,
3574 span: Span::merge(start, end),
3575 name,
3576 ty,
3577 default,
3578 });
3579
3580 self.skip_newlines();
3581 if self.at(TokenKind::Comma) {
3582 let _ = self.advance();
3583 }
3584 }
3585
3586 fields
3587 }
3588
3589 fn parse_enum_decl(&mut self, annotations: Vec<Annotation>, vis: Visibility) -> EnumDecl {
3597 let start = self.peek().span;
3598 let _ = self.advance(); let name_span = self.peek().span;
3601 let name = if self.at(TokenKind::TypeIdent) {
3602 let tok = self.advance();
3603 Ident {
3604 name: tok.literal.unwrap_or_default(),
3605 span: tok.span,
3606 }
3607 } else {
3608 self.diagnostics.error(
3609 DiagnosticCode {
3610 prefix: 'E',
3611 number: 2050,
3612 },
3613 format!("expected enum name, found `{}`", self.peek().kind),
3614 name_span,
3615 );
3616 Ident {
3617 name: String::new(),
3618 span: name_span,
3619 }
3620 };
3621
3622 let generic_params = self.parse_generic_params();
3623 let where_clause = self.parse_where_clause();
3624
3625 self.skip_newlines();
3626 let _ = self.expect(TokenKind::LBrace);
3627 let variants = self.parse_enum_variants();
3628 let end = self
3629 .expect(TokenKind::RBrace)
3630 .map(|t| t.span)
3631 .unwrap_or(start);
3632
3633 EnumDecl {
3634 id: self.alloc_id(),
3635 span: Span::merge(start, end),
3636 annotations,
3637 visibility: vis,
3638 name,
3639 generic_params,
3640 where_clause,
3641 variants,
3642 }
3643 }
3644
3645 fn parse_enum_variants(&mut self) -> Vec<EnumVariant> {
3647 let mut variants = Vec::new();
3648
3649 loop {
3650 self.skip_newlines();
3651 while self.at(TokenKind::DocComment) {
3652 let _ = self.advance();
3653 self.skip_newlines();
3654 }
3655 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
3656 break;
3657 }
3658 if !matches!(
3660 self.peek().kind,
3661 TokenKind::TypeIdent
3662 | TokenKind::Ok_
3663 | TokenKind::Err_
3664 | TokenKind::Some_
3665 | TokenKind::None_
3666 ) {
3667 break;
3668 }
3669
3670 let id = self.alloc_id();
3671 let start = self.peek().span;
3672 let tok = self.advance();
3673 let variant_name = tok.literal.unwrap_or_else(|| tok.kind.to_string());
3675 let name = Ident {
3676 name: variant_name,
3677 span: tok.span,
3678 };
3679
3680 let variant = if self.at(TokenKind::LBrace) {
3681 let _ = self.advance();
3683 let fields = self.parse_record_fields();
3684 let end = self
3685 .expect(TokenKind::RBrace)
3686 .map(|t| t.span)
3687 .unwrap_or(start);
3688 EnumVariant::Struct {
3689 id,
3690 span: Span::merge(start, end),
3691 name,
3692 fields,
3693 }
3694 } else if self.at(TokenKind::LParen) {
3695 let _ = self.advance();
3697 let mut tys = Vec::new();
3698 self.skip_newlines();
3699 while !self.at(TokenKind::RParen) && !self.at(TokenKind::Eof) {
3700 tys.push(self.parse_type_expr());
3701 self.skip_newlines();
3702 if self.at(TokenKind::Comma) {
3703 let _ = self.advance();
3704 self.skip_newlines();
3705 } else {
3706 break;
3707 }
3708 }
3709 let end = self
3710 .expect(TokenKind::RParen)
3711 .map(|t| t.span)
3712 .unwrap_or(start);
3713 EnumVariant::Tuple {
3714 id,
3715 span: Span::merge(start, end),
3716 name,
3717 tys,
3718 }
3719 } else {
3720 EnumVariant::Unit {
3722 id,
3723 span: start,
3724 name,
3725 }
3726 };
3727
3728 variants.push(variant);
3729
3730 self.skip_newlines();
3731 if self.at(TokenKind::Comma) {
3732 let _ = self.advance();
3733 }
3734 }
3735
3736 variants
3737 }
3738
3739 fn parse_class_decl(&mut self, annotations: Vec<Annotation>, vis: Visibility) -> ClassDecl {
3747 let start = self.peek().span;
3748 let _ = self.advance(); let name_span = self.peek().span;
3751 let name = if self.at(TokenKind::TypeIdent) {
3752 let tok = self.advance();
3753 Ident {
3754 name: tok.literal.unwrap_or_default(),
3755 span: tok.span,
3756 }
3757 } else {
3758 self.diagnostics.error(
3759 DiagnosticCode {
3760 prefix: 'E',
3761 number: 2060,
3762 },
3763 format!("expected class name, found `{}`", self.peek().kind),
3764 name_span,
3765 );
3766 Ident {
3767 name: String::new(),
3768 span: name_span,
3769 }
3770 };
3771
3772 let generic_params = self.parse_generic_params();
3773
3774 let mut base: Option<TypePath> = None;
3776 let mut traits: Vec<TypePath> = Vec::new();
3777
3778 if self.at(TokenKind::Colon) {
3779 let _ = self.advance(); let first = self.parse_type_path();
3782 base = Some(first);
3783
3784 while self.at(TokenKind::Comma) {
3786 let _ = self.advance();
3787 self.skip_newlines();
3788 traits.push(self.parse_type_path());
3789 }
3790 }
3791
3792 let where_clause = self.parse_where_clause();
3793
3794 self.skip_newlines();
3795 let _ = self.expect(TokenKind::LBrace);
3796
3797 let (fields, methods) = self.parse_class_members();
3798
3799 let end = self
3800 .expect(TokenKind::RBrace)
3801 .map(|t| t.span)
3802 .unwrap_or(start);
3803
3804 ClassDecl {
3805 id: self.alloc_id(),
3806 span: Span::merge(start, end),
3807 annotations,
3808 visibility: vis,
3809 name,
3810 generic_params,
3811 base,
3812 traits,
3813 where_clause,
3814 fields,
3815 methods,
3816 }
3817 }
3818
3819 fn parse_class_members(&mut self) -> (Vec<RecordDeclField>, Vec<FnDecl>) {
3821 let mut fields = Vec::new();
3822 let mut methods = Vec::new();
3823
3824 loop {
3825 self.skip_newlines();
3826 while self.at(TokenKind::DocComment) {
3827 let _ = self.advance();
3828 self.skip_newlines();
3829 }
3830 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
3831 break;
3832 }
3833
3834 let mut annotations = Vec::new();
3836 while self.at(TokenKind::At) {
3837 annotations.push(self.parse_annotation());
3838 self.skip_newlines();
3839 }
3840
3841 let vis = if self.at_visibility() {
3843 self.parse_visibility()
3844 } else {
3845 Visibility::Private
3846 };
3847
3848 match self.peek().kind.clone() {
3849 TokenKind::Fn | TokenKind::Async => {
3850 methods.push(self.parse_fn_decl(annotations, vis));
3851 }
3852 TokenKind::Ident => {
3853 let id = self.alloc_id();
3855 let field_start = self.peek().span;
3856 let tok = self.advance();
3857 let field_name = Ident {
3858 name: tok.literal.unwrap_or_default(),
3859 span: tok.span,
3860 };
3861 let _ = self.expect(TokenKind::Colon);
3862 let ty = self.parse_type_expr();
3863 let default = if self.at(TokenKind::Assign) {
3864 let _ = self.advance();
3865 Some(self.parse_expr_stub())
3866 } else {
3867 None
3868 };
3869 let field_end = self.peek().span;
3870 fields.push(RecordDeclField {
3871 id,
3872 span: Span::merge(field_start, field_end),
3873 name: field_name,
3874 ty,
3875 default,
3876 });
3877 self.skip_newlines();
3878 if self.at(TokenKind::Comma) {
3879 let _ = self.advance();
3880 }
3881 }
3882 _ => {
3883 let _ = self.advance();
3885 }
3886 }
3887 }
3888
3889 (fields, methods)
3890 }
3891
3892 fn parse_trait_decl(
3900 &mut self,
3901 annotations: Vec<Annotation>,
3902 vis: Visibility,
3903 is_platform: bool,
3904 ) -> TraitDecl {
3905 let start = self.peek().span;
3906 let _ = self.expect(TokenKind::Trait); let name_span = self.peek().span;
3909 let name = if self.at(TokenKind::TypeIdent) {
3910 let tok = self.advance();
3911 Ident {
3912 name: tok.literal.unwrap_or_default(),
3913 span: tok.span,
3914 }
3915 } else {
3916 self.diagnostics.error(
3917 DiagnosticCode {
3918 prefix: 'E',
3919 number: 2070,
3920 },
3921 format!("expected trait name, found `{}`", self.peek().kind),
3922 name_span,
3923 );
3924 Ident {
3925 name: String::new(),
3926 span: name_span,
3927 }
3928 };
3929
3930 let generic_params = self.parse_generic_params();
3931
3932 let mut supertraits = Vec::new();
3934 if self.at(TokenKind::Colon) {
3935 let _ = self.advance();
3936 supertraits.push(self.parse_type_path());
3937 while self.at(TokenKind::Comma) {
3938 let _ = self.advance();
3939 self.skip_newlines();
3940 supertraits.push(self.parse_type_path());
3941 }
3942 }
3943
3944 let _where_clause = self.parse_where_clause();
3945
3946 self.skip_newlines();
3947 let _ = self.expect(TokenKind::LBrace);
3948
3949 let (associated_types, methods) = self.parse_trait_members();
3950
3951 let end = self
3952 .expect(TokenKind::RBrace)
3953 .map(|t| t.span)
3954 .unwrap_or(start);
3955
3956 TraitDecl {
3957 id: self.alloc_id(),
3958 span: Span::merge(start, end),
3959 annotations,
3960 visibility: vis,
3961 is_platform,
3962 name,
3963 generic_params,
3964 supertraits,
3965 associated_types,
3966 methods,
3967 }
3968 }
3969
3970 fn parse_platform_trait_decl(
3972 &mut self,
3973 annotations: Vec<Annotation>,
3974 vis: Visibility,
3975 ) -> TraitDecl {
3976 let _ = self.advance(); self.parse_trait_decl(annotations, vis, true)
3978 }
3979
3980 fn parse_trait_members(&mut self) -> (Vec<AssociatedType>, Vec<FnDecl>) {
3984 let mut assoc_types = Vec::new();
3985 let mut methods = Vec::new();
3986
3987 loop {
3988 self.skip_newlines();
3989 while self.at(TokenKind::DocComment) {
3990 let _ = self.advance();
3991 self.skip_newlines();
3992 }
3993 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
3994 break;
3995 }
3996
3997 let mut annotations = Vec::new();
3999 while self.at(TokenKind::At) {
4000 annotations.push(self.parse_annotation());
4001 self.skip_newlines();
4002 }
4003
4004 let vis = if self.at_visibility() {
4006 self.parse_visibility()
4007 } else {
4008 Visibility::Private
4009 };
4010
4011 match self.peek().kind.clone() {
4012 TokenKind::Type => {
4014 let at_start = self.peek().span;
4015 let _ = self.advance(); let at_id = self.alloc_id();
4017 let at_name_span = self.peek().span;
4018 let at_name = if self.at(TokenKind::TypeIdent) {
4019 let tok = self.advance();
4020 Ident {
4021 name: tok.literal.unwrap_or_default(),
4022 span: tok.span,
4023 }
4024 } else {
4025 self.diagnostics.error(
4026 DiagnosticCode {
4027 prefix: 'E',
4028 number: 2071,
4029 },
4030 format!(
4031 "expected associated type name, found `{}`",
4032 self.peek().kind
4033 ),
4034 at_name_span,
4035 );
4036 Ident {
4037 name: String::new(),
4038 span: at_name_span,
4039 }
4040 };
4041
4042 let bounds = if self.at(TokenKind::Colon) {
4043 let _ = self.advance();
4044 vec![self.parse_type_path()]
4045 } else {
4046 Vec::new()
4047 };
4048
4049 let at_end = self.peek().span;
4050 assoc_types.push(AssociatedType {
4051 id: at_id,
4052 span: Span::merge(at_start, at_end),
4053 name: at_name,
4054 bounds,
4055 });
4056 }
4057 TokenKind::Fn | TokenKind::Async => {
4058 let fn_start = self.peek().span;
4059 let is_async = if self.at(TokenKind::Async) {
4060 let _ = self.advance();
4061 true
4062 } else {
4063 false
4064 };
4065 let _ = self.expect(TokenKind::Fn);
4066
4067 let fn_name_span = self.peek().span;
4068 let fn_name = if self.at(TokenKind::Ident) {
4069 let tok = self.advance();
4070 Ident {
4071 name: tok.literal.unwrap_or_default(),
4072 span: tok.span,
4073 }
4074 } else {
4075 self.diagnostics.error(
4076 DiagnosticCode {
4077 prefix: 'E',
4078 number: 2072,
4079 },
4080 format!("expected method name, found `{}`", self.peek().kind),
4081 fn_name_span,
4082 );
4083 Ident {
4084 name: String::new(),
4085 span: fn_name_span,
4086 }
4087 };
4088
4089 let generic_params = self.parse_generic_params();
4090 let _ = self.expect(TokenKind::LParen);
4091 let params = self.parse_param_list();
4092 let _ = self.expect(TokenKind::RParen);
4093
4094 let return_type = if self.at(TokenKind::ThinArrow) {
4095 let _ = self.advance();
4096 Some(self.parse_type_expr())
4097 } else {
4098 None
4099 };
4100
4101 let effect_clause = self.parse_effect_clause();
4102 let where_clause = self.parse_where_clause();
4103
4104 self.skip_newlines();
4105
4106 let body = if self.at(TokenKind::LBrace) {
4108 Some(self.parse_block())
4109 } else {
4110 None
4111 };
4112
4113 let fn_end = body
4114 .as_ref()
4115 .map(|b| b.span)
4116 .unwrap_or_else(|| self.peek().span);
4117 methods.push(FnDecl {
4118 id: self.alloc_id(),
4119 span: Span::merge(fn_start, fn_end),
4120 annotations,
4121 visibility: vis,
4122 is_async,
4123 name: fn_name,
4124 generic_params,
4125 params,
4126 return_type,
4127 effect_clause,
4128 where_clause,
4129 body,
4130 });
4131 }
4132 _ => {
4133 let _ = self.advance();
4135 }
4136 }
4137 }
4138
4139 (assoc_types, methods)
4140 }
4141
4142 fn parse_impl_block(&mut self, annotations: Vec<Annotation>) -> ImplBlock {
4150 let start = self.peek().span;
4151 let _ = self.advance(); let generic_params = self.parse_generic_params();
4154
4155 let (trait_path, target) = self.parse_impl_header();
4158
4159 let where_clause = self.parse_where_clause();
4160
4161 self.skip_newlines();
4162 let _ = self.expect(TokenKind::LBrace);
4163 let methods = self.parse_impl_methods();
4164 let end = self
4165 .expect(TokenKind::RBrace)
4166 .map(|t| t.span)
4167 .unwrap_or(start);
4168
4169 ImplBlock {
4170 id: self.alloc_id(),
4171 span: Span::merge(start, end),
4172 annotations,
4173 generic_params,
4174 trait_path,
4175 target,
4176 where_clause,
4177 type_assignments: vec![],
4178 methods,
4179 }
4180 }
4181
4182 fn parse_impl_header(&mut self) -> (Option<TypePath>, TypeExpr) {
4184 let first = self.parse_type_expr();
4186
4187 if self.at(TokenKind::For) {
4188 let _ = self.advance(); let target = self.parse_type_expr();
4191 let trait_path = match &first {
4193 TypeExpr::Named { path, .. } => Some(path.clone()),
4194 _ => None,
4195 };
4196 (trait_path, target)
4197 } else {
4198 (None, first)
4200 }
4201 }
4202
4203 fn parse_impl_methods(&mut self) -> Vec<FnDecl> {
4205 let mut methods = Vec::new();
4206
4207 loop {
4208 self.skip_newlines();
4209 while self.at(TokenKind::DocComment) {
4210 let _ = self.advance();
4211 self.skip_newlines();
4212 }
4213 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
4214 break;
4215 }
4216
4217 let mut annotations = Vec::new();
4219 while self.at(TokenKind::At) {
4220 annotations.push(self.parse_annotation());
4221 self.skip_newlines();
4222 }
4223
4224 let vis = if self.at_visibility() {
4226 self.parse_visibility()
4227 } else {
4228 Visibility::Private
4229 };
4230
4231 if matches!(self.peek().kind, TokenKind::Fn | TokenKind::Async) {
4232 methods.push(self.parse_fn_decl(annotations, vis));
4233 } else {
4234 if self.at(TokenKind::Eof) {
4236 break;
4237 }
4238 let _ = self.advance();
4239 }
4240 }
4241
4242 methods
4243 }
4244
4245 fn parse_effect_decl(&mut self, annotations: Vec<Annotation>, vis: Visibility) -> EffectDecl {
4254 let start = self.peek().span;
4255 let _ = self.advance(); let name_span = self.peek().span;
4258 let name = if self.at(TokenKind::TypeIdent) {
4259 let tok = self.advance();
4260 Ident {
4261 name: tok.literal.unwrap_or_default(),
4262 span: tok.span,
4263 }
4264 } else {
4265 self.diagnostics.error(
4266 DiagnosticCode {
4267 prefix: 'E',
4268 number: 2090,
4269 },
4270 format!("expected effect name, found `{}`", self.peek().kind),
4271 name_span,
4272 );
4273 Ident {
4274 name: String::new(),
4275 span: name_span,
4276 }
4277 };
4278
4279 let generic_params = self.parse_generic_params();
4280
4281 if self.at(TokenKind::Assign) {
4283 let _ = self.advance(); let mut components = vec![self.parse_type_path()];
4285 while self.at(TokenKind::Plus) {
4286 let _ = self.advance();
4287 self.skip_newlines();
4288 components.push(self.parse_type_path());
4289 }
4290 let end = self.peek().span;
4291 if self.at(TokenKind::Newline) {
4293 let _ = self.advance();
4294 }
4295 return EffectDecl {
4296 id: self.alloc_id(),
4297 span: Span::merge(start, end),
4298 annotations,
4299 visibility: vis,
4300 name,
4301 generic_params,
4302 components,
4303 operations: Vec::new(),
4304 };
4305 }
4306
4307 self.skip_newlines();
4309 let _ = self.expect(TokenKind::LBrace);
4310 let operations = self.parse_effect_operations();
4311 let end = self
4312 .expect(TokenKind::RBrace)
4313 .map(|t| t.span)
4314 .unwrap_or(start);
4315
4316 EffectDecl {
4317 id: self.alloc_id(),
4318 span: Span::merge(start, end),
4319 annotations,
4320 visibility: vis,
4321 name,
4322 generic_params,
4323 components: vec![],
4324 operations,
4325 }
4326 }
4327
4328 fn parse_effect_operations(&mut self) -> Vec<FnDecl> {
4332 let mut ops = Vec::new();
4333
4334 loop {
4335 self.skip_newlines();
4336 while self.at(TokenKind::DocComment) {
4337 let _ = self.advance();
4338 self.skip_newlines();
4339 }
4340 if self.at(TokenKind::RBrace) || self.at(TokenKind::Eof) {
4341 break;
4342 }
4343
4344 let mut annotations = Vec::new();
4346 while self.at(TokenKind::At) {
4347 annotations.push(self.parse_annotation());
4348 self.skip_newlines();
4349 }
4350
4351 let vis = if self.at_visibility() {
4352 self.parse_visibility()
4353 } else {
4354 Visibility::Private
4355 };
4356
4357 if !matches!(self.peek().kind, TokenKind::Fn | TokenKind::Async) {
4358 if self.at(TokenKind::Eof) {
4359 break;
4360 }
4361 let _ = self.advance();
4362 continue;
4363 }
4364
4365 let fn_start = self.peek().span;
4366 let is_async = if self.at(TokenKind::Async) {
4367 let _ = self.advance();
4368 true
4369 } else {
4370 false
4371 };
4372 let _ = self.expect(TokenKind::Fn);
4373
4374 let fn_name_span = self.peek().span;
4375 let fn_name = if self.at(TokenKind::Ident) {
4376 let tok = self.advance();
4377 Ident {
4378 name: tok.literal.unwrap_or_default(),
4379 span: tok.span,
4380 }
4381 } else {
4382 self.diagnostics.error(
4383 DiagnosticCode {
4384 prefix: 'E',
4385 number: 2091,
4386 },
4387 format!("expected operation name, found `{}`", self.peek().kind),
4388 fn_name_span,
4389 );
4390 Ident {
4391 name: String::new(),
4392 span: fn_name_span,
4393 }
4394 };
4395
4396 let generic_params = self.parse_generic_params();
4397 let _ = self.expect(TokenKind::LParen);
4398 let params = self.parse_param_list();
4399 let _ = self.expect(TokenKind::RParen);
4400
4401 let return_type = if self.at(TokenKind::ThinArrow) {
4402 let _ = self.advance();
4403 Some(self.parse_type_expr())
4404 } else {
4405 None
4406 };
4407
4408 let effect_clause = self.parse_effect_clause();
4409 let where_clause = self.parse_where_clause();
4410
4411 let fn_end = self.peek().span;
4413
4414 ops.push(FnDecl {
4415 id: self.alloc_id(),
4416 span: Span::merge(fn_start, fn_end),
4417 annotations,
4418 visibility: vis,
4419 is_async,
4420 name: fn_name,
4421 generic_params,
4422 params,
4423 return_type,
4424 effect_clause,
4425 where_clause,
4426 body: None,
4427 });
4428 }
4429
4430 ops
4431 }
4432
4433 fn parse_module_handle_decl(&mut self) -> ModuleHandleDecl {
4437 let start = self.peek().span;
4438 let _ = self.advance(); let effect = self.parse_type_path();
4441 let _ = self.expect(TokenKind::With);
4442 let handler = self.parse_expr();
4443 let end = handler.span();
4444
4445 if self.at(TokenKind::Newline) {
4446 let _ = self.advance();
4447 }
4448
4449 ModuleHandleDecl {
4450 id: self.alloc_id(),
4451 span: Span::merge(start, end),
4452 effect,
4453 handler,
4454 }
4455 }
4456}
4457
4458#[cfg(test)]
4461mod tests {
4462 use super::*;
4463 use bock_errors::FileId;
4464 use bock_lexer::Lexer;
4465 use std::path::PathBuf;
4466
4467 fn parse(src: &str) -> (Module, DiagnosticBag) {
4468 let file_id = FileId(0);
4469 let source = SourceFile::new(file_id, PathBuf::from("test.bock"), src.to_string());
4470 let tokens = Lexer::new(&source).tokenize();
4471 let mut parser = Parser::new(tokens, &source);
4472 let module = parser.parse_module();
4473 let diags = std::mem::replace(&mut parser.diagnostics, DiagnosticBag::new());
4474 (module, diags)
4475 }
4476
4477 #[test]
4478 fn parse_empty_file() {
4479 let (m, diags) = parse("");
4480 assert!(m.path.is_none());
4481 assert!(m.imports.is_empty());
4482 assert!(m.items.is_empty());
4483 assert!(!diags.has_errors());
4484 }
4485
4486 #[test]
4487 fn parse_module_declaration() {
4488 let (m, diags) = parse("module app.auth\n");
4489 assert!(!diags.has_errors(), "unexpected errors");
4490 let path = m.path.expect("module decl should be present");
4491 let names: Vec<&str> = path.segments.iter().map(|s| s.name.as_str()).collect();
4492 assert_eq!(names, ["app", "auth"]);
4493 }
4494
4495 #[test]
4496 fn parse_module_declaration_missing() {
4497 let (m, diags) = parse("fn foo() {}\n");
4499 assert!(m.path.is_none());
4500 assert!(!diags.has_errors());
4501 }
4502
4503 #[test]
4504 fn parse_import_glob() {
4505 let (m, diags) = parse("use app.services.*\n");
4506 assert!(!diags.has_errors(), "unexpected errors");
4507 assert_eq!(m.imports.len(), 1);
4508 let imp = &m.imports[0];
4509 let path_segs: Vec<&str> = imp.path.segments.iter().map(|s| s.name.as_str()).collect();
4510 assert_eq!(path_segs, ["app", "services"]);
4511 assert_eq!(imp.items, ImportItems::Glob);
4512 }
4513
4514 #[test]
4515 fn parse_import_named_list() {
4516 let (m, diags) = parse("use core.collections.{List, Map}\n");
4517 assert!(!diags.has_errors(), "unexpected errors");
4518 assert_eq!(m.imports.len(), 1);
4519 let imp = &m.imports[0];
4520 let path_segs: Vec<&str> = imp.path.segments.iter().map(|s| s.name.as_str()).collect();
4521 assert_eq!(path_segs, ["core", "collections"]);
4522 match &imp.items {
4523 ImportItems::Named(names) => {
4524 let ns: Vec<&str> = names.iter().map(|n| n.name.name.as_str()).collect();
4525 assert_eq!(ns, ["List", "Map"]);
4526 }
4527 other => panic!("expected Named, got {other:?}"),
4528 }
4529 }
4530
4531 #[test]
4532 fn parse_import_single_name() {
4533 let (m, diags) = parse("use app.models.User\n");
4534 assert!(!diags.has_errors(), "unexpected errors");
4535 assert_eq!(m.imports.len(), 1);
4536 let imp = &m.imports[0];
4537 match &imp.items {
4541 ImportItems::Named(names) if names.len() == 1 => {
4542 assert_eq!(names[0].name.name, "User");
4543 }
4544 ImportItems::Module => {
4545 let last = imp.path.segments.last().expect("non-empty path");
4547 assert_eq!(last.name, "User");
4548 }
4549 other => panic!("unexpected import items: {other:?}"),
4550 }
4551 }
4552
4553 #[test]
4554 fn parse_multi_import_file() {
4555 let src = "\
4556module myapp.core\n\
4557use core.collections.{List, Map}\n\
4558use app.models.User\n\
4559use app.services.*\n\
4560";
4561 let (m, diags) = parse(src);
4562 assert!(!diags.has_errors(), "unexpected errors");
4563
4564 let path = m.path.expect("module decl");
4566 assert_eq!(path.segments[0].name, "myapp");
4567 assert_eq!(path.segments[1].name, "core");
4568
4569 assert_eq!(m.imports.len(), 3);
4571
4572 let first = &m.imports[0];
4574 assert!(matches!(first.items, ImportItems::Named(_)));
4575
4576 let last = &m.imports[2];
4578 assert_eq!(last.items, ImportItems::Glob);
4579 }
4580
4581 #[test]
4582 fn parser_new_and_diagnostics() {
4583 let file_id = FileId(0);
4584 let source = SourceFile::new(file_id, PathBuf::from("x.bock"), String::new());
4585 let tokens = Lexer::new(&source).tokenize();
4586 let parser = Parser::new(tokens, &source);
4587 assert!(!parser.diagnostics().has_errors());
4588 }
4589
4590 #[test]
4593 fn parse_simple_fn() {
4594 let (m, diags) = parse("fn greet() {}\n");
4595 assert!(!diags.has_errors(), "{diags:?}");
4596 assert_eq!(m.items.len(), 1);
4597 let Item::Fn(f) = &m.items[0] else {
4598 panic!("expected Fn")
4599 };
4600 assert_eq!(f.name.name, "greet");
4601 assert!(!f.is_async);
4602 assert_eq!(f.visibility, Visibility::Private);
4603 assert!(f.params.is_empty());
4604 assert!(f.return_type.is_none());
4605 }
4606
4607 #[test]
4608 fn parse_fn_with_params_and_return_type() {
4609 let (m, diags) = parse("fn add(x: Int, y: Int) -> Int {}\n");
4610 assert!(!diags.has_errors(), "{diags:?}");
4611 let Item::Fn(f) = &m.items[0] else { panic!() };
4612 assert_eq!(f.name.name, "add");
4613 assert_eq!(f.params.len(), 2);
4614 assert_eq!(
4615 f.params[0].pattern,
4616 Pattern::Bind {
4617 id: f.params[0].pattern.node_id(),
4618 span: f.params[0].pattern.span(),
4619 name: Ident {
4620 name: "x".into(),
4621 span: f.params[0].pattern.span()
4622 },
4623 }
4624 );
4625 assert!(f.return_type.is_some());
4626 let TypeExpr::Named { path, .. } = f.return_type.as_ref().unwrap() else {
4627 panic!()
4628 };
4629 assert_eq!(path.segments[0].name, "Int");
4630 }
4631
4632 #[test]
4633 fn parse_async_fn() {
4634 let (m, diags) = parse("async fn fetch() -> String {}\n");
4635 assert!(!diags.has_errors(), "{diags:?}");
4636 let Item::Fn(f) = &m.items[0] else { panic!() };
4637 assert!(f.is_async);
4638 assert_eq!(f.name.name, "fetch");
4639 }
4640
4641 #[test]
4642 fn parse_fn_with_visibility() {
4643 let (m, diags) = parse("public fn exposed() {}\n");
4644 assert!(!diags.has_errors(), "{diags:?}");
4645 let Item::Fn(f) = &m.items[0] else { panic!() };
4646 assert_eq!(f.visibility, Visibility::Public);
4647 }
4648
4649 #[test]
4650 fn parse_fn_with_generic_params() {
4651 let (m, diags) = parse("fn identity[T](x: T) -> T {}\n");
4652 assert!(!diags.has_errors(), "{diags:?}");
4653 let Item::Fn(f) = &m.items[0] else { panic!() };
4654 assert_eq!(f.generic_params.len(), 1);
4655 assert_eq!(f.generic_params[0].name.name, "T");
4656 }
4657
4658 #[test]
4659 fn parse_fn_with_generic_bounds() {
4660 let (m, diags) = parse("fn compare[T: Ord](a: T, b: T) -> Bool {}\n");
4661 assert!(!diags.has_errors(), "{diags:?}");
4662 let Item::Fn(f) = &m.items[0] else { panic!() };
4663 assert_eq!(f.generic_params[0].name.name, "T");
4664 assert_eq!(f.generic_params[0].bounds[0].segments[0].name, "Ord");
4665 }
4666
4667 #[test]
4668 fn parse_fn_with_where_clause() {
4669 let (m, diags) = parse("fn sorted[T](items: List) -> List where (T: Ord) {}\n");
4670 assert!(!diags.has_errors(), "{diags:?}");
4671 let Item::Fn(f) = &m.items[0] else { panic!() };
4672 assert_eq!(f.where_clause.len(), 1);
4673 assert_eq!(f.where_clause[0].param.name, "T");
4674 assert_eq!(f.where_clause[0].bounds[0].segments[0].name, "Ord");
4675 }
4676
4677 #[test]
4678 fn parse_fn_with_where_clause_multiple_constraints() {
4679 let (m, diags) = parse("fn dual[T, U](a: T, b: U) -> Bool where (T: Eq, U: Ord) {}\n");
4680 assert!(!diags.has_errors(), "{diags:?}");
4681 let Item::Fn(f) = &m.items[0] else { panic!() };
4682 assert_eq!(f.where_clause.len(), 2);
4683 }
4684
4685 #[test]
4686 fn parse_fn_with_effect_clause() {
4687 let (m, diags) = parse("fn log_msg(msg: String) with Log {}\n");
4688 assert!(!diags.has_errors(), "{diags:?}");
4689 let Item::Fn(f) = &m.items[0] else { panic!() };
4690 assert_eq!(f.effect_clause.len(), 1);
4691 assert_eq!(f.effect_clause[0].segments[0].name, "Log");
4692 }
4693
4694 #[test]
4695 fn parse_fn_with_multiple_effects() {
4696 let (m, diags) = parse("fn do_io(path: String) with Io, Log {}\n");
4697 assert!(!diags.has_errors(), "{diags:?}");
4698 let Item::Fn(f) = &m.items[0] else { panic!() };
4699 assert_eq!(f.effect_clause.len(), 2);
4700 }
4701
4702 #[test]
4703 fn parse_fn_with_default_param() {
4704 let (m, diags) = parse("fn greet(name: String, loud: Bool = false) {}\n");
4705 assert!(!diags.has_errors(), "{diags:?}");
4706 let Item::Fn(f) = &m.items[0] else { panic!() };
4707 assert!(f.params[1].default.is_some());
4708 let Expr::Literal {
4709 lit: Literal::Bool(false),
4710 ..
4711 } = f.params[1].default.as_ref().unwrap()
4712 else {
4713 panic!("expected false literal")
4714 };
4715 }
4716
4717 #[test]
4718 fn parse_fn_with_annotation() {
4719 let (m, diags) = parse("@test\nfn it_works() {}\n");
4720 assert!(!diags.has_errors(), "{diags:?}");
4721 let Item::Fn(f) = &m.items[0] else { panic!() };
4722 assert_eq!(f.annotations.len(), 1);
4723 assert_eq!(f.annotations[0].name.name, "test");
4724 }
4725
4726 #[test]
4729 fn parse_simple_record() {
4730 let (m, diags) = parse("record Point { x: Int, y: Int }\n");
4731 assert!(!diags.has_errors(), "{diags:?}");
4732 assert_eq!(m.items.len(), 1);
4733 let Item::Record(r) = &m.items[0] else {
4734 panic!("expected Record")
4735 };
4736 assert_eq!(r.name.name, "Point");
4737 assert_eq!(r.fields.len(), 2);
4738 assert_eq!(r.fields[0].name.name, "x");
4739 assert_eq!(r.fields[1].name.name, "y");
4740 }
4741
4742 #[test]
4743 fn parse_record_with_default_field_values() {
4744 let (m, diags) = parse("record Config { retries: Int = 3, verbose: Bool = false }\n");
4745 assert!(!diags.has_errors(), "{diags:?}");
4746 let Item::Record(r) = &m.items[0] else {
4747 panic!()
4748 };
4749 assert_eq!(r.name.name, "Config");
4750 assert!(r.fields[0].default.is_some());
4751 let Expr::Literal {
4752 lit: Literal::Int(n),
4753 ..
4754 } = r.fields[0].default.as_ref().unwrap()
4755 else {
4756 panic!("expected int literal")
4757 };
4758 assert_eq!(n, "3");
4759 assert!(r.fields[1].default.is_some());
4760 }
4761
4762 #[test]
4763 fn parse_record_with_generic_params() {
4764 let (m, diags) = parse("record Pair[A, B] { first: A, second: B }\n");
4765 assert!(!diags.has_errors(), "{diags:?}");
4766 let Item::Record(r) = &m.items[0] else {
4767 panic!()
4768 };
4769 assert_eq!(r.generic_params.len(), 2);
4770 assert_eq!(r.generic_params[0].name.name, "A");
4771 assert_eq!(r.generic_params[1].name.name, "B");
4772 }
4773
4774 #[test]
4775 fn parse_record_with_annotation() {
4776 let (m, diags) = parse("@derive(Equatable)\nrecord User { id: Int, name: String }\n");
4777 assert!(!diags.has_errors(), "{diags:?}");
4778 let Item::Record(r) = &m.items[0] else {
4779 panic!()
4780 };
4781 assert_eq!(r.annotations.len(), 1);
4782 assert_eq!(r.annotations[0].name.name, "derive");
4783 }
4784
4785 #[test]
4786 fn parse_record_with_visibility() {
4787 let (m, diags) = parse("public record Token { kind: Int }\n");
4788 assert!(!diags.has_errors(), "{diags:?}");
4789 let Item::Record(r) = &m.items[0] else {
4790 panic!()
4791 };
4792 assert_eq!(r.visibility, Visibility::Public);
4793 }
4794
4795 #[test]
4796 fn parse_record_optional_field_type() {
4797 let (m, diags) = parse("record Profile { name: String, bio: String? }\n");
4798 assert!(!diags.has_errors(), "{diags:?}");
4799 let Item::Record(r) = &m.items[0] else {
4800 panic!()
4801 };
4802 assert!(matches!(r.fields[1].ty, TypeExpr::Optional { .. }));
4803 }
4804
4805 #[test]
4808 fn parse_enum_unit_variants() {
4809 let (m, diags) = parse("enum Direction {\n North\n South\n East\n West\n}\n");
4810 assert!(!diags.has_errors(), "{diags:?}");
4811 let Item::Enum(e) = &m.items[0] else {
4812 panic!("expected Enum")
4813 };
4814 assert_eq!(e.name.name, "Direction");
4815 assert_eq!(e.variants.len(), 4);
4816 for v in &e.variants {
4817 assert!(matches!(v, EnumVariant::Unit { .. }));
4818 }
4819 }
4820
4821 #[test]
4822 fn parse_enum_struct_variants() {
4823 let src = "enum Shape {\n Circle { radius: Float }\n Rect { w: Float, h: Float }\n}\n";
4824 let (m, diags) = parse(src);
4825 assert!(!diags.has_errors(), "{diags:?}");
4826 let Item::Enum(e) = &m.items[0] else { panic!() };
4827 assert_eq!(e.variants.len(), 2);
4828 assert!(matches!(&e.variants[0], EnumVariant::Struct { .. }));
4829 assert!(matches!(&e.variants[1], EnumVariant::Struct { .. }));
4830 let EnumVariant::Struct { fields, .. } = &e.variants[0] else {
4831 unreachable!()
4832 };
4833 assert_eq!(fields[0].name.name, "radius");
4834 }
4835
4836 #[test]
4837 fn parse_enum_tuple_variants() {
4838 let src = "enum Result {\n Ok(Int)\n Err(String)\n}\n";
4839 let (m, diags) = parse(src);
4840 assert!(!diags.has_errors(), "{diags:?}");
4841 let Item::Enum(e) = &m.items[0] else { panic!() };
4842 assert_eq!(e.variants.len(), 2);
4843 assert!(matches!(&e.variants[0], EnumVariant::Tuple { .. }));
4844 assert!(matches!(&e.variants[1], EnumVariant::Tuple { .. }));
4845 let EnumVariant::Tuple { tys, .. } = &e.variants[0] else {
4846 unreachable!()
4847 };
4848 assert_eq!(tys.len(), 1);
4849 }
4850
4851 #[test]
4852 fn parse_enum_mixed_variants() {
4853 let src = "enum Expr {\n Num(Int)\n Add { left: Int, right: Int }\n Unit\n}\n";
4854 let (m, diags) = parse(src);
4855 assert!(!diags.has_errors(), "{diags:?}");
4856 let Item::Enum(e) = &m.items[0] else { panic!() };
4857 assert_eq!(e.variants.len(), 3);
4858 assert!(matches!(&e.variants[0], EnumVariant::Tuple { .. }));
4859 assert!(matches!(&e.variants[1], EnumVariant::Struct { .. }));
4860 assert!(matches!(&e.variants[2], EnumVariant::Unit { .. }));
4861 }
4862
4863 #[test]
4864 fn parse_enum_with_generics() {
4865 let src = "enum Option[T] {\n Some(T)\n None\n}\n";
4866 let (m, diags) = parse(src);
4867 assert!(!diags.has_errors(), "{diags:?}");
4868 let Item::Enum(e) = &m.items[0] else { panic!() };
4869 assert_eq!(e.generic_params.len(), 1);
4870 assert_eq!(e.generic_params[0].name.name, "T");
4871 assert_eq!(e.variants.len(), 2);
4872 }
4873
4874 #[test]
4875 fn parse_enum_with_annotation() {
4876 let src = "@derive(Equatable)\nenum Status {\n Active\n Inactive\n}\n";
4877 let (m, diags) = parse(src);
4878 assert!(!diags.has_errors(), "{diags:?}");
4879 let Item::Enum(e) = &m.items[0] else { panic!() };
4880 assert_eq!(e.annotations.len(), 1);
4881 }
4882
4883 #[test]
4886 fn parse_generic_type_in_field() {
4887 let (m, diags) = parse("record Container { items: List[Int] }\n");
4888 assert!(!diags.has_errors(), "{diags:?}");
4889 let Item::Record(r) = &m.items[0] else {
4890 panic!()
4891 };
4892 let TypeExpr::Named { args, .. } = &r.fields[0].ty else {
4893 panic!()
4894 };
4895 assert_eq!(args.len(), 1);
4896 }
4897
4898 #[test]
4899 fn parse_multiple_items_in_file() {
4900 let src = "fn foo() {}\nrecord Bar { x: Int }\nenum Baz { A\n B\n}\n";
4901 let (m, diags) = parse(src);
4902 assert!(!diags.has_errors(), "{diags:?}");
4903 assert_eq!(m.items.len(), 3);
4904 assert!(matches!(m.items[0], Item::Fn(_)));
4905 assert!(matches!(m.items[1], Item::Record(_)));
4906 assert!(matches!(m.items[2], Item::Enum(_)));
4907 }
4908
4909 #[test]
4912 fn parse_empty_class() {
4913 let src = "class Animal {}\n";
4914 let (m, diags) = parse(src);
4915 assert!(!diags.has_errors(), "{diags:?}");
4916 let Item::Class(c) = &m.items[0] else {
4917 panic!("expected Class")
4918 };
4919 assert_eq!(c.name.name, "Animal");
4920 assert!(c.base.is_none());
4921 assert!(c.traits.is_empty());
4922 assert!(c.fields.is_empty());
4923 assert!(c.methods.is_empty());
4924 }
4925
4926 #[test]
4927 fn parse_class_with_fields_and_method() {
4928 let src = "class Point {\n x: Int\n y: Int\n fn distance(self) -> Float { }\n}\n";
4929 let (m, diags) = parse(src);
4930 assert!(!diags.has_errors(), "{diags:?}");
4931 let Item::Class(c) = &m.items[0] else {
4932 panic!()
4933 };
4934 assert_eq!(c.name.name, "Point");
4935 assert_eq!(c.fields.len(), 2);
4936 assert_eq!(c.fields[0].name.name, "x");
4937 assert_eq!(c.fields[1].name.name, "y");
4938 assert_eq!(c.methods.len(), 1);
4939 assert_eq!(c.methods[0].name.name, "distance");
4940 }
4941
4942 #[test]
4943 fn parse_class_with_inheritance() {
4944 let src = "class Dog : Animal, Trainable {}\n";
4945 let (m, diags) = parse(src);
4946 assert!(!diags.has_errors(), "{diags:?}");
4947 let Item::Class(c) = &m.items[0] else {
4948 panic!()
4949 };
4950 assert_eq!(c.name.name, "Dog");
4951 let base = c.base.as_ref().expect("should have base");
4952 assert_eq!(base.segments[0].name, "Animal");
4953 assert_eq!(c.traits.len(), 1);
4954 assert_eq!(c.traits[0].segments[0].name, "Trainable");
4955 }
4956
4957 #[test]
4958 fn parse_class_with_generics() {
4959 let src = "class Box[T] {\n value: T\n}\n";
4960 let (m, diags) = parse(src);
4961 assert!(!diags.has_errors(), "{diags:?}");
4962 let Item::Class(c) = &m.items[0] else {
4963 panic!()
4964 };
4965 assert_eq!(c.generic_params.len(), 1);
4966 assert_eq!(c.generic_params[0].name.name, "T");
4967 assert_eq!(c.fields.len(), 1);
4968 }
4969
4970 #[test]
4971 fn parse_class_with_annotation() {
4972 let src = "@derive(Equatable)\nclass User {\n name: String\n}\n";
4973 let (m, diags) = parse(src);
4974 assert!(!diags.has_errors(), "{diags:?}");
4975 let Item::Class(c) = &m.items[0] else {
4976 panic!()
4977 };
4978 assert_eq!(c.annotations.len(), 1);
4979 assert_eq!(c.annotations[0].name.name, "derive");
4980 }
4981
4982 #[test]
4983 fn parse_public_class() {
4984 let src = "public class Foo {}\n";
4985 let (m, diags) = parse(src);
4986 assert!(!diags.has_errors(), "{diags:?}");
4987 let Item::Class(c) = &m.items[0] else {
4988 panic!()
4989 };
4990 assert_eq!(c.visibility, Visibility::Public);
4991 }
4992
4993 #[test]
4994 fn parse_empty_trait() {
4995 let src = "trait Printable {}\n";
4996 let (m, diags) = parse(src);
4997 assert!(!diags.has_errors(), "{diags:?}");
4998 let Item::Trait(t) = &m.items[0] else {
4999 panic!("expected Trait")
5000 };
5001 assert_eq!(t.name.name, "Printable");
5002 assert!(!t.is_platform);
5003 assert!(t.methods.is_empty());
5004 assert!(t.associated_types.is_empty());
5005 }
5006
5007 #[test]
5008 fn parse_trait_with_required_and_default_methods() {
5009 let src = "trait Display {\n fn show(self) -> String\n fn debug(self) -> String { }\n}\n";
5010 let (m, diags) = parse(src);
5011 assert!(!diags.has_errors(), "{diags:?}");
5012 let Item::Trait(t) = &m.items[0] else {
5013 panic!()
5014 };
5015 assert_eq!(t.methods.len(), 2);
5016 assert_eq!(t.methods[0].name.name, "show");
5017 assert_eq!(t.methods[1].name.name, "debug");
5018 }
5019
5020 #[test]
5021 fn parse_trait_with_associated_type() {
5022 let src = "trait Collection {\n type Item\n fn len(self) -> Int\n}\n";
5023 let (m, diags) = parse(src);
5024 assert!(!diags.has_errors(), "{diags:?}");
5025 let Item::Trait(t) = &m.items[0] else {
5026 panic!()
5027 };
5028 assert_eq!(t.associated_types.len(), 1);
5029 assert_eq!(t.associated_types[0].name.name, "Item");
5030 assert_eq!(t.methods.len(), 1);
5031 }
5032
5033 #[test]
5034 fn parse_trait_associated_type_with_bound() {
5035 let src = "trait Keyed {\n type Key: Hashable\n}\n";
5036 let (m, diags) = parse(src);
5037 assert!(!diags.has_errors(), "{diags:?}");
5038 let Item::Trait(t) = &m.items[0] else {
5039 panic!()
5040 };
5041 assert_eq!(t.associated_types[0].bounds.len(), 1);
5042 assert_eq!(t.associated_types[0].bounds[0].segments[0].name, "Hashable");
5043 }
5044
5045 #[test]
5046 fn parse_trait_with_generics() {
5047 let src = "trait Functor[F] {\n fn map(self) -> F\n}\n";
5048 let (m, diags) = parse(src);
5049 assert!(!diags.has_errors(), "{diags:?}");
5050 let Item::Trait(t) = &m.items[0] else {
5051 panic!()
5052 };
5053 assert_eq!(t.generic_params.len(), 1);
5054 assert_eq!(t.generic_params[0].name.name, "F");
5055 }
5056
5057 #[test]
5058 fn parse_platform_trait() {
5059 let src = "platform trait FileSystem {\n fn read(path: String) -> String\n}\n";
5060 let (m, diags) = parse(src);
5061 assert!(!diags.has_errors(), "{diags:?}");
5062 let Item::PlatformTrait(t) = &m.items[0] else {
5063 panic!("expected PlatformTrait")
5064 };
5065 assert_eq!(t.name.name, "FileSystem");
5066 assert!(t.is_platform);
5067 assert_eq!(t.methods.len(), 1);
5068 }
5069
5070 #[test]
5071 fn parse_impl_type() {
5072 let src = "impl Dog {\n fn bark(self) -> String { }\n}\n";
5073 let (m, diags) = parse(src);
5074 assert!(!diags.has_errors(), "{diags:?}");
5075 let Item::Impl(b) = &m.items[0] else {
5076 panic!("expected Impl")
5077 };
5078 assert!(b.trait_path.is_none());
5079 assert_eq!(b.methods.len(), 1);
5080 assert_eq!(b.methods[0].name.name, "bark");
5081 }
5082
5083 #[test]
5084 fn parse_impl_trait_for_type() {
5085 let src = "impl Printable for Dog {\n fn show(self) -> String { }\n}\n";
5086 let (m, diags) = parse(src);
5087 assert!(!diags.has_errors(), "{diags:?}");
5088 let Item::Impl(b) = &m.items[0] else { panic!() };
5089 let trait_path = b.trait_path.as_ref().expect("should have trait path");
5090 assert_eq!(trait_path.segments[0].name, "Printable");
5091 assert_eq!(b.methods.len(), 1);
5092 }
5093
5094 #[test]
5095 fn parse_impl_with_generics() {
5096 let src = "impl[T] Display for Box[T] {\n fn show(self) -> String { }\n}\n";
5097 let (m, diags) = parse(src);
5098 assert!(!diags.has_errors(), "{diags:?}");
5099 let Item::Impl(b) = &m.items[0] else { panic!() };
5100 assert_eq!(b.generic_params.len(), 1);
5101 assert_eq!(b.generic_params[0].name.name, "T");
5102 let trait_path = b.trait_path.as_ref().expect("trait path");
5103 assert_eq!(trait_path.segments[0].name, "Display");
5104 }
5105
5106 #[test]
5107 fn parse_impl_empty_body() {
5108 let src = "impl Animal {}\n";
5109 let (m, diags) = parse(src);
5110 assert!(!diags.has_errors(), "{diags:?}");
5111 let Item::Impl(b) = &m.items[0] else { panic!() };
5112 assert!(b.methods.is_empty());
5113 }
5114
5115 #[test]
5116 fn parse_mixed_items_with_class_trait_impl() {
5117 let src = concat!(
5118 "trait Greet {\n fn hello(self) -> String\n}\n",
5119 "class Cat {}\n",
5120 "impl Greet for Cat {\n fn hello(self) -> String { }\n}\n",
5121 );
5122 let (m, diags) = parse(src);
5123 assert!(!diags.has_errors(), "{diags:?}");
5124 assert_eq!(m.items.len(), 3);
5125 assert!(matches!(m.items[0], Item::Trait(_)));
5126 assert!(matches!(m.items[1], Item::Class(_)));
5127 assert!(matches!(m.items[2], Item::Impl(_)));
5128 }
5129
5130 fn parse_fn_body(src: &str) -> (Expr, DiagnosticBag) {
5134 let src = format!("fn test() {{\n{src}\n}}");
5135 let (m, diags) = parse(&src);
5136 let fn_decl = match m.items.first().expect("expected fn") {
5137 Item::Fn(f) => f.clone(),
5138 _ => panic!("expected fn item"),
5139 };
5140 let body = fn_decl.body.expect("expected function body");
5141 let tail = body.tail.expect("expected tail expression");
5142 (*tail, diags)
5143 }
5144
5145 fn parse_expr_str(src: &str) -> (Expr, DiagnosticBag) {
5147 parse_fn_body(src)
5148 }
5149
5150 #[test]
5151 fn expr_integer_literal() {
5152 let (e, diags) = parse_expr_str("42");
5153 assert!(!diags.has_errors(), "{diags:?}");
5154 assert!(matches!(e, Expr::Literal { lit: Literal::Int(ref s), .. } if s == "42"));
5155 }
5156
5157 #[test]
5158 fn expr_float_literal() {
5159 let (e, diags) = parse_expr_str("3.14");
5160 assert!(!diags.has_errors(), "{diags:?}");
5161 assert!(matches!(
5162 e,
5163 Expr::Literal {
5164 lit: Literal::Float(_),
5165 ..
5166 }
5167 ));
5168 }
5169
5170 #[test]
5171 fn expr_bool_literal() {
5172 let (e, diags) = parse_expr_str("true");
5173 assert!(!diags.has_errors(), "{diags:?}");
5174 assert!(matches!(
5175 e,
5176 Expr::Literal {
5177 lit: Literal::Bool(true),
5178 ..
5179 }
5180 ));
5181
5182 let (e2, _) = parse_expr_str("false");
5183 assert!(matches!(
5184 e2,
5185 Expr::Literal {
5186 lit: Literal::Bool(false),
5187 ..
5188 }
5189 ));
5190 }
5191
5192 #[test]
5193 fn expr_string_literal() {
5194 let (e, diags) = parse_expr_str(r#""hello""#);
5195 assert!(!diags.has_errors(), "{diags:?}");
5196 assert!(matches!(
5197 e,
5198 Expr::Literal {
5199 lit: Literal::String(_),
5200 ..
5201 }
5202 ));
5203 }
5204
5205 #[test]
5206 fn expr_identifier() {
5207 let (e, diags) = parse_expr_str("foo");
5208 assert!(!diags.has_errors(), "{diags:?}");
5209 assert!(matches!(e, Expr::Identifier { ref name, .. } if name.name == "foo"));
5210 }
5211
5212 #[test]
5213 fn expr_binary_add() {
5214 let (e, diags) = parse_expr_str("1 + 2");
5215 assert!(!diags.has_errors(), "{diags:?}");
5216 assert!(matches!(e, Expr::Binary { op: BinOp::Add, .. }));
5217 }
5218
5219 #[test]
5220 fn expr_binary_precedence_mul_over_add() {
5221 let (e, diags) = parse_expr_str("1 + 2 * 3");
5223 assert!(!diags.has_errors(), "{diags:?}");
5224 match e {
5225 Expr::Binary {
5226 op: BinOp::Add,
5227 right,
5228 ..
5229 } => {
5230 assert!(matches!(*right, Expr::Binary { op: BinOp::Mul, .. }));
5231 }
5232 _ => panic!("expected Add binary expr, got {e:?}"),
5233 }
5234 }
5235
5236 #[test]
5237 fn expr_binary_left_associative() {
5238 let (e, diags) = parse_expr_str("1 - 2 - 3");
5240 assert!(!diags.has_errors(), "{diags:?}");
5241 match e {
5242 Expr::Binary {
5243 op: BinOp::Sub,
5244 left,
5245 right,
5246 ..
5247 } => {
5248 assert!(matches!(*left, Expr::Binary { op: BinOp::Sub, .. }));
5249 assert!(matches!(*right, Expr::Literal { .. }));
5250 }
5251 _ => panic!("expected Sub binary expr"),
5252 }
5253 }
5254
5255 #[test]
5256 fn expr_power_right_associative() {
5257 let (e, diags) = parse_expr_str("2 ** 3 ** 4");
5259 assert!(!diags.has_errors(), "{diags:?}");
5260 match e {
5261 Expr::Binary {
5262 op: BinOp::Pow,
5263 left,
5264 right,
5265 ..
5266 } => {
5267 assert!(matches!(*left, Expr::Literal { .. }));
5268 assert!(matches!(*right, Expr::Binary { op: BinOp::Pow, .. }));
5269 }
5270 _ => panic!("expected Pow binary expr"),
5271 }
5272 }
5273
5274 #[test]
5275 fn expr_comparison_operators() {
5276 for (src, expected_op) in [
5277 ("a == b", BinOp::Eq),
5278 ("a != b", BinOp::Ne),
5279 ("a < b", BinOp::Lt),
5280 ("a > b", BinOp::Gt),
5281 ("a <= b", BinOp::Le),
5282 ("a >= b", BinOp::Ge),
5283 ] {
5284 let (e, diags) = parse_expr_str(src);
5285 assert!(!diags.has_errors(), "errors for {src}: {diags:?}");
5286 assert!(
5287 matches!(&e, Expr::Binary { op, .. } if *op == expected_op),
5288 "{src} expected {expected_op:?}"
5289 );
5290 }
5291 }
5292
5293 #[test]
5294 fn expr_logical_and_or() {
5295 let (e, diags) = parse_expr_str("a && b");
5296 assert!(!diags.has_errors(), "{diags:?}");
5297 assert!(matches!(e, Expr::Binary { op: BinOp::And, .. }));
5298
5299 let (e2, _) = parse_expr_str("a || b");
5300 assert!(matches!(e2, Expr::Binary { op: BinOp::Or, .. }));
5301 }
5302
5303 #[test]
5304 fn expr_and_binds_tighter_than_or() {
5305 let (e, diags) = parse_expr_str("a || b && c");
5307 assert!(!diags.has_errors(), "{diags:?}");
5308 match e {
5309 Expr::Binary {
5310 op: BinOp::Or,
5311 right,
5312 ..
5313 } => {
5314 assert!(matches!(*right, Expr::Binary { op: BinOp::And, .. }));
5315 }
5316 _ => panic!("expected Or expr"),
5317 }
5318 }
5319
5320 #[test]
5321 fn expr_assignment() {
5322 let (e, diags) = parse_expr_str("x = 5");
5323 assert!(!diags.has_errors(), "{diags:?}");
5324 assert!(matches!(
5325 e,
5326 Expr::Assign {
5327 op: AssignOp::Assign,
5328 ..
5329 }
5330 ));
5331 }
5332
5333 #[test]
5334 fn expr_compound_assignment() {
5335 for (src, expected_op) in [
5336 ("x += 1", AssignOp::AddAssign),
5337 ("x -= 1", AssignOp::SubAssign),
5338 ("x *= 2", AssignOp::MulAssign),
5339 ("x /= 2", AssignOp::DivAssign),
5340 ("x %= 3", AssignOp::RemAssign),
5341 ] {
5342 let (e, diags) = parse_expr_str(src);
5343 assert!(!diags.has_errors(), "errors for {src}: {diags:?}");
5344 assert!(
5345 matches!(&e, Expr::Assign { op, .. } if *op == expected_op),
5346 "expected {expected_op:?} for {src}"
5347 );
5348 }
5349 }
5350
5351 #[test]
5352 fn expr_unary_neg() {
5353 let (e, diags) = parse_expr_str("-x");
5354 assert!(!diags.has_errors(), "{diags:?}");
5355 assert!(matches!(
5356 e,
5357 Expr::Unary {
5358 op: UnaryOp::Neg,
5359 ..
5360 }
5361 ));
5362 }
5363
5364 #[test]
5365 fn expr_unary_not() {
5366 let (e, diags) = parse_expr_str("!flag");
5367 assert!(!diags.has_errors(), "{diags:?}");
5368 assert!(matches!(
5369 e,
5370 Expr::Unary {
5371 op: UnaryOp::Not,
5372 ..
5373 }
5374 ));
5375 }
5376
5377 #[test]
5378 fn expr_unary_bitnot() {
5379 let (e, diags) = parse_expr_str("~x");
5380 assert!(!diags.has_errors(), "{diags:?}");
5381 assert!(matches!(
5382 e,
5383 Expr::Unary {
5384 op: UnaryOp::BitNot,
5385 ..
5386 }
5387 ));
5388 }
5389
5390 #[test]
5391 fn expr_try_operator() {
5392 let (e, diags) = parse_expr_str("result?");
5393 assert!(!diags.has_errors(), "{diags:?}");
5394 assert!(matches!(e, Expr::Try { .. }));
5395 }
5396
5397 #[test]
5398 fn expr_field_access() {
5399 let (e, diags) = parse_expr_str("obj.field");
5400 assert!(!diags.has_errors(), "{diags:?}");
5401 assert!(matches!(e, Expr::FieldAccess { ref field, .. } if field.name == "field"));
5402 }
5403
5404 #[test]
5405 fn expr_method_call() {
5406 let (e, diags) = parse_expr_str("obj.method(1, 2)");
5407 assert!(!diags.has_errors(), "{diags:?}");
5408 assert!(matches!(e, Expr::MethodCall { ref method, .. } if method.name == "method"));
5409 }
5410
5411 #[test]
5412 fn expr_function_call() {
5413 let (e, diags) = parse_expr_str("foo(1, 2, 3)");
5414 assert!(!diags.has_errors(), "{diags:?}");
5415 match e {
5416 Expr::Call { args, .. } => assert_eq!(args.len(), 3),
5417 _ => panic!("expected Call"),
5418 }
5419 }
5420
5421 #[test]
5422 fn expr_labeled_arg() {
5423 let (e, diags) = parse_expr_str("foo(x: 1, y: 2)");
5424 assert!(!diags.has_errors(), "{diags:?}");
5425 match e {
5426 Expr::Call { args, .. } => {
5427 assert_eq!(args.len(), 2);
5428 assert_eq!(args[0].label.as_ref().map(|i| i.name.as_str()), Some("x"));
5429 assert_eq!(args[1].label.as_ref().map(|i| i.name.as_str()), Some("y"));
5430 }
5431 _ => panic!("expected Call"),
5432 }
5433 }
5434
5435 #[test]
5436 fn expr_index_access() {
5437 let (e, diags) = parse_expr_str("arr[0]");
5438 assert!(!diags.has_errors(), "{diags:?}");
5439 assert!(matches!(e, Expr::Index { .. }));
5440 }
5441
5442 #[test]
5443 fn expr_postfix_chain() {
5444 let (e, diags) = parse_expr_str("obj.method(arg).field");
5446 assert!(!diags.has_errors(), "{diags:?}");
5447 match e {
5449 Expr::FieldAccess {
5450 ref field,
5451 ref object,
5452 ..
5453 } => {
5454 assert_eq!(field.name, "field");
5455 assert!(matches!(**object, Expr::MethodCall { .. }));
5456 }
5457 _ => panic!("expected FieldAccess, got {e:?}"),
5458 }
5459 }
5460
5461 #[test]
5462 fn expr_deep_postfix_chain() {
5463 let (e, diags) = parse_expr_str("a.b(c).d[0]?");
5464 assert!(!diags.has_errors(), "{diags:?}");
5465 assert!(matches!(e, Expr::Try { .. }));
5466 }
5467
5468 #[test]
5469 fn expr_pipe_operator() {
5470 let (e, diags) = parse_expr_str("data |> parse");
5471 assert!(!diags.has_errors(), "{diags:?}");
5472 assert!(matches!(e, Expr::Pipe { .. }));
5473 }
5474
5475 #[test]
5476 fn expr_pipe_chain() {
5477 let (e, diags) = parse_expr_str("a |> b |> c");
5479 assert!(!diags.has_errors(), "{diags:?}");
5480 match e {
5481 Expr::Pipe { left, .. } => {
5482 assert!(matches!(*left, Expr::Pipe { .. }));
5483 }
5484 _ => panic!("expected Pipe"),
5485 }
5486 }
5487
5488 #[test]
5489 fn expr_compose_operator() {
5490 let (e, diags) = parse_expr_str("parse >> validate");
5491 assert!(!diags.has_errors(), "{diags:?}");
5492 assert!(matches!(e, Expr::Compose { .. }));
5493 }
5494
5495 #[test]
5496 fn expr_range_exclusive() {
5497 let (e, diags) = parse_expr_str("1..10");
5498 assert!(!diags.has_errors(), "{diags:?}");
5499 assert!(matches!(
5500 e,
5501 Expr::Range {
5502 inclusive: false,
5503 ..
5504 }
5505 ));
5506 }
5507
5508 #[test]
5509 fn expr_range_inclusive() {
5510 let (e, diags) = parse_expr_str("1..=10");
5511 assert!(!diags.has_errors(), "{diags:?}");
5512 assert!(matches!(
5513 e,
5514 Expr::Range {
5515 inclusive: true,
5516 ..
5517 }
5518 ));
5519 }
5520
5521 #[test]
5522 fn expr_bitwise_operators() {
5523 let cases = [
5524 ("a & b", BinOp::BitAnd),
5525 ("a | b", BinOp::BitOr),
5526 ("a ^ b", BinOp::BitXor),
5527 ];
5528 for (src, op) in cases {
5529 let (e, diags) = parse_expr_str(src);
5530 assert!(!diags.has_errors(), "errors for {src}: {diags:?}");
5531 assert!(matches!(&e, Expr::Binary { op: actual, .. } if *actual == op));
5532 }
5533 }
5534
5535 #[test]
5536 fn shl_is_parse_error() {
5537 let (e, _) = parse_expr_str("a << 2");
5541 assert!(
5542 !matches!(&e, Expr::Binary { .. }),
5543 "`<<` must not be parsed as infix binary operator"
5544 );
5545 }
5546
5547 #[test]
5548 fn compose_still_works() {
5549 let (e, diags) = parse_expr_str("f >> g");
5551 assert!(!diags.has_errors(), "{diags:?}");
5552 assert!(matches!(e, Expr::Compose { .. }));
5553 }
5554
5555 #[test]
5556 fn precedence_add_mul_after_renumber() {
5557 let (e, diags) = parse_expr_str("a + b * c");
5559 assert!(!diags.has_errors(), "{diags:?}");
5560 match &e {
5562 Expr::Binary { op, right, .. } => {
5563 assert_eq!(*op, BinOp::Add);
5564 assert!(
5565 matches!(right.as_ref(), Expr::Binary { op: inner_op, .. } if *inner_op == BinOp::Mul),
5566 "right side of Add should be Mul"
5567 );
5568 }
5569 _ => panic!("expected Binary(Add) at top level"),
5570 }
5571 }
5572
5573 #[test]
5574 fn expr_placeholder() {
5575 let (e, diags) = parse_expr_str("_");
5576 assert!(!diags.has_errors(), "{diags:?}");
5577 assert!(matches!(e, Expr::Placeholder { .. }));
5578 }
5579
5580 #[test]
5581 fn expr_list_literal() {
5582 let (e, diags) = parse_expr_str("[1, 2, 3]");
5583 assert!(!diags.has_errors(), "{diags:?}");
5584 match e {
5585 Expr::ListLiteral { elems, .. } => assert_eq!(elems.len(), 3),
5586 _ => panic!("expected ListLiteral"),
5587 }
5588 }
5589
5590 #[test]
5591 fn expr_empty_list() {
5592 let (e, diags) = parse_expr_str("[]");
5593 assert!(!diags.has_errors(), "{diags:?}");
5594 assert!(matches!(e, Expr::ListLiteral { ref elems, .. } if elems.is_empty()));
5595 }
5596
5597 #[test]
5598 fn expr_tuple_literal() {
5599 let (e, diags) = parse_expr_str("(1, 2, 3)");
5600 assert!(!diags.has_errors(), "{diags:?}");
5601 match e {
5602 Expr::TupleLiteral { elems, .. } => assert_eq!(elems.len(), 3),
5603 _ => panic!("expected TupleLiteral, got {e:?}"),
5604 }
5605 }
5606
5607 #[test]
5608 fn expr_unit_literal() {
5609 let (e, diags) = parse_expr_str("()");
5610 assert!(!diags.has_errors(), "{diags:?}");
5611 assert!(matches!(
5612 e,
5613 Expr::Literal {
5614 lit: Literal::Unit,
5615 ..
5616 }
5617 ));
5618 }
5619
5620 #[test]
5621 fn expr_set_literal() {
5622 let (e, diags) = parse_expr_str(r#"#{"a", "b"}"#);
5623 assert!(!diags.has_errors(), "{diags:?}");
5624 match e {
5625 Expr::SetLiteral { elems, .. } => assert_eq!(elems.len(), 2),
5626 _ => panic!("expected SetLiteral"),
5627 }
5628 }
5629
5630 #[test]
5631 fn expr_map_literal() {
5632 let (e, diags) = parse_expr_str(r#"{"key": "value"}"#);
5633 assert!(!diags.has_errors(), "{diags:?}");
5634 match e {
5635 Expr::MapLiteral { entries, .. } => assert_eq!(entries.len(), 1),
5636 _ => panic!("expected MapLiteral, got {e:?}"),
5637 }
5638 }
5639
5640 #[test]
5641 fn empty_map_literal_with_type_annotation() {
5642 let src = "fn test() {\nlet m: Map[String, Int] = {}\n}";
5644 let (m, diags) = parse(src);
5645 assert!(!diags.has_errors(), "{diags:?}");
5646 let f = match m.items.first().unwrap() {
5647 Item::Fn(f) => f,
5648 other => panic!("expected Fn, got {other:?}"),
5649 };
5650 let body = f.body.as_ref().expect("expected body");
5651 let stmt = body.stmts.first().expect("expected a statement");
5652 match stmt {
5653 Stmt::Let(let_stmt) => match &let_stmt.value {
5654 Expr::MapLiteral { entries, .. } => assert!(entries.is_empty()),
5655 other => panic!("expected MapLiteral, got {other:?}"),
5656 },
5657 other => panic!("expected Let, got {other:?}"),
5658 }
5659 }
5660
5661 #[test]
5662 fn empty_braces_without_map_annotation_is_block() {
5663 let src = "fn test() {\nlet x = {}\n}";
5665 let (m, diags) = parse(src);
5666 assert!(!diags.has_errors(), "{diags:?}");
5667 let f = match m.items.first().unwrap() {
5668 Item::Fn(f) => f,
5669 other => panic!("expected Fn, got {other:?}"),
5670 };
5671 let body = f.body.as_ref().expect("expected body");
5672 let stmt = body.stmts.first().expect("expected a statement");
5673 match stmt {
5674 Stmt::Let(let_stmt) => assert!(
5675 matches!(&let_stmt.value, Expr::Block { .. }),
5676 "expected Block, got {:?}",
5677 let_stmt.value
5678 ),
5679 other => panic!("expected Let, got {other:?}"),
5680 }
5681 }
5682
5683 #[test]
5684 fn if_empty_block_still_works() {
5685 let (e, diags) = parse_expr_str("if (true) {}");
5687 assert!(!diags.has_errors(), "{diags:?}");
5688 assert!(matches!(e, Expr::If { .. }));
5689 }
5690
5691 #[test]
5692 fn expr_block_is_expression() {
5693 let src = "fn test() {\n{ let x = 1\nx }\n}";
5694 let (m, diags) = parse(src);
5695 assert!(!diags.has_errors(), "{diags:?}");
5696 let fn_decl = match m.items.first().unwrap() {
5697 Item::Fn(f) => f,
5698 _ => panic!(),
5699 };
5700 let body = fn_decl.body.as_ref().expect("expected function body");
5702 let tail = body.tail.as_ref().expect("expected tail");
5703 assert!(matches!(**tail, Expr::Block { .. }));
5704 }
5705
5706 #[test]
5707 fn expr_if_expression() {
5708 let (e, diags) = parse_expr_str("if (cond) { a } else { b }");
5709 assert!(!diags.has_errors(), "{diags:?}");
5710 match e {
5711 Expr::If {
5712 let_pattern,
5713 else_block,
5714 ..
5715 } => {
5716 assert!(let_pattern.is_none());
5717 assert!(else_block.is_some());
5718 }
5719 _ => panic!("expected If expr, got {e:?}"),
5720 }
5721 }
5722
5723 #[test]
5724 fn expr_if_no_else() {
5725 let (e, diags) = parse_expr_str("if (x > 0) { foo() }");
5726 assert!(!diags.has_errors(), "{diags:?}");
5727 assert!(matches!(
5728 e,
5729 Expr::If {
5730 else_block: None,
5731 ..
5732 }
5733 ));
5734 }
5735
5736 #[test]
5737 fn expr_if_let() {
5738 let (e, diags) = parse_expr_str("if (let Some(v) = opt) { v }");
5739 assert!(!diags.has_errors(), "{diags:?}");
5740 match e {
5741 Expr::If {
5742 let_pattern: Some(p),
5743 ..
5744 } => {
5745 assert!(matches!(p, Pattern::Constructor { .. }));
5746 }
5747 _ => panic!("expected if-let, got {e:?}"),
5748 }
5749 }
5750
5751 #[test]
5752 fn expr_if_else_if_chain() {
5753 let (e, diags) = parse_expr_str("if (a) { 1 } else if (b) { 2 } else { 3 }");
5754 assert!(!diags.has_errors(), "{diags:?}");
5755 match e {
5756 Expr::If {
5757 else_block: Some(else_e),
5758 ..
5759 } => {
5760 assert!(matches!(*else_e, Expr::If { .. }));
5761 }
5762 _ => panic!("expected if-else-if chain"),
5763 }
5764 }
5765
5766 #[test]
5767 fn expr_match() {
5768 let src = "match val {\n 0 => zero\n n => other\n}";
5769 let (e, diags) = parse_expr_str(src);
5770 assert!(!diags.has_errors(), "{diags:?}");
5771 match e {
5772 Expr::Match { arms, .. } => assert_eq!(arms.len(), 2),
5773 _ => panic!("expected Match"),
5774 }
5775 }
5776
5777 #[test]
5778 fn expr_match_with_guard() {
5779 let src = "match x {\n n if (n > 0) => pos\n _ => other\n}";
5780 let (e, diags) = parse_expr_str(src);
5781 assert!(!diags.has_errors(), "{diags:?}");
5782 match e {
5783 Expr::Match { arms, .. } => {
5784 assert!(arms[0].guard.is_some());
5785 assert!(arms[1].guard.is_none());
5786 }
5787 _ => panic!("expected Match"),
5788 }
5789 }
5790
5791 #[test]
5792 fn expr_lambda_single_param() {
5793 let (e, diags) = parse_expr_str("(x) => x * 2");
5794 assert!(!diags.has_errors(), "{diags:?}");
5795 match e {
5796 Expr::Lambda { params, body, .. } => {
5797 assert_eq!(params.len(), 1);
5798 assert!(matches!(*body, Expr::Binary { op: BinOp::Mul, .. }));
5799 }
5800 _ => panic!("expected Lambda, got {e:?}"),
5801 }
5802 }
5803
5804 #[test]
5805 fn expr_lambda_no_params() {
5806 let (e, diags) = parse_expr_str("() => 42");
5807 assert!(!diags.has_errors(), "{diags:?}");
5808 match e {
5809 Expr::Lambda { params, .. } => assert_eq!(params.len(), 0),
5810 _ => panic!("expected Lambda"),
5811 }
5812 }
5813
5814 #[test]
5815 fn expr_lambda_block_body() {
5816 let (e, diags) = parse_expr_str("(a, b) => { a + b }");
5817 assert!(!diags.has_errors(), "{diags:?}");
5818 match e {
5819 Expr::Lambda { params, body, .. } => {
5820 assert_eq!(params.len(), 2);
5821 assert!(matches!(*body, Expr::Block { .. }));
5822 }
5823 _ => panic!("expected Lambda"),
5824 }
5825 }
5826
5827 #[test]
5828 fn expr_lambda_typed_params() {
5829 let (e, diags) = parse_expr_str("(x: Int) => x");
5830 assert!(!diags.has_errors(), "{diags:?}");
5831 match e {
5832 Expr::Lambda { params, .. } => {
5833 assert_eq!(params.len(), 1);
5834 assert!(params[0].ty.is_some());
5835 }
5836 _ => panic!("expected Lambda"),
5837 }
5838 }
5839
5840 #[test]
5841 fn expr_return() {
5842 let (e, diags) = parse_expr_str("return 42");
5843 assert!(!diags.has_errors(), "{diags:?}");
5844 assert!(matches!(e, Expr::Return { value: Some(_), .. }));
5845 }
5846
5847 #[test]
5848 fn expr_return_void() {
5849 let src = "fn test() {\nreturn\n}";
5851 let (m, diags) = parse(src);
5852 assert!(!diags.has_errors(), "{diags:?}");
5853 let fn_decl = match m.items.first().unwrap() {
5854 Item::Fn(f) => f,
5855 _ => panic!(),
5856 };
5857 let body = fn_decl.body.as_ref().expect("expected function body");
5859 let has_return = body
5860 .tail
5861 .as_ref()
5862 .map(|t| matches!(**t, Expr::Return { .. }))
5863 .or_else(|| {
5864 body.stmts
5865 .last()
5866 .map(|s| matches!(s, Stmt::Expr(Expr::Return { .. })))
5867 })
5868 .unwrap_or(false);
5869 assert!(has_return, "expected return expr in body");
5870 }
5871
5872 #[test]
5873 fn expr_await() {
5874 let (e, diags) = parse_expr_str("await foo()");
5875 assert!(!diags.has_errors(), "{diags:?}");
5876 assert!(matches!(e, Expr::Await { .. }));
5877 }
5878
5879 #[test]
5880 fn expr_await_postfix() {
5881 let (e, diags) = parse_expr_str("foo().await");
5882 assert!(!diags.has_errors(), "{diags:?}");
5883 assert!(matches!(e, Expr::Await { .. }));
5884 }
5885
5886 #[test]
5887 fn expr_unreachable() {
5888 let (e, diags) = parse_expr_str("unreachable");
5889 assert!(!diags.has_errors(), "{diags:?}");
5890 assert!(matches!(e, Expr::Unreachable { .. }));
5891 }
5892
5893 #[test]
5894 fn expr_is_simple_type() {
5895 let (e, diags) = parse_expr_str("value is Int");
5896 assert!(!diags.has_errors(), "{diags:?}");
5897 match &e {
5898 Expr::Is { type_expr, .. } => {
5899 if let TypeExpr::Named { path, args, .. } = type_expr {
5900 assert_eq!(path.segments[0].name, "Int");
5901 assert!(args.is_empty());
5902 } else {
5903 panic!("expected Named type_expr, got {type_expr:?}");
5904 }
5905 }
5906 _ => panic!("expected Expr::Is, got {e:?}"),
5907 }
5908 }
5909
5910 #[test]
5911 fn expr_is_generic_args_preserved() {
5912 let (e, diags) = parse_expr_str("x is Option[Int]");
5913 assert!(!diags.has_errors(), "{diags:?}");
5914 match &e {
5915 Expr::Is { type_expr, .. } => {
5916 if let TypeExpr::Named { path, args, .. } = type_expr {
5917 assert_eq!(path.segments[0].name, "Option");
5918 assert_eq!(args.len(), 1);
5919 } else {
5920 panic!("expected Named type_expr, got {type_expr:?}");
5921 }
5922 }
5923 _ => panic!("expected Expr::Is, got {e:?}"),
5924 }
5925 }
5926
5927 #[test]
5928 fn expr_is_multi_arg_generic() {
5929 let (e, diags) = parse_expr_str("x is Result[String, Error]");
5930 assert!(!diags.has_errors(), "{diags:?}");
5931 match &e {
5932 Expr::Is { type_expr, .. } => {
5933 if let TypeExpr::Named { path, args, .. } = type_expr {
5934 assert_eq!(path.segments[0].name, "Result");
5935 assert_eq!(args.len(), 2);
5936 } else {
5937 panic!("expected Named type_expr, got {type_expr:?}");
5938 }
5939 }
5940 _ => panic!("expected Expr::Is, got {e:?}"),
5941 }
5942 }
5943
5944 #[test]
5945 fn expr_is_nested_generic() {
5946 let (e, diags) = parse_expr_str("x is List[List[Int]]");
5947 assert!(!diags.has_errors(), "{diags:?}");
5948 match &e {
5949 Expr::Is { type_expr, .. } => {
5950 if let TypeExpr::Named { path, args, .. } = type_expr {
5951 assert_eq!(path.segments[0].name, "List");
5952 assert_eq!(args.len(), 1);
5953 if let TypeExpr::Named {
5955 path: inner,
5956 args: inner_args,
5957 ..
5958 } = &args[0]
5959 {
5960 assert_eq!(inner.segments[0].name, "List");
5961 assert_eq!(inner_args.len(), 1);
5962 } else {
5963 panic!("expected nested Named type_expr");
5964 }
5965 } else {
5966 panic!("expected Named type_expr, got {type_expr:?}");
5967 }
5968 }
5969 _ => panic!("expected Expr::Is, got {e:?}"),
5970 }
5971 }
5972
5973 #[test]
5974 fn expr_record_construct() {
5975 let (e, diags) = parse_expr_str("User { id: 1, name }");
5976 assert!(!diags.has_errors(), "{diags:?}");
5977 match e {
5978 Expr::RecordConstruct {
5979 path,
5980 fields,
5981 spread,
5982 ..
5983 } => {
5984 assert_eq!(path.segments[0].name, "User");
5985 assert_eq!(fields.len(), 2);
5986 assert_eq!(fields[0].name.name, "id");
5987 assert!(fields[0].value.is_some()); assert_eq!(fields[1].name.name, "name");
5989 assert!(fields[1].value.is_none()); assert!(spread.is_none());
5991 }
5992 _ => panic!("expected RecordConstruct, got {e:?}"),
5993 }
5994 }
5995
5996 #[test]
5997 fn expr_record_construct_with_spread() {
5998 let (e, diags) = parse_expr_str("User { name, ..defaults }");
5999 assert!(!diags.has_errors(), "{diags:?}");
6000 match e {
6001 Expr::RecordConstruct { spread, .. } => {
6002 assert!(spread.is_some());
6003 }
6004 _ => panic!("expected RecordConstruct"),
6005 }
6006 }
6007
6008 #[test]
6009 fn expr_let_statement_in_block() {
6010 let src = "fn test() {\nlet x = 42\nx\n}";
6011 let (m, diags) = parse(src);
6012 assert!(!diags.has_errors(), "{diags:?}");
6013 let fn_decl = match m.items.first().unwrap() {
6014 Item::Fn(f) => f,
6015 _ => panic!(),
6016 };
6017 let body = fn_decl.body.as_ref().expect("expected function body");
6018 assert_eq!(body.stmts.len(), 1);
6019 assert!(matches!(body.stmts[0], Stmt::Let(_)));
6020 assert!(body.tail.is_some());
6021 }
6022
6023 #[test]
6024 fn expr_let_mut_in_block() {
6025 let src = "fn test() {\nlet mut x = 0\nx\n}";
6026 let (m, diags) = parse(src);
6027 assert!(!diags.has_errors(), "{diags:?}");
6028 let fn_decl = match m.items.first().unwrap() {
6029 Item::Fn(f) => f,
6030 _ => panic!(),
6031 };
6032 let body = fn_decl.body.as_ref().expect("expected function body");
6033 assert!(
6034 matches!(&body.stmts[0], Stmt::Let(l) if matches!(l.pattern, Pattern::MutBind { .. }))
6035 );
6036 }
6037
6038 #[test]
6039 fn expr_for_loop_in_block() {
6040 let src = "fn test() {\nfor x in items { foo(x) }\n}";
6041 let (m, diags) = parse(src);
6042 assert!(!diags.has_errors(), "{diags:?}");
6043 let fn_decl = match m.items.first().unwrap() {
6044 Item::Fn(f) => f,
6045 _ => panic!(),
6046 };
6047 assert!(matches!(
6048 &fn_decl.body.as_ref().unwrap().stmts[0],
6049 Stmt::For(_)
6050 ));
6051 }
6052
6053 #[test]
6054 fn expr_while_loop_in_block() {
6055 let src = "fn test() {\nwhile (x > 0) { x -= 1 }\n}";
6056 let (m, diags) = parse(src);
6057 assert!(!diags.has_errors(), "{diags:?}");
6058 let fn_decl = match m.items.first().unwrap() {
6059 Item::Fn(f) => f,
6060 _ => panic!(),
6061 };
6062 assert!(matches!(
6063 &fn_decl.body.as_ref().unwrap().stmts[0],
6064 Stmt::While(_)
6065 ));
6066 }
6067
6068 #[test]
6069 fn expr_loop_in_block() {
6070 let src = "fn test() {\nloop { break }\n}";
6071 let (m, diags) = parse(src);
6072 assert!(!diags.has_errors(), "{diags:?}");
6073 let fn_decl = match m.items.first().unwrap() {
6074 Item::Fn(f) => f,
6075 _ => panic!(),
6076 };
6077 assert!(matches!(
6079 fn_decl.body.as_ref().unwrap().tail.as_deref(),
6080 Some(Expr::Loop { .. })
6081 ));
6082 }
6083
6084 #[test]
6085 fn expr_complex_expression() {
6086 let (e, diags) = parse_expr_str("data |> parse |> validate");
6088 assert!(!diags.has_errors(), "{diags:?}");
6089 match e {
6091 Expr::Pipe { left, .. } => {
6092 assert!(matches!(*left, Expr::Pipe { .. }));
6093 }
6094 _ => panic!("expected Pipe chain"),
6095 }
6096 }
6097
6098 #[test]
6099 fn expr_nested_binary() {
6100 let (e, diags) = parse_expr_str("(a + b) * c");
6102 assert!(!diags.has_errors(), "{diags:?}");
6103 match e {
6104 Expr::Binary {
6105 op: BinOp::Mul,
6106 left,
6107 ..
6108 } => {
6109 assert!(matches!(*left, Expr::Binary { op: BinOp::Add, .. }));
6110 }
6111 _ => panic!("expected Mul expr"),
6112 }
6113 }
6114
6115 #[test]
6116 fn expr_pattern_constructor_in_match() {
6117 let src = "match opt {\n Some(x) => x\n None => 0\n}";
6118 let (e, diags) = parse_expr_str(src);
6119 assert!(!diags.has_errors(), "{diags:?}");
6120 match e {
6121 Expr::Match { arms, .. } => {
6122 assert!(matches!(&arms[0].pattern, Pattern::Constructor { .. }));
6123 assert!(matches!(&arms[1].pattern, Pattern::Constructor { .. }));
6124 }
6125 _ => panic!("expected Match"),
6126 }
6127 }
6128
6129 #[test]
6130 fn expr_pattern_wildcard_in_match() {
6131 let src = "match x {\n _ => 0\n}";
6132 let (e, diags) = parse_expr_str(src);
6133 assert!(!diags.has_errors(), "{diags:?}");
6134 match e {
6135 Expr::Match { arms, .. } => {
6136 assert!(matches!(&arms[0].pattern, Pattern::Wildcard { .. }));
6137 }
6138 _ => panic!("expected Match"),
6139 }
6140 }
6141
6142 #[test]
6143 fn expr_pattern_or() {
6144 let src = "match x {\n 1 | 2 => few\n _ => many\n}";
6145 let (e, diags) = parse_expr_str(src);
6146 assert!(!diags.has_errors(), "{diags:?}");
6147 match e {
6148 Expr::Match { arms, .. } => {
6149 assert!(matches!(&arms[0].pattern, Pattern::Or { .. }));
6150 }
6151 _ => panic!("expected Match"),
6152 }
6153 }
6154
6155 #[test]
6156 fn expr_if_as_primary_expression() {
6157 let src = "fn test() {\nlet x = if (cond) { a } else { b }\nx\n}";
6159 let (m, diags) = parse(src);
6160 assert!(!diags.has_errors(), "{diags:?}");
6161 let fn_decl = match m.items.first().unwrap() {
6162 Item::Fn(f) => f,
6163 _ => panic!(),
6164 };
6165 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6167 Stmt::Let(l) => {
6168 assert!(
6169 matches!(l.value, Expr::If { .. }),
6170 "expected If as let value"
6171 );
6172 }
6173 _ => panic!("expected Let stmt"),
6174 }
6175 }
6176
6177 #[test]
6178 fn expr_match_as_primary_expression() {
6179 let src = "fn test() {\nlet x = match val {\n1 => a\n_ => b\n}\nx\n}";
6181 let (m, diags) = parse(src);
6182 assert!(!diags.has_errors(), "{diags:?}");
6183 let fn_decl = match m.items.first().unwrap() {
6184 Item::Fn(f) => f,
6185 _ => panic!(),
6186 };
6187 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6188 Stmt::Let(l) => {
6189 assert!(
6190 matches!(l.value, Expr::Match { .. }),
6191 "expected Match as let value"
6192 );
6193 }
6194 _ => panic!("expected Let stmt"),
6195 }
6196 }
6197
6198 #[test]
6199 fn expr_loop_as_primary_expression() {
6200 let src = "fn test() {\nlet x = loop {\nbreak 42\n}\nx\n}";
6202 let (m, diags) = parse(src);
6203 assert!(!diags.has_errors(), "{diags:?}");
6204 let fn_decl = match m.items.first().unwrap() {
6205 Item::Fn(f) => f,
6206 _ => panic!(),
6207 };
6208 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6209 Stmt::Let(l) => {
6210 assert!(
6211 matches!(l.value, Expr::Loop { .. }),
6212 "expected Loop as let value"
6213 );
6214 }
6215 _ => panic!("expected Let stmt"),
6216 }
6217 }
6218
6219 #[test]
6220 fn expr_loop_as_function_arg() {
6221 let src = "fn test() {\nfoo(loop { break 1 })\n}";
6222 let (m, diags) = parse(src);
6223 assert!(!diags.has_errors(), "{diags:?}");
6224 let fn_decl = match m.items.first().unwrap() {
6225 Item::Fn(f) => f,
6226 _ => panic!(),
6227 };
6228 let tail = fn_decl
6230 .body
6231 .as_ref()
6232 .unwrap()
6233 .tail
6234 .as_ref()
6235 .expect("expected tail");
6236 match tail.as_ref() {
6237 Expr::Call { args, .. } => {
6238 assert!(
6239 matches!(args[0].value, Expr::Loop { .. }),
6240 "expected Loop as arg"
6241 );
6242 }
6243 _ => panic!("expected Call expr"),
6244 }
6245 }
6246
6247 #[test]
6248 fn stmt_let_with_type_annotation() {
6249 let src = "fn test() {\nlet x: Int = 42\nx\n}";
6250 let (m, diags) = parse(src);
6251 assert!(!diags.has_errors(), "{diags:?}");
6252 let fn_decl = match m.items.first().unwrap() {
6253 Item::Fn(f) => f,
6254 _ => panic!(),
6255 };
6256 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6257 Stmt::Let(l) => {
6258 assert!(l.ty.is_some(), "expected type annotation on let");
6259 }
6260 _ => panic!("expected Let stmt"),
6261 }
6262 }
6263
6264 #[test]
6265 fn stmt_let_with_tuple_destructuring() {
6266 let src = "fn test() {\nlet (x, y) = get_point()\nx\n}";
6267 let (m, diags) = parse(src);
6268 assert!(!diags.has_errors(), "{diags:?}");
6269 let fn_decl = match m.items.first().unwrap() {
6270 Item::Fn(f) => f,
6271 _ => panic!(),
6272 };
6273 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6274 Stmt::Let(l) => {
6275 assert!(
6276 matches!(l.pattern, Pattern::Tuple { .. }),
6277 "expected tuple pattern, got {:?}",
6278 l.pattern
6279 );
6280 }
6281 _ => panic!("expected Let stmt"),
6282 }
6283 }
6284
6285 #[test]
6286 fn stmt_guard_in_block() {
6287 let src = "fn test() {\nguard (x > 0) else { return }\nx\n}";
6288 let (m, diags) = parse(src);
6289 assert!(!diags.has_errors(), "{diags:?}");
6290 let fn_decl = match m.items.first().unwrap() {
6291 Item::Fn(f) => f,
6292 _ => panic!(),
6293 };
6294 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6295 Stmt::Guard(g) => {
6296 assert!(
6297 !g.else_block.stmts.is_empty()
6298 || g.else_block.tail.is_some()
6299 || !g.else_block.stmts.is_empty(),
6300 "expected non-empty else block"
6301 );
6302 }
6303 _ => panic!(
6304 "expected Guard stmt, got {:?}",
6305 fn_decl.body.as_ref().unwrap().stmts[0]
6306 ),
6307 }
6308 }
6309
6310 #[test]
6311 fn stmt_handling_block_with_multiple_bindings() {
6312 let src = "fn test() {\nhandling (Log with logger, Clock with mock) {\ndo_work()\n}\n}";
6313 let (m, diags) = parse(src);
6314 assert!(!diags.has_errors(), "{diags:?}");
6315 let fn_decl = match m.items.first().unwrap() {
6316 Item::Fn(f) => f,
6317 _ => panic!(),
6318 };
6319 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6320 Stmt::Handling(h) => {
6321 assert_eq!(h.handlers.len(), 2, "expected 2 handler bindings");
6322 }
6323 _ => panic!(
6324 "expected Handling stmt, got {:?}",
6325 fn_decl.body.as_ref().unwrap().stmts[0]
6326 ),
6327 }
6328 }
6329
6330 #[test]
6331 fn stmt_handling_block_single_binding() {
6332 let src = "fn test() {\nhandling (Log with handler) {\ndo_work()\n}\n}";
6333 let (m, diags) = parse(src);
6334 assert!(!diags.has_errors(), "{diags:?}");
6335 let fn_decl = match m.items.first().unwrap() {
6336 Item::Fn(f) => f,
6337 _ => panic!(),
6338 };
6339 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6340 Stmt::Handling(h) => {
6341 assert_eq!(h.handlers.len(), 1);
6342 }
6343 _ => panic!("expected Handling stmt"),
6344 }
6345 }
6346
6347 #[test]
6348 fn stmt_continuation_operator_at_end_of_line() {
6349 let src = "fn test() {\nlet x = a +\n b\nx\n}";
6351 let (m, diags) = parse(src);
6352 assert!(!diags.has_errors(), "{diags:?}");
6353 let fn_decl = match m.items.first().unwrap() {
6354 Item::Fn(f) => f,
6355 _ => panic!(),
6356 };
6357 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6358 Stmt::Let(l) => {
6359 assert!(
6360 matches!(l.value, Expr::Binary { op: BinOp::Add, .. }),
6361 "expected binary Add across lines"
6362 );
6363 }
6364 _ => panic!("expected Let stmt"),
6365 }
6366 }
6367
6368 #[test]
6369 fn stmt_continuation_pipe_at_start_of_next_line() {
6370 let src = "fn test() {\nlet x = data\n |> transform\nx\n}";
6372 let (m, diags) = parse(src);
6373 assert!(!diags.has_errors(), "{diags:?}");
6374 let fn_decl = match m.items.first().unwrap() {
6375 Item::Fn(f) => f,
6376 _ => panic!(),
6377 };
6378 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6379 Stmt::Let(l) => {
6380 assert!(
6381 matches!(l.value, Expr::Pipe { .. }),
6382 "expected Pipe across lines"
6383 );
6384 }
6385 _ => panic!("expected Let stmt"),
6386 }
6387 }
6388
6389 #[test]
6390 fn stmt_continuation_dot_at_start_of_next_line() {
6391 let src = "fn test() {\nlet x = obj\n .field\nx\n}";
6393 let (m, diags) = parse(src);
6394 assert!(!diags.has_errors(), "{diags:?}");
6395 let fn_decl = match m.items.first().unwrap() {
6396 Item::Fn(f) => f,
6397 _ => panic!(),
6398 };
6399 match &fn_decl.body.as_ref().unwrap().stmts[0] {
6400 Stmt::Let(l) => {
6401 assert!(
6402 matches!(l.value, Expr::FieldAccess { .. }),
6403 "expected FieldAccess across lines"
6404 );
6405 }
6406 _ => panic!("expected Let stmt"),
6407 }
6408 }
6409
6410 #[test]
6411 fn stmt_continuation_else_on_next_line() {
6412 let src = "fn test() -> Int {\nif (true) { 1 }\nelse { 2 }\n}";
6414 let (m, diags) = parse(src);
6415 assert!(!diags.has_errors(), "{diags:?}");
6416 let fn_decl = match m.items.first().unwrap() {
6417 Item::Fn(f) => f,
6418 _ => panic!(),
6419 };
6420 let tail = fn_decl.body.as_ref().unwrap().tail.as_ref().expect("expected tail expr");
6422 match tail.as_ref() {
6423 Expr::If { else_block, .. } => {
6424 assert!(else_block.is_some(), "expected else block across lines");
6425 }
6426 other => panic!("expected If expr, got {other:?}"),
6427 }
6428 }
6429
6430 #[test]
6431 fn stmt_continuation_else_if_on_next_line() {
6432 let src = "fn test() -> Int {\nif (true) { 1 }\nelse if (false) { 2 }\nelse { 3 }\n}";
6434 let (m, diags) = parse(src);
6435 assert!(!diags.has_errors(), "{diags:?}");
6436 let fn_decl = match m.items.first().unwrap() {
6437 Item::Fn(f) => f,
6438 _ => panic!(),
6439 };
6440 let tail = fn_decl.body.as_ref().unwrap().tail.as_ref().expect("expected tail expr");
6441 match tail.as_ref() {
6442 Expr::If { else_block, .. } => {
6443 let inner = else_block.as_ref().expect("expected else-if chain");
6444 assert!(
6445 matches!(inner.as_ref(), Expr::If { .. }),
6446 "expected nested If in else-if chain"
6447 );
6448 }
6449 other => panic!("expected If expr, got {other:?}"),
6450 }
6451 }
6452
6453 #[test]
6454 fn stmt_semicolon_separates_statements() {
6455 let src = "fn test() {\nlet x = 1; let y = 2\nx\n}";
6457 let (m, diags) = parse(src);
6458 assert!(!diags.has_errors(), "{diags:?}");
6459 let fn_decl = match m.items.first().unwrap() {
6460 Item::Fn(f) => f,
6461 _ => panic!(),
6462 };
6463 assert_eq!(
6464 fn_decl.body.as_ref().unwrap().stmts.len(),
6465 2,
6466 "expected 2 stmts from semicolon-separated line"
6467 );
6468 }
6469
6470 #[test]
6471 fn stmt_loop_break_with_value() {
6472 let src = "fn test() {\nloop { break 42 }\n}";
6474 let (m, diags) = parse(src);
6475 assert!(!diags.has_errors(), "{diags:?}");
6476 let fn_decl = match m.items.first().unwrap() {
6477 Item::Fn(f) => f,
6478 _ => panic!(),
6479 };
6480 match fn_decl.body.as_ref().unwrap().tail.as_deref() {
6482 Some(Expr::Loop { body, .. }) => {
6483 let has_break = body
6485 .stmts
6486 .iter()
6487 .any(|s| matches!(s, Stmt::Expr(Expr::Break { value: Some(_), .. })))
6488 || body
6489 .tail
6490 .as_ref()
6491 .is_some_and(|t| matches!(**t, Expr::Break { value: Some(_), .. }));
6492 assert!(has_break, "expected break with value in loop body");
6493 }
6494 _ => panic!("expected Loop tail expression"),
6495 }
6496 }
6497
6498 fn parse_pat(src: &str) -> (Pattern, DiagnosticBag) {
6501 let wrapped = format!("fn f() {{ match x {{\n{src}\n}} }}");
6503 let (m, diags) = parse(&wrapped);
6504 let fn_decl = match m.items.first().unwrap() {
6505 Item::Fn(f) => f,
6506 _ => panic!("expected fn"),
6507 };
6508 let mat = match fn_decl.body.as_ref().unwrap().tail.as_deref() {
6509 Some(Expr::Match { arms, .. }) => arms.clone(),
6510 _ => match fn_decl.body.as_ref().unwrap().stmts.first() {
6511 Some(Stmt::Expr(Expr::Match { arms, .. })) => arms.clone(),
6512 _ => panic!("expected match expression"),
6513 },
6514 };
6515 let pat = mat
6516 .into_iter()
6517 .next()
6518 .expect("expected at least one arm")
6519 .pattern;
6520 (pat, diags)
6521 }
6522
6523 #[test]
6524 fn pattern_wildcard() {
6525 let (pat, diags) = parse_pat("_ => 1");
6526 assert!(!diags.has_errors(), "{diags:?}");
6527 assert!(matches!(pat, Pattern::Wildcard { .. }));
6528 }
6529
6530 #[test]
6531 fn pattern_bind() {
6532 let (pat, diags) = parse_pat("name => 1");
6533 assert!(!diags.has_errors(), "{diags:?}");
6534 assert!(matches!(pat, Pattern::Bind { .. }));
6535 if let Pattern::Bind { name, .. } = pat {
6536 assert_eq!(name.name, "name");
6537 }
6538 }
6539
6540 #[test]
6541 fn pattern_mut_bind() {
6542 let (pat, diags) = parse_pat("mut x => 1");
6543 assert!(!diags.has_errors(), "{diags:?}");
6544 assert!(matches!(pat, Pattern::MutBind { .. }));
6545 if let Pattern::MutBind { name, .. } = pat {
6546 assert_eq!(name.name, "x");
6547 }
6548 }
6549
6550 #[test]
6551 fn pattern_literal_int() {
6552 let (pat, diags) = parse_pat("42 => 1");
6553 assert!(!diags.has_errors(), "{diags:?}");
6554 assert!(matches!(
6555 pat,
6556 Pattern::Literal {
6557 lit: Literal::Int(_),
6558 ..
6559 }
6560 ));
6561 }
6562
6563 #[test]
6564 fn pattern_literal_string() {
6565 let (pat, diags) = parse_pat(r#""hello" => 1"#);
6566 assert!(!diags.has_errors(), "{diags:?}");
6567 assert!(matches!(
6568 pat,
6569 Pattern::Literal {
6570 lit: Literal::String(_),
6571 ..
6572 }
6573 ));
6574 }
6575
6576 #[test]
6577 fn pattern_literal_bool_true() {
6578 let (pat, diags) = parse_pat("true => 1");
6579 assert!(!diags.has_errors(), "{diags:?}");
6580 assert!(matches!(
6581 pat,
6582 Pattern::Literal {
6583 lit: Literal::Bool(true),
6584 ..
6585 }
6586 ));
6587 }
6588
6589 #[test]
6590 fn pattern_literal_bool_false() {
6591 let (pat, diags) = parse_pat("false => 1");
6592 assert!(!diags.has_errors(), "{diags:?}");
6593 assert!(matches!(
6594 pat,
6595 Pattern::Literal {
6596 lit: Literal::Bool(false),
6597 ..
6598 }
6599 ));
6600 }
6601
6602 #[test]
6603 fn pattern_constructor_some() {
6604 let (pat, diags) = parse_pat("Some(x) => 1");
6605 assert!(!diags.has_errors(), "{diags:?}");
6606 if let Pattern::Constructor { fields, .. } = pat {
6607 assert_eq!(fields.len(), 1);
6608 assert!(matches!(fields[0], Pattern::Bind { .. }));
6609 } else {
6610 panic!("expected Constructor pattern");
6611 }
6612 }
6613
6614 #[test]
6615 fn pattern_constructor_err() {
6616 let (pat, diags) = parse_pat("Err(e) => 1");
6617 assert!(!diags.has_errors(), "{diags:?}");
6618 assert!(matches!(pat, Pattern::Constructor { .. }));
6619 }
6620
6621 #[test]
6622 fn pattern_record_shorthand() {
6623 let (pat, diags) = parse_pat("Point { x, y } => 1");
6624 assert!(!diags.has_errors(), "{diags:?}");
6625 if let Pattern::Record { fields, rest, .. } = pat {
6626 assert_eq!(fields.len(), 2);
6627 assert_eq!(fields[0].name.name, "x");
6628 assert!(
6629 fields[0].pattern.is_none(),
6630 "shorthand should have no sub-pattern"
6631 );
6632 assert_eq!(fields[1].name.name, "y");
6633 assert!(!rest, "no rest expected");
6634 } else {
6635 panic!("expected Record pattern");
6636 }
6637 }
6638
6639 #[test]
6640 fn pattern_record_with_rename() {
6641 let (pat, diags) = parse_pat("User { name: n, age: a } => 1");
6642 assert!(!diags.has_errors(), "{diags:?}");
6643 if let Pattern::Record { fields, rest, .. } = pat {
6644 assert_eq!(fields.len(), 2);
6645 assert_eq!(fields[0].name.name, "name");
6646 assert!(fields[0].pattern.is_some());
6647 assert!(!rest);
6648 } else {
6649 panic!("expected Record pattern");
6650 }
6651 }
6652
6653 #[test]
6654 fn pattern_record_with_rest() {
6655 let (pat, diags) = parse_pat("User { name: n, .. } => 1");
6656 assert!(!diags.has_errors(), "{diags:?}");
6657 if let Pattern::Record { fields, rest, .. } = pat {
6658 assert_eq!(fields.len(), 1);
6659 assert_eq!(fields[0].name.name, "name");
6660 assert!(rest, "rest flag should be set for `..`");
6661 } else {
6662 panic!("expected Record pattern");
6663 }
6664 }
6665
6666 #[test]
6667 fn pattern_tuple() {
6668 let (pat, diags) = parse_pat("(a, b, c) => 1");
6669 assert!(!diags.has_errors(), "{diags:?}");
6670 if let Pattern::Tuple { elems, .. } = pat {
6671 assert_eq!(elems.len(), 3);
6672 } else {
6673 panic!("expected Tuple pattern");
6674 }
6675 }
6676
6677 #[test]
6678 fn pattern_list_with_rest() {
6679 let (pat, diags) = parse_pat("[first, ..rest] => 1");
6680 assert!(!diags.has_errors(), "{diags:?}");
6681 if let Pattern::List { elems, rest, .. } = pat {
6682 assert_eq!(elems.len(), 1);
6683 assert!(matches!(elems[0], Pattern::Bind { .. }));
6684 let r = rest.expect("rest pattern expected");
6685 assert!(matches!(*r, Pattern::Bind { .. }));
6686 } else {
6687 panic!("expected List pattern");
6688 }
6689 }
6690
6691 #[test]
6692 fn pattern_list_rest_only() {
6693 let (pat, diags) = parse_pat("[..] => 1");
6694 assert!(!diags.has_errors(), "{diags:?}");
6695 if let Pattern::List { elems, rest, .. } = pat {
6696 assert!(elems.is_empty());
6697 assert!(rest.is_some());
6698 } else {
6699 panic!("expected List pattern");
6700 }
6701 }
6702
6703 #[test]
6704 fn pattern_or() {
6705 let (pat, diags) = parse_pat("A | B | C => 1");
6706 assert!(!diags.has_errors(), "{diags:?}");
6707 if let Pattern::Or { alternatives, .. } = pat {
6708 assert_eq!(alternatives.len(), 3);
6709 } else {
6710 panic!("expected Or pattern");
6711 }
6712 }
6713
6714 #[test]
6715 fn pattern_range() {
6716 let (pat, diags) = parse_pat("1..10 => 1");
6717 assert!(!diags.has_errors(), "{diags:?}");
6718 if let Pattern::Range { inclusive, .. } = pat {
6719 assert!(!inclusive);
6720 } else {
6721 panic!("expected Range pattern");
6722 }
6723 }
6724
6725 #[test]
6726 fn pattern_nested_constructor() {
6727 let (pat, diags) = parse_pat("Some(Ok((a, b))) => 1");
6729 assert!(!diags.has_errors(), "{diags:?}");
6730 if let Pattern::Constructor { fields, .. } = pat {
6731 assert_eq!(fields.len(), 1, "Some should have 1 field");
6732 if let Pattern::Constructor { fields: inner, .. } = &fields[0] {
6733 assert_eq!(inner.len(), 1, "Ok should have 1 field");
6734 assert!(matches!(inner[0], Pattern::Tuple { .. }));
6735 } else {
6736 panic!("expected inner Constructor (Ok)");
6737 }
6738 } else {
6739 panic!("expected outer Constructor (Some)");
6740 }
6741 }
6742
6743 #[test]
6744 fn pattern_or_in_match_arm() {
6745 let src = "fn f() { match x {\n1 | 2 => \"small\"\n_ => \"other\"\n} }";
6746 let (m, diags) = parse(src);
6747 assert!(!diags.has_errors(), "{diags:?}");
6748 let fn_decl = match m.items.first().unwrap() {
6749 Item::Fn(f) => f,
6750 _ => panic!(),
6751 };
6752 let arms = match fn_decl.body.as_ref().unwrap().tail.as_deref() {
6753 Some(Expr::Match { arms, .. }) => arms.clone(),
6754 _ => match fn_decl.body.as_ref().unwrap().stmts.first() {
6755 Some(Stmt::Expr(Expr::Match { arms, .. })) => arms.clone(),
6756 _ => panic!("expected match"),
6757 },
6758 };
6759 assert_eq!(arms.len(), 2);
6760 assert!(matches!(arms[0].pattern, Pattern::Or { .. }));
6761 }
6762
6763 #[test]
6764 fn pattern_guard_in_match_arm() {
6765 let src = "fn f() { match x {\nn if (n > 100) => \"large\"\n_ => \"other\"\n} }";
6766 let (m, diags) = parse(src);
6767 assert!(!diags.has_errors(), "{diags:?}");
6768 let fn_decl = match m.items.first().unwrap() {
6769 Item::Fn(f) => f,
6770 _ => panic!(),
6771 };
6772 let arms = match fn_decl.body.as_ref().unwrap().tail.as_deref() {
6773 Some(Expr::Match { arms, .. }) => arms.clone(),
6774 _ => match fn_decl.body.as_ref().unwrap().stmts.first() {
6775 Some(Stmt::Expr(Expr::Match { arms, .. })) => arms.clone(),
6776 _ => panic!("expected match"),
6777 },
6778 };
6779 assert_eq!(arms.len(), 2);
6780 assert!(arms[0].guard.is_some(), "first arm should have guard");
6781 assert!(arms[1].guard.is_none());
6782 }
6783
6784 #[test]
6785 fn pattern_full_match_example() {
6786 let src = r#"fn f() {
6797match value {
6798 0 => "zero"
6799 1 | 2 => "small"
6800 n if (n > 100) => "large"
6801 Point { x: 0, y } => "on y-axis"
6802 Some(Ok(v)) => "got it"
6803 [first, ..rest] => "head"
6804 _ => "other"
6805}
6806}"#;
6807 let (m, diags) = parse(src);
6808 assert!(!diags.has_errors(), "{diags:?}");
6809 let fn_decl = match m.items.first().unwrap() {
6810 Item::Fn(f) => f,
6811 _ => panic!(),
6812 };
6813 let arms = match fn_decl.body.as_ref().unwrap().tail.as_deref() {
6814 Some(Expr::Match { arms, .. }) => arms.clone(),
6815 _ => match fn_decl.body.as_ref().unwrap().stmts.first() {
6816 Some(Stmt::Expr(Expr::Match { arms, .. })) => arms.clone(),
6817 _ => panic!("expected match"),
6818 },
6819 };
6820 assert_eq!(arms.len(), 7);
6821 assert!(matches!(
6822 arms[0].pattern,
6823 Pattern::Literal {
6824 lit: Literal::Int(_),
6825 ..
6826 }
6827 ));
6828 assert!(matches!(arms[1].pattern, Pattern::Or { .. }));
6829 assert!(arms[2].guard.is_some());
6830 assert!(matches!(arms[3].pattern, Pattern::Record { .. }));
6831 assert!(matches!(arms[4].pattern, Pattern::Constructor { .. }));
6832 assert!(matches!(arms[5].pattern, Pattern::List { .. }));
6833 assert!(matches!(arms[6].pattern, Pattern::Wildcard { .. }));
6834 }
6835
6836 #[test]
6837 fn pattern_if_let() {
6838 let src = "fn f() { if (let Some(user) = find(id)) { consume(user) } }";
6839 let (m, diags) = parse(src);
6840 assert!(!diags.has_errors(), "{diags:?}");
6841 let fn_decl = match m.items.first().unwrap() {
6842 Item::Fn(f) => f,
6843 _ => panic!(),
6844 };
6845 let has_if_let = fn_decl.body.as_ref().unwrap().stmts.iter().any(|s| {
6847 matches!(
6848 s,
6849 Stmt::Expr(Expr::If {
6850 let_pattern: Some(_),
6851 ..
6852 })
6853 )
6854 }) || fn_decl
6855 .body
6856 .as_ref()
6857 .unwrap()
6858 .tail
6859 .as_ref()
6860 .is_some_and(|t| {
6861 matches!(
6862 t.as_ref(),
6863 Expr::If {
6864 let_pattern: Some(_),
6865 ..
6866 }
6867 )
6868 });
6869 assert!(has_if_let, "expected if-let expression with let_pattern");
6870 }
6871
6872 fn parse_type_str(ty: &str) -> (TypeExpr, DiagnosticBag) {
6876 let src = format!("fn f(x: {ty}) {{}}\n");
6877 let (m, diags) = parse(&src);
6878 let Item::Fn(f) = &m.items[0] else {
6879 panic!("expected fn")
6880 };
6881 let ty = f.params[0].ty.clone().expect("param should have type");
6882 (ty, diags)
6883 }
6884
6885 #[test]
6886 fn type_named_simple() {
6887 let (ty, diags) = parse_type_str("Int");
6888 assert!(!diags.has_errors(), "{diags:?}");
6889 let TypeExpr::Named { path, args, .. } = ty else {
6890 panic!("expected Named")
6891 };
6892 assert_eq!(path.segments[0].name, "Int");
6893 assert!(args.is_empty());
6894 }
6895
6896 #[test]
6897 fn type_named_module_path() {
6898 let (ty, diags) = parse_type_str("app.models.User");
6899 assert!(!diags.has_errors(), "{diags:?}");
6900 let TypeExpr::Named { path, .. } = ty else {
6901 panic!("expected Named")
6902 };
6903 let names: Vec<&str> = path.segments.iter().map(|s| s.name.as_str()).collect();
6904 assert_eq!(names, ["app", "models", "User"]);
6905 }
6906
6907 #[test]
6908 fn type_generic_single() {
6909 let (ty, diags) = parse_type_str("List[Int]");
6910 assert!(!diags.has_errors(), "{diags:?}");
6911 let TypeExpr::Named { path, args, .. } = ty else {
6912 panic!("expected Named")
6913 };
6914 assert_eq!(path.segments[0].name, "List");
6915 assert_eq!(args.len(), 1);
6916 assert!(matches!(&args[0], TypeExpr::Named { path, .. } if path.segments[0].name == "Int"));
6917 }
6918
6919 #[test]
6920 fn type_generic_two_params() {
6921 let (ty, diags) = parse_type_str("Map[String, Int]");
6922 assert!(!diags.has_errors(), "{diags:?}");
6923 let TypeExpr::Named { path, args, .. } = ty else {
6924 panic!("expected Named")
6925 };
6926 assert_eq!(path.segments[0].name, "Map");
6927 assert_eq!(args.len(), 2);
6928 }
6929
6930 #[test]
6931 fn type_generic_nested() {
6932 let (ty, diags) = parse_type_str("Map[String, List[User]]");
6933 assert!(!diags.has_errors(), "{diags:?}");
6934 let TypeExpr::Named { args, .. } = ty else {
6935 panic!("expected Named")
6936 };
6937 assert_eq!(args.len(), 2);
6938 let TypeExpr::Named {
6939 path: inner_path,
6940 args: inner_args,
6941 ..
6942 } = &args[1]
6943 else {
6944 panic!("expected inner Named")
6945 };
6946 assert_eq!(inner_path.segments[0].name, "List");
6947 assert_eq!(inner_args.len(), 1);
6948 }
6949
6950 #[test]
6951 fn type_tuple_unit() {
6952 let (ty, diags) = parse_type_str("()");
6953 assert!(!diags.has_errors(), "{diags:?}");
6954 let TypeExpr::Tuple { elems, .. } = ty else {
6955 panic!("expected Tuple")
6956 };
6957 assert!(elems.is_empty());
6958 }
6959
6960 #[test]
6961 fn type_tuple_two_elems() {
6962 let (ty, diags) = parse_type_str("(Int, String)");
6963 assert!(!diags.has_errors(), "{diags:?}");
6964 let TypeExpr::Tuple { elems, .. } = ty else {
6965 panic!("expected Tuple")
6966 };
6967 assert_eq!(elems.len(), 2);
6968 }
6969
6970 #[test]
6971 fn type_tuple_three_elems() {
6972 let (ty, diags) = parse_type_str("(Int, String, Bool)");
6973 assert!(!diags.has_errors(), "{diags:?}");
6974 let TypeExpr::Tuple { elems, .. } = ty else {
6975 panic!("expected Tuple")
6976 };
6977 assert_eq!(elems.len(), 3);
6978 }
6979
6980 #[test]
6981 fn type_fn_no_params() {
6982 let (ty, diags) = parse_type_str("Fn() -> Void");
6983 assert!(!diags.has_errors(), "{diags:?}");
6984 let TypeExpr::Function {
6985 params,
6986 ret,
6987 effects,
6988 ..
6989 } = ty
6990 else {
6991 panic!("expected Function")
6992 };
6993 assert!(params.is_empty());
6994 assert!(effects.is_empty());
6995 assert!(
6996 matches!(ret.as_ref(), TypeExpr::Named { path, .. } if path.segments[0].name == "Void")
6997 );
6998 }
6999
7000 #[test]
7001 fn type_fn_with_params_and_return() {
7002 let (ty, diags) = parse_type_str("Fn(Int, Int) -> Int");
7003 assert!(!diags.has_errors(), "{diags:?}");
7004 let TypeExpr::Function {
7005 params,
7006 ret,
7007 effects,
7008 ..
7009 } = ty
7010 else {
7011 panic!("expected Function")
7012 };
7013 assert_eq!(params.len(), 2);
7014 assert!(effects.is_empty());
7015 assert!(
7016 matches!(ret.as_ref(), TypeExpr::Named { path, .. } if path.segments[0].name == "Int")
7017 );
7018 }
7019
7020 #[test]
7021 fn type_fn_with_effect_clause() {
7022 let (ty, diags) = parse_type_str("Fn(String) -> Void with Log");
7023 assert!(!diags.has_errors(), "{diags:?}");
7024 let TypeExpr::Function {
7025 params, effects, ..
7026 } = ty
7027 else {
7028 panic!("expected Function")
7029 };
7030 assert_eq!(params.len(), 1);
7031 assert_eq!(effects.len(), 1);
7032 assert_eq!(effects[0].segments[0].name, "Log");
7033 }
7034
7035 #[test]
7036 fn type_fn_with_multiple_effects() {
7037 let (ty, diags) = parse_type_str("Fn() -> Void with Log, Io");
7038 assert!(!diags.has_errors(), "{diags:?}");
7039 let TypeExpr::Function { effects, .. } = ty else {
7040 panic!("expected Function")
7041 };
7042 assert_eq!(effects.len(), 2);
7043 assert_eq!(effects[0].segments[0].name, "Log");
7044 assert_eq!(effects[1].segments[0].name, "Io");
7045 }
7046
7047 #[test]
7048 fn type_optional_shorthand() {
7049 let (ty, diags) = parse_type_str("User?");
7050 assert!(!diags.has_errors(), "{diags:?}");
7051 let TypeExpr::Optional { inner, .. } = ty else {
7052 panic!("expected Optional")
7053 };
7054 let TypeExpr::Named { path, .. } = inner.as_ref() else {
7055 panic!("expected Named inner")
7056 };
7057 assert_eq!(path.segments[0].name, "User");
7058 }
7059
7060 #[test]
7061 fn type_optional_generic() {
7062 let (ty, diags) = parse_type_str("List[Int]?");
7063 assert!(!diags.has_errors(), "{diags:?}");
7064 let TypeExpr::Optional { inner, .. } = ty else {
7065 panic!("expected Optional")
7066 };
7067 assert!(matches!(inner.as_ref(), TypeExpr::Named { .. }));
7068 }
7069
7070 #[test]
7071 fn type_self_in_impl() {
7072 let src = "record Wrap { inner: Self }\n";
7074 let (m, diags) = parse(src);
7075 assert!(!diags.has_errors(), "{diags:?}");
7076 let Item::Record(r) = &m.items[0] else {
7077 panic!()
7078 };
7079 assert!(matches!(r.fields[0].ty, TypeExpr::SelfType { .. }));
7080 }
7081
7082 #[test]
7083 fn type_deeply_nested_generics() {
7084 let (ty, diags) = parse_type_str("Map[String, List[Result[User, String]]]");
7086 assert!(!diags.has_errors(), "{diags:?}");
7087 let TypeExpr::Named { path, args, .. } = ty else {
7088 panic!("expected Named")
7089 };
7090 assert_eq!(path.segments[0].name, "Map");
7091 assert_eq!(args.len(), 2);
7092 let TypeExpr::Named {
7093 path: list_path,
7094 args: list_args,
7095 ..
7096 } = &args[1]
7097 else {
7098 panic!("expected List")
7099 };
7100 assert_eq!(list_path.segments[0].name, "List");
7101 assert_eq!(list_args.len(), 1);
7102 let TypeExpr::Named {
7103 path: result_path,
7104 args: result_args,
7105 ..
7106 } = &list_args[0]
7107 else {
7108 panic!("expected Result")
7109 };
7110 assert_eq!(result_path.segments[0].name, "Result");
7111 assert_eq!(result_args.len(), 2);
7112 }
7113
7114 #[test]
7117 fn effect_empty_body() {
7118 let src = "effect Log {\n}\n";
7119 let (m, diags) = parse(src);
7120 assert!(!diags.has_errors(), "{diags:?}");
7121 assert_eq!(m.items.len(), 1);
7122 let Item::Effect(e) = &m.items[0] else {
7123 panic!("expected Effect")
7124 };
7125 assert_eq!(e.name.name, "Log");
7126 assert!(e.operations.is_empty());
7127 }
7128
7129 #[test]
7130 fn effect_with_operations() {
7131 let src = "effect Log {\n fn log(level: Level, message: String) -> Void\n}\n";
7132 let (m, diags) = parse(src);
7133 assert!(!diags.has_errors(), "{diags:?}");
7134 let Item::Effect(e) = &m.items[0] else {
7135 panic!("expected Effect")
7136 };
7137 assert_eq!(e.name.name, "Log");
7138 assert_eq!(e.operations.len(), 1);
7139 assert_eq!(e.operations[0].name.name, "log");
7140 assert_eq!(e.operations[0].params.len(), 2);
7141 }
7142
7143 #[test]
7144 fn effect_multiple_operations() {
7145 let src = "effect Storage {\n fn read(key: String) -> Option[Bytes]\n fn write(key: String, val: Bytes) -> Void\n}\n";
7146 let (m, diags) = parse(src);
7147 assert!(!diags.has_errors(), "{diags:?}");
7148 let Item::Effect(e) = &m.items[0] else {
7149 panic!("expected Effect")
7150 };
7151 assert_eq!(e.operations.len(), 2);
7152 assert_eq!(e.operations[0].name.name, "read");
7153 assert_eq!(e.operations[1].name.name, "write");
7154 }
7155
7156 #[test]
7157 fn effect_composite() {
7158 let src = "effect Observable = Log + Trace + Metrics\n";
7159 let (m, diags) = parse(src);
7160 assert!(!diags.has_errors(), "{diags:?}");
7161 assert_eq!(m.items.len(), 1);
7162 let Item::Effect(e) = &m.items[0] else {
7163 panic!("expected Effect")
7164 };
7165 assert_eq!(e.name.name, "Observable");
7166 assert!(
7167 e.operations.is_empty(),
7168 "composite effects have no operations"
7169 );
7170 }
7171
7172 #[test]
7173 fn effect_with_visibility() {
7174 let src = "public effect Log {\n fn log(msg: String) -> Void\n}\n";
7175 let (m, diags) = parse(src);
7176 assert!(!diags.has_errors(), "{diags:?}");
7177 let Item::Effect(e) = &m.items[0] else {
7178 panic!("expected Effect")
7179 };
7180 assert_eq!(e.visibility, Visibility::Public);
7181 }
7182
7183 #[test]
7186 fn annotation_no_args() {
7187 let src = "@deprecated\nfn old() {}\n";
7188 let (m, diags) = parse(src);
7189 assert!(!diags.has_errors(), "{diags:?}");
7190 let Item::Fn(f) = &m.items[0] else { panic!() };
7191 assert_eq!(f.annotations.len(), 1);
7192 assert_eq!(f.annotations[0].name.name, "deprecated");
7193 assert!(f.annotations[0].args.is_empty());
7194 }
7195
7196 #[test]
7197 fn annotation_positional_arg() {
7198 let src = "@domain(\"e-commerce\")\nfn process() {}\n";
7199 let (m, diags) = parse(src);
7200 assert!(!diags.has_errors(), "{diags:?}");
7201 let Item::Fn(f) = &m.items[0] else { panic!() };
7202 assert_eq!(f.annotations[0].name.name, "domain");
7203 assert_eq!(f.annotations[0].args.len(), 1);
7204 }
7205
7206 #[test]
7207 fn annotation_named_arg() {
7208 let src = "@performance(max_latency: 100)\nfn fast() {}\n";
7209 let (m, diags) = parse(src);
7210 assert!(!diags.has_errors(), "{diags:?}");
7211 let Item::Fn(f) = &m.items[0] else { panic!() };
7212 assert_eq!(f.annotations[0].name.name, "performance");
7213 assert_eq!(f.annotations[0].args.len(), 1);
7214 }
7215
7216 #[test]
7217 fn annotation_multiline_string() {
7218 let src = "@context(\"\"\"\n Payment module.\n\"\"\")\nfn pay() {}\n";
7219 let (m, diags) = parse(src);
7220 assert!(!diags.has_errors(), "{diags:?}");
7221 let Item::Fn(f) = &m.items[0] else { panic!() };
7222 assert_eq!(f.annotations[0].name.name, "context");
7223 assert_eq!(f.annotations[0].args.len(), 1);
7224 }
7225
7226 #[test]
7227 fn multiple_annotations_stack() {
7228 let src = "@deprecated\n@domain(\"old\")\nfn legacy() {}\n";
7229 let (m, diags) = parse(src);
7230 assert!(!diags.has_errors(), "{diags:?}");
7231 let Item::Fn(f) = &m.items[0] else { panic!() };
7232 assert_eq!(f.annotations.len(), 2);
7233 assert_eq!(f.annotations[0].name.name, "deprecated");
7234 assert_eq!(f.annotations[1].name.name, "domain");
7235 }
7236
7237 #[test]
7240 fn module_handle_decl() {
7241 let src = "handle Log with ConsoleLog\n";
7242 let (m, diags) = parse(src);
7243 assert!(!diags.has_errors(), "{diags:?}");
7244 assert_eq!(m.items.len(), 1);
7245 let Item::ModuleHandle(h) = &m.items[0] else {
7246 panic!("expected ModuleHandle")
7247 };
7248 assert_eq!(h.effect.segments[0].name, "Log");
7249 }
7250
7251 #[test]
7252 fn module_handle_decl_qualified_effect() {
7253 let src = "handle Std.Io with FileIo\n";
7254 let (m, diags) = parse(src);
7255 assert!(!diags.has_errors(), "{diags:?}");
7256 let Item::ModuleHandle(h) = &m.items[0] else {
7257 panic!("expected ModuleHandle")
7258 };
7259 assert_eq!(h.effect.segments.len(), 2);
7260 assert_eq!(h.effect.segments[0].name, "Std");
7261 assert_eq!(h.effect.segments[1].name, "Io");
7262 }
7263
7264 #[test]
7267 fn fn_with_effect_clause_integration() {
7268 let src = "fn process(data: Data) -> Result\n with Log, Clock\n{\n data\n}\n";
7269 let (m, diags) = parse(src);
7270 assert!(!diags.has_errors(), "{diags:?}");
7271 let Item::Fn(f) = &m.items[0] else { panic!() };
7272 assert_eq!(f.effect_clause.len(), 2);
7273 assert_eq!(f.effect_clause[0].segments[0].name, "Log");
7274 assert_eq!(f.effect_clause[1].segments[0].name, "Clock");
7275 }
7276
7277 #[test]
7281 fn disambig_brace_after_type_ident_is_record_construct() {
7282 let src = "fn f() { Point { x: 1, y: 2 } }\n";
7283 let (m, diags) = parse(src);
7284 assert!(!diags.has_errors(), "{diags:?}");
7285 let Item::Fn(f) = &m.items[0] else { panic!() };
7286 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7287 assert!(
7288 matches!(tail, Expr::RecordConstruct { .. }),
7289 "expected RecordConstruct, got {tail:?}"
7290 );
7291 }
7292
7293 #[test]
7295 fn disambig_brace_with_colon_is_map() {
7296 let src = "fn f() { { \"key\": 42 } }\n";
7297 let (m, diags) = parse(src);
7298 assert!(!diags.has_errors(), "{diags:?}");
7299 let Item::Fn(f) = &m.items[0] else { panic!() };
7300 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7301 assert!(
7302 matches!(tail, Expr::MapLiteral { .. }),
7303 "expected MapLiteral, got {tail:?}"
7304 );
7305 }
7306
7307 #[test]
7309 fn disambig_brace_without_colon_is_block() {
7310 let src = "fn f() { { 42 } }\n";
7311 let (m, diags) = parse(src);
7312 assert!(!diags.has_errors(), "{diags:?}");
7313 let Item::Fn(f) = &m.items[0] else { panic!() };
7314 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7315 assert!(
7316 matches!(tail, Expr::Block { .. }),
7317 "expected Block, got {tail:?}"
7318 );
7319 }
7320
7321 #[test]
7323 fn disambig_single_paren_is_grouping() {
7324 let src = "fn f() { (42) }\n";
7325 let (m, diags) = parse(src);
7326 assert!(!diags.has_errors(), "{diags:?}");
7327 let Item::Fn(f) = &m.items[0] else { panic!() };
7328 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7329 assert!(
7331 !matches!(tail, Expr::TupleLiteral { .. }),
7332 "should not be TupleLiteral"
7333 );
7334 }
7335
7336 #[test]
7338 fn disambig_multi_paren_is_tuple() {
7339 let src = "fn f() { (1, 2) }\n";
7340 let (m, diags) = parse(src);
7341 assert!(!diags.has_errors(), "{diags:?}");
7342 let Item::Fn(f) = &m.items[0] else { panic!() };
7343 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7344 assert!(matches!(tail, Expr::TupleLiteral { elems, .. } if elems.len() == 2));
7345 }
7346
7347 #[test]
7349 fn disambig_trailing_comma_is_single_elem_tuple() {
7350 let src = "fn f() { (1,) }\n";
7351 let (m, diags) = parse(src);
7352 assert!(!diags.has_errors(), "{diags:?}");
7353 let Item::Fn(f) = &m.items[0] else { panic!() };
7354 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7355 assert!(matches!(tail, Expr::TupleLiteral { elems, .. } if elems.len() == 1));
7356 }
7357
7358 #[test]
7360 fn disambig_map_with_ident_key() {
7361 let src = "fn f() { { name: \"Alice\" } }\n";
7362 let (m, diags) = parse(src);
7363 assert!(!diags.has_errors(), "{diags:?}");
7364 let Item::Fn(f) = &m.items[0] else { panic!() };
7365 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7366 assert!(matches!(tail, Expr::MapLiteral { entries, .. } if entries.len() == 1));
7367 }
7368
7369 #[test]
7371 fn disambig_empty_braces_is_block() {
7372 let src = "fn f() { {} }\n";
7373 let (m, diags) = parse(src);
7374 assert!(!diags.has_errors(), "{diags:?}");
7375 let Item::Fn(f) = &m.items[0] else { panic!() };
7376 let tail = f.body.as_ref().unwrap().tail.as_deref().expect("tail expr");
7377 assert!(
7378 matches!(tail, Expr::Block { .. }),
7379 "expected Block, got {tail:?}"
7380 );
7381 }
7382
7383 #[test]
7388 fn recovery_unexpected_token_at_top_level() {
7389 let src = "fn before() {}\n???\nfn after() {}\n";
7391 let (m, diags) = parse(src);
7392 assert!(diags.has_errors(), "should have errors");
7393 let fns: Vec<_> = m
7395 .items
7396 .iter()
7397 .filter(|i| matches!(i, Item::Fn(_)))
7398 .collect();
7399 assert_eq!(fns.len(), 2, "both fns should be in the AST");
7400 assert!(m.items.iter().any(|i| matches!(i, Item::Error { .. })));
7402 }
7403
7404 #[test]
7406 fn recovery_multiple_errors_reported() {
7407 let src = "???\nfn mid() {}\n!!!\nfn ok() {}\n";
7409 let (m, diags) = parse(src);
7410 assert!(diags.has_errors());
7411 assert!(
7412 diags.error_count() >= 2,
7413 "should report multiple errors, got: {diags:?}"
7414 );
7415 let fns: Vec<_> = m
7417 .items
7418 .iter()
7419 .filter(|i| matches!(i, Item::Fn(_)))
7420 .collect();
7421 assert_eq!(fns.len(), 2);
7422 }
7423
7424 #[test]
7426 fn recovery_after_malformed_fn_body() {
7427 let src = "fn bad( {}\nfn good() {}\n";
7429 let (m, diags) = parse(src);
7430 assert!(diags.has_errors());
7431 let has_good = m.items.iter().any(|i| {
7433 if let Item::Fn(f) = i {
7434 f.name.name == "good"
7435 } else {
7436 false
7437 }
7438 });
7439 assert!(
7440 has_good,
7441 "fn good should be recovered; items: {:#?}",
7442 m.items
7443 );
7444 }
7445
7446 #[test]
7449 fn integration_complete_source_file() {
7450 let src = "\
7451module app.core\n\
7452use std.io.*\n\
7453use std.collections.{List, Map}\n\
7454\n\
7455public record User {\n\
7456 name: String\n\
7457 age: Int\n\
7458}\n\
7459\n\
7460public enum Color {\n\
7461 Red\n\
7462 Green\n\
7463 Blue\n\
7464}\n\
7465\n\
7466public fn greet(user: User) -> String {\n\
7467 \"Hello\"\n\
7468}\n\
7469\n\
7470public fn add(x: Int, y: Int) -> Int {\n\
7471 x + y\n\
7472}\n\
7473";
7474 let (m, diags) = parse(src);
7475 assert!(!diags.has_errors(), "errors: {diags:?}");
7476
7477 let path = m.path.as_ref().expect("module path");
7479 assert_eq!(path.segments[0].name, "app");
7480 assert_eq!(path.segments[1].name, "core");
7481
7482 assert_eq!(m.imports.len(), 2);
7484
7485 assert_eq!(m.items.len(), 4);
7487 assert!(matches!(m.items[0], Item::Record(_)));
7488 assert!(matches!(m.items[1], Item::Enum(_)));
7489 assert!(matches!(m.items[2], Item::Fn(_)));
7490 assert!(matches!(m.items[3], Item::Fn(_)));
7491
7492 let Item::Record(r) = &m.items[0] else {
7493 panic!()
7494 };
7495 assert_eq!(r.name.name, "User");
7496 assert_eq!(r.fields.len(), 2);
7497
7498 let Item::Enum(e) = &m.items[1] else { panic!() };
7499 assert_eq!(e.name.name, "Color");
7500 assert_eq!(e.variants.len(), 3);
7501 }
7502
7503 #[test]
7506 fn parse_type_alias_simple() {
7507 let (m, diags) = parse("type Email = String\n");
7508 assert!(!diags.has_errors(), "errors: {diags:?}");
7509 assert_eq!(m.items.len(), 1);
7510 let Item::TypeAlias(ta) = &m.items[0] else {
7511 panic!("expected TypeAlias")
7512 };
7513 assert_eq!(ta.name.name, "Email");
7514 assert!(ta.generic_params.is_empty());
7515 assert!(ta.where_clause.is_empty());
7516 assert_eq!(ta.visibility, Visibility::Private);
7517 }
7518
7519 #[test]
7520 fn parse_type_alias_generic() {
7521 let (m, diags) = parse("type NonEmpty[T] = List[T]\n");
7522 assert!(!diags.has_errors(), "errors: {diags:?}");
7523 assert_eq!(m.items.len(), 1);
7524 let Item::TypeAlias(ta) = &m.items[0] else {
7525 panic!("expected TypeAlias")
7526 };
7527 assert_eq!(ta.name.name, "NonEmpty");
7528 assert_eq!(ta.generic_params.len(), 1);
7529 assert_eq!(ta.generic_params[0].name.name, "T");
7530 }
7531
7532 #[test]
7533 fn parse_type_alias_plain() {
7534 let (m, diags) = parse("type Port = Int\n");
7535 assert!(!diags.has_errors(), "errors: {diags:?}");
7536 assert_eq!(m.items.len(), 1);
7537 let Item::TypeAlias(ta) = &m.items[0] else {
7538 panic!("expected TypeAlias")
7539 };
7540 assert_eq!(ta.name.name, "Port");
7541 assert!(ta.generic_params.is_empty());
7542 }
7543
7544 #[test]
7545 fn parse_type_alias_with_where_clause() {
7546 let (m, diags) = parse("type Sortable[T] = List[T] where (T: Comparable)\n");
7547 assert!(!diags.has_errors(), "errors: {diags:?}");
7548 assert_eq!(m.items.len(), 1);
7549 let Item::TypeAlias(ta) = &m.items[0] else {
7550 panic!("expected TypeAlias")
7551 };
7552 assert_eq!(ta.name.name, "Sortable");
7553 assert_eq!(ta.generic_params.len(), 1);
7554 assert_eq!(ta.where_clause.len(), 1);
7555 assert_eq!(ta.where_clause[0].param.name, "T");
7556 }
7557
7558 #[test]
7561 fn parse_const_int() {
7562 let (m, diags) = parse("const MAX_SIZE: Int = 1024\n");
7563 assert!(!diags.has_errors(), "errors: {diags:?}");
7564 assert_eq!(m.items.len(), 1);
7565 let Item::Const(cd) = &m.items[0] else {
7566 panic!("expected Const")
7567 };
7568 assert_eq!(cd.name.name, "MAX_SIZE");
7569 assert_eq!(cd.visibility, Visibility::Private);
7570 }
7571
7572 #[test]
7573 fn parse_const_float() {
7574 let (m, diags) = parse("const PI: Float = 3.14159\n");
7575 assert!(!diags.has_errors(), "errors: {diags:?}");
7576 assert_eq!(m.items.len(), 1);
7577 let Item::Const(cd) = &m.items[0] else {
7578 panic!("expected Const")
7579 };
7580 assert_eq!(cd.name.name, "PI");
7581 }
7582
7583 #[test]
7584 fn parse_const_with_visibility() {
7585 let (m, diags) = parse("public const VERSION: String = \"1.0.0\"\n");
7586 assert!(!diags.has_errors(), "errors: {diags:?}");
7587 assert_eq!(m.items.len(), 1);
7588 let Item::Const(cd) = &m.items[0] else {
7589 panic!("expected Const")
7590 };
7591 assert_eq!(cd.name.name, "VERSION");
7592 assert_eq!(cd.visibility, Visibility::Public);
7593 }
7594
7595 #[test]
7596 fn parse_type_alias_with_visibility() {
7597 let (m, diags) = parse("public type UserId = Int\n");
7598 assert!(!diags.has_errors(), "errors: {diags:?}");
7599 assert_eq!(m.items.len(), 1);
7600 let Item::TypeAlias(ta) = &m.items[0] else {
7601 panic!("expected TypeAlias")
7602 };
7603 assert_eq!(ta.name.name, "UserId");
7604 assert_eq!(ta.visibility, Visibility::Public);
7605 }
7606
7607 #[test]
7610 fn import_visibility_stored() {
7611 let (m, diags) = parse("public use app.models.User\n");
7612 assert!(!diags.has_errors(), "errors: {diags:?}");
7613 assert_eq!(m.imports.len(), 1);
7614 assert_eq!(m.imports[0].visibility, Visibility::Public);
7615 }
7616
7617 #[test]
7618 fn import_private_visibility_default() {
7619 let (m, diags) = parse("use app.models.User\n");
7620 assert!(!diags.has_errors(), "errors: {diags:?}");
7621 assert_eq!(m.imports.len(), 1);
7622 assert_eq!(m.imports[0].visibility, Visibility::Private);
7623 }
7624
7625 #[test]
7626 fn composite_effect_components_stored() {
7627 let (m, diags) = parse("effect IO = Log + Clock + Storage\n");
7628 assert!(!diags.has_errors(), "errors: {diags:?}");
7629 assert_eq!(m.items.len(), 1);
7630 let Item::Effect(eff) = &m.items[0] else {
7631 panic!("expected Effect")
7632 };
7633 assert_eq!(eff.name.name, "IO");
7634 let component_names: Vec<&str> = eff
7635 .components
7636 .iter()
7637 .map(|c| c.segments[0].name.as_str())
7638 .collect();
7639 assert_eq!(component_names, ["Log", "Clock", "Storage"]);
7640 }
7641
7642 #[test]
7643 fn trait_supertraits_stored() {
7644 let (m, diags) = parse("trait Ordered: Comparable, Equatable {\n}\n");
7645 assert!(!diags.has_errors(), "errors: {diags:?}");
7646 assert_eq!(m.items.len(), 1);
7647 let Item::Trait(tr) = &m.items[0] else {
7648 panic!("expected Trait")
7649 };
7650 assert_eq!(tr.name.name, "Ordered");
7651 let supertrait_names: Vec<&str> = tr
7652 .supertraits
7653 .iter()
7654 .map(|s| s.segments[0].name.as_str())
7655 .collect();
7656 assert_eq!(supertrait_names, ["Comparable", "Equatable"]);
7657 }
7658
7659 #[test]
7660 fn import_alias_in_list() {
7661 let (m, diags) = parse("use json.{Value as JsonValue}\n");
7662 assert!(!diags.has_errors(), "errors: {diags:?}");
7663 assert_eq!(m.imports.len(), 1);
7664 match &m.imports[0].items {
7665 ImportItems::Named(names) => {
7666 assert_eq!(names.len(), 1);
7667 assert_eq!(names[0].name.name, "Value");
7668 assert_eq!(names[0].alias.as_ref().unwrap().name, "JsonValue");
7669 }
7670 other => panic!("expected Named import, got {other:?}"),
7671 }
7672 }
7673
7674 #[test]
7675 fn annotation_named_args_preserve_labels() {
7676 let (m, diags) = parse("@performance(max_latency: 100, max_memory: 50)\nfn fast() {}\n");
7677 assert!(!diags.has_errors(), "errors: {diags:?}");
7678 assert_eq!(m.items.len(), 1);
7679 let Item::Fn(f) = &m.items[0] else {
7680 panic!("expected Fn")
7681 };
7682 assert_eq!(f.annotations.len(), 1);
7683 let ann = &f.annotations[0];
7684 assert_eq!(ann.name.name, "performance");
7685 assert_eq!(ann.args.len(), 2);
7686 assert_eq!(ann.args[0].label.as_ref().unwrap().name, "max_latency");
7687 assert_eq!(ann.args[1].label.as_ref().unwrap().name, "max_memory");
7688 }
7689
7690 #[test]
7691 fn trait_required_method_body_is_none() {
7692 let (m, diags) = parse("trait Foo {\n fn bar(self) -> Int\n}\n");
7693 assert!(!diags.has_errors(), "errors: {diags:?}");
7694 assert_eq!(m.items.len(), 1);
7695 let Item::Trait(tr) = &m.items[0] else {
7696 panic!("expected Trait")
7697 };
7698 assert_eq!(tr.methods.len(), 1);
7699 assert_eq!(tr.methods[0].name.name, "bar");
7700 assert!(
7701 tr.methods[0].body.is_none(),
7702 "required method should have body: None"
7703 );
7704 }
7705
7706 #[test]
7711 fn comparison_chained_eq_is_error() {
7712 let (_, diags) = parse_expr_str("a == b == c");
7714 assert!(diags.has_errors(), "chained == must produce a parse error");
7715 }
7716
7717 #[test]
7718 fn comparison_chained_ne_is_error() {
7719 let (_, diags) = parse_expr_str("a != b != c");
7720 assert!(diags.has_errors(), "chained != must produce a parse error");
7721 }
7722
7723 #[test]
7724 fn comparison_chained_lt_gt_is_error() {
7725 let (_, diags) = parse_expr_str("a < b > c");
7726 assert!(diags.has_errors(), "chained < > must produce a parse error");
7727 }
7728
7729 #[test]
7730 fn comparison_chained_le_ge_is_error() {
7731 let (_, diags) = parse_expr_str("a <= b >= c");
7732 assert!(
7733 diags.has_errors(),
7734 "chained <= >= must produce a parse error"
7735 );
7736 }
7737
7738 #[test]
7739 fn comparison_single_eq_still_works() {
7740 let (e, diags) = parse_expr_str("a == b");
7741 assert!(!diags.has_errors(), "{diags:?}");
7742 assert!(matches!(e, Expr::Binary { op: BinOp::Eq, .. }));
7743 }
7744
7745 #[test]
7746 fn comparison_single_lt_still_works() {
7747 let (e, diags) = parse_expr_str("a < b");
7748 assert!(!diags.has_errors(), "{diags:?}");
7749 assert!(matches!(e, Expr::Binary { op: BinOp::Lt, .. }));
7750 }
7751
7752 #[test]
7756 fn prec_01_02_assignment_wraps_pipe() {
7757 let (e, diags) = parse_expr_str("a = b |> c");
7759 assert!(!diags.has_errors(), "{diags:?}");
7760 match &e {
7761 Expr::Assign { value, .. } => {
7762 assert!(
7763 matches!(value.as_ref(), Expr::Pipe { .. }),
7764 "assignment RHS should be Pipe, got {value:?}"
7765 );
7766 }
7767 _ => panic!("expected Assign, got {e:?}"),
7768 }
7769 }
7770
7771 #[test]
7772 fn prec_02_03_pipe_wraps_compose() {
7773 let (e, diags) = parse_expr_str("a |> b >> c");
7775 assert!(!diags.has_errors(), "{diags:?}");
7776 match &e {
7777 Expr::Pipe { right, .. } => {
7778 assert!(
7779 matches!(right.as_ref(), Expr::Compose { .. }),
7780 "pipe RHS should be Compose, got {right:?}"
7781 );
7782 }
7783 _ => panic!("expected Pipe, got {e:?}"),
7784 }
7785 }
7786
7787 #[test]
7788 fn prec_03_04_compose_wraps_range() {
7789 let (e, diags) = parse_expr_str("a >> b .. c");
7791 assert!(!diags.has_errors(), "{diags:?}");
7792 match &e {
7793 Expr::Compose { right, .. } => {
7794 assert!(
7795 matches!(right.as_ref(), Expr::Range { .. }),
7796 "compose RHS should be Range, got {right:?}"
7797 );
7798 }
7799 _ => panic!("expected Compose, got {e:?}"),
7800 }
7801 }
7802
7803 #[test]
7804 fn prec_04_05_range_wraps_logical_or() {
7805 let (e, diags) = parse_expr_str("a .. b || c");
7807 assert!(!diags.has_errors(), "{diags:?}");
7808 match &e {
7809 Expr::Range { hi, .. } => {
7810 assert!(
7811 matches!(hi.as_ref(), Expr::Binary { op: BinOp::Or, .. }),
7812 "range hi should be Or, got {hi:?}"
7813 );
7814 }
7815 _ => panic!("expected Range, got {e:?}"),
7816 }
7817 }
7818
7819 #[test]
7820 fn prec_05_06_or_wraps_and() {
7821 let (e, diags) = parse_expr_str("a || b && c");
7823 assert!(!diags.has_errors(), "{diags:?}");
7824 match &e {
7825 Expr::Binary {
7826 op: BinOp::Or,
7827 right,
7828 ..
7829 } => {
7830 assert!(
7831 matches!(right.as_ref(), Expr::Binary { op: BinOp::And, .. }),
7832 "Or RHS should be And, got {right:?}"
7833 );
7834 }
7835 _ => panic!("expected Or, got {e:?}"),
7836 }
7837 }
7838
7839 #[test]
7840 fn prec_06_07_and_wraps_comparison() {
7841 let (e, diags) = parse_expr_str("a && b == c");
7843 assert!(!diags.has_errors(), "{diags:?}");
7844 match &e {
7845 Expr::Binary {
7846 op: BinOp::And,
7847 right,
7848 ..
7849 } => {
7850 assert!(
7851 matches!(right.as_ref(), Expr::Binary { op: BinOp::Eq, .. }),
7852 "And RHS should be Eq, got {right:?}"
7853 );
7854 }
7855 _ => panic!("expected And, got {e:?}"),
7856 }
7857 }
7858
7859 #[test]
7860 fn prec_07_08_comparison_wraps_bitor() {
7861 let (e, diags) = parse_expr_str("a == b | c");
7863 assert!(!diags.has_errors(), "{diags:?}");
7864 match &e {
7865 Expr::Binary {
7866 op: BinOp::Eq,
7867 right,
7868 ..
7869 } => {
7870 assert!(
7871 matches!(
7872 right.as_ref(),
7873 Expr::Binary {
7874 op: BinOp::BitOr,
7875 ..
7876 }
7877 ),
7878 "Eq RHS should be BitOr, got {right:?}"
7879 );
7880 }
7881 _ => panic!("expected Eq, got {e:?}"),
7882 }
7883 }
7884
7885 #[test]
7886 fn prec_08_09_bitor_wraps_bitxor() {
7887 let (e, diags) = parse_expr_str("a | b ^ c");
7889 assert!(!diags.has_errors(), "{diags:?}");
7890 match &e {
7891 Expr::Binary {
7892 op: BinOp::BitOr,
7893 right,
7894 ..
7895 } => {
7896 assert!(
7897 matches!(
7898 right.as_ref(),
7899 Expr::Binary {
7900 op: BinOp::BitXor,
7901 ..
7902 }
7903 ),
7904 "BitOr RHS should be BitXor, got {right:?}"
7905 );
7906 }
7907 _ => panic!("expected BitOr, got {e:?}"),
7908 }
7909 }
7910
7911 #[test]
7912 fn prec_09_10_bitxor_wraps_bitand() {
7913 let (e, diags) = parse_expr_str("a ^ b & c");
7915 assert!(!diags.has_errors(), "{diags:?}");
7916 match &e {
7917 Expr::Binary {
7918 op: BinOp::BitXor,
7919 right,
7920 ..
7921 } => {
7922 assert!(
7923 matches!(
7924 right.as_ref(),
7925 Expr::Binary {
7926 op: BinOp::BitAnd,
7927 ..
7928 }
7929 ),
7930 "BitXor RHS should be BitAnd, got {right:?}"
7931 );
7932 }
7933 _ => panic!("expected BitXor, got {e:?}"),
7934 }
7935 }
7936
7937 #[test]
7938 fn prec_10_11_bitand_wraps_add() {
7939 let (e, diags) = parse_expr_str("a & b + c");
7941 assert!(!diags.has_errors(), "{diags:?}");
7942 match &e {
7943 Expr::Binary {
7944 op: BinOp::BitAnd,
7945 right,
7946 ..
7947 } => {
7948 assert!(
7949 matches!(right.as_ref(), Expr::Binary { op: BinOp::Add, .. }),
7950 "BitAnd RHS should be Add, got {right:?}"
7951 );
7952 }
7953 _ => panic!("expected BitAnd, got {e:?}"),
7954 }
7955 }
7956
7957 #[test]
7958 fn prec_11_12_add_wraps_mul() {
7959 let (e, diags) = parse_expr_str("a + b * c");
7961 assert!(!diags.has_errors(), "{diags:?}");
7962 match &e {
7963 Expr::Binary {
7964 op: BinOp::Add,
7965 right,
7966 ..
7967 } => {
7968 assert!(
7969 matches!(right.as_ref(), Expr::Binary { op: BinOp::Mul, .. }),
7970 "Add RHS should be Mul, got {right:?}"
7971 );
7972 }
7973 _ => panic!("expected Add, got {e:?}"),
7974 }
7975 }
7976
7977 #[test]
7978 fn prec_12_13_mul_wraps_power() {
7979 let (e, diags) = parse_expr_str("a * b ** c");
7981 assert!(!diags.has_errors(), "{diags:?}");
7982 match &e {
7983 Expr::Binary {
7984 op: BinOp::Mul,
7985 right,
7986 ..
7987 } => {
7988 assert!(
7989 matches!(right.as_ref(), Expr::Binary { op: BinOp::Pow, .. }),
7990 "Mul RHS should be Pow, got {right:?}"
7991 );
7992 }
7993 _ => panic!("expected Mul, got {e:?}"),
7994 }
7995 }
7996
7997 #[test]
7998 fn prec_13_14_power_wraps_unary() {
7999 let (e, diags) = parse_expr_str("-a ** b");
8001 assert!(!diags.has_errors(), "{diags:?}");
8002 match &e {
8003 Expr::Binary {
8004 op: BinOp::Pow,
8005 left,
8006 ..
8007 } => {
8008 assert!(
8009 matches!(
8010 left.as_ref(),
8011 Expr::Unary {
8012 op: UnaryOp::Neg,
8013 ..
8014 }
8015 ),
8016 "Pow LHS should be Neg, got {left:?}"
8017 );
8018 }
8019 _ => panic!("expected Pow, got {e:?}"),
8020 }
8021 }
8022
8023 #[test]
8024 fn prec_14_15_unary_wraps_postfix() {
8025 let (e, diags) = parse_expr_str("!a.b");
8027 assert!(!diags.has_errors(), "{diags:?}");
8028 match &e {
8029 Expr::Unary {
8030 op: UnaryOp::Not,
8031 operand,
8032 ..
8033 } => {
8034 assert!(
8035 matches!(operand.as_ref(), Expr::FieldAccess { .. }),
8036 "Not operand should be FieldAccess, got {operand:?}"
8037 );
8038 }
8039 _ => panic!("expected Unary(Not), got {e:?}"),
8040 }
8041 }
8042
8043 #[test]
8046 fn assoc_01_assignment_right() {
8047 let (e, diags) = parse_expr_str("a = b = c");
8049 assert!(!diags.has_errors(), "{diags:?}");
8050 match &e {
8051 Expr::Assign { value, .. } => {
8052 assert!(
8053 matches!(value.as_ref(), Expr::Assign { .. }),
8054 "assignment should be right-assoc, got {value:?}"
8055 );
8056 }
8057 _ => panic!("expected Assign, got {e:?}"),
8058 }
8059 }
8060
8061 #[test]
8062 fn assoc_02_pipe_left() {
8063 let (e, diags) = parse_expr_str("a |> b |> c");
8065 assert!(!diags.has_errors(), "{diags:?}");
8066 match &e {
8067 Expr::Pipe { left, .. } => {
8068 assert!(
8069 matches!(left.as_ref(), Expr::Pipe { .. }),
8070 "pipe should be left-assoc, got {left:?}"
8071 );
8072 }
8073 _ => panic!("expected Pipe, got {e:?}"),
8074 }
8075 }
8076
8077 #[test]
8078 fn assoc_03_compose_left() {
8079 let (e, diags) = parse_expr_str("a >> b >> c");
8081 assert!(!diags.has_errors(), "{diags:?}");
8082 match &e {
8083 Expr::Compose { left, .. } => {
8084 assert!(
8085 matches!(left.as_ref(), Expr::Compose { .. }),
8086 "compose should be left-assoc, got {left:?}"
8087 );
8088 }
8089 _ => panic!("expected Compose, got {e:?}"),
8090 }
8091 }
8092
8093 #[test]
8094 fn assoc_04_range_non_assoc() {
8095 let (_, diags) = parse_expr_str("a .. b .. c");
8097 assert!(diags.has_errors(), "chained .. must produce a parse error");
8098 }
8099
8100 #[test]
8101 fn assoc_05_or_left() {
8102 let (e, diags) = parse_expr_str("a || b || c");
8104 assert!(!diags.has_errors(), "{diags:?}");
8105 match &e {
8106 Expr::Binary {
8107 op: BinOp::Or,
8108 left,
8109 ..
8110 } => {
8111 assert!(
8112 matches!(left.as_ref(), Expr::Binary { op: BinOp::Or, .. }),
8113 "|| should be left-assoc, got {left:?}"
8114 );
8115 }
8116 _ => panic!("expected Or, got {e:?}"),
8117 }
8118 }
8119
8120 #[test]
8121 fn assoc_06_and_left() {
8122 let (e, diags) = parse_expr_str("a && b && c");
8124 assert!(!diags.has_errors(), "{diags:?}");
8125 match &e {
8126 Expr::Binary {
8127 op: BinOp::And,
8128 left,
8129 ..
8130 } => {
8131 assert!(
8132 matches!(left.as_ref(), Expr::Binary { op: BinOp::And, .. }),
8133 "&& should be left-assoc, got {left:?}"
8134 );
8135 }
8136 _ => panic!("expected And, got {e:?}"),
8137 }
8138 }
8139
8140 #[test]
8141 fn assoc_07_comparison_non_assoc() {
8142 let (_, diags) = parse_expr_str("a == b == c");
8144 assert!(diags.has_errors(), "chained == must produce a parse error");
8145 }
8146
8147 #[test]
8148 fn assoc_08_bitor_left() {
8149 let (e, diags) = parse_expr_str("a | b | c");
8151 assert!(!diags.has_errors(), "{diags:?}");
8152 match &e {
8153 Expr::Binary {
8154 op: BinOp::BitOr,
8155 left,
8156 ..
8157 } => {
8158 assert!(
8159 matches!(
8160 left.as_ref(),
8161 Expr::Binary {
8162 op: BinOp::BitOr,
8163 ..
8164 }
8165 ),
8166 "| should be left-assoc, got {left:?}"
8167 );
8168 }
8169 _ => panic!("expected BitOr, got {e:?}"),
8170 }
8171 }
8172
8173 #[test]
8174 fn assoc_09_bitxor_left() {
8175 let (e, diags) = parse_expr_str("a ^ b ^ c");
8177 assert!(!diags.has_errors(), "{diags:?}");
8178 match &e {
8179 Expr::Binary {
8180 op: BinOp::BitXor,
8181 left,
8182 ..
8183 } => {
8184 assert!(
8185 matches!(
8186 left.as_ref(),
8187 Expr::Binary {
8188 op: BinOp::BitXor,
8189 ..
8190 }
8191 ),
8192 "^ should be left-assoc, got {left:?}"
8193 );
8194 }
8195 _ => panic!("expected BitXor, got {e:?}"),
8196 }
8197 }
8198
8199 #[test]
8200 fn assoc_10_bitand_left() {
8201 let (e, diags) = parse_expr_str("a & b & c");
8203 assert!(!diags.has_errors(), "{diags:?}");
8204 match &e {
8205 Expr::Binary {
8206 op: BinOp::BitAnd,
8207 left,
8208 ..
8209 } => {
8210 assert!(
8211 matches!(
8212 left.as_ref(),
8213 Expr::Binary {
8214 op: BinOp::BitAnd,
8215 ..
8216 }
8217 ),
8218 "& should be left-assoc, got {left:?}"
8219 );
8220 }
8221 _ => panic!("expected BitAnd, got {e:?}"),
8222 }
8223 }
8224
8225 #[test]
8226 fn assoc_11_add_left() {
8227 let (e, diags) = parse_expr_str("a - b - c");
8229 assert!(!diags.has_errors(), "{diags:?}");
8230 match &e {
8231 Expr::Binary {
8232 op: BinOp::Sub,
8233 left,
8234 ..
8235 } => {
8236 assert!(
8237 matches!(left.as_ref(), Expr::Binary { op: BinOp::Sub, .. }),
8238 "- should be left-assoc, got {left:?}"
8239 );
8240 }
8241 _ => panic!("expected Sub, got {e:?}"),
8242 }
8243 }
8244
8245 #[test]
8246 fn assoc_12_mul_left() {
8247 let (e, diags) = parse_expr_str("a / b / c");
8249 assert!(!diags.has_errors(), "{diags:?}");
8250 match &e {
8251 Expr::Binary {
8252 op: BinOp::Div,
8253 left,
8254 ..
8255 } => {
8256 assert!(
8257 matches!(left.as_ref(), Expr::Binary { op: BinOp::Div, .. }),
8258 "/ should be left-assoc, got {left:?}"
8259 );
8260 }
8261 _ => panic!("expected Div, got {e:?}"),
8262 }
8263 }
8264
8265 #[test]
8266 fn assoc_13_power_right() {
8267 let (e, diags) = parse_expr_str("a ** b ** c");
8269 assert!(!diags.has_errors(), "{diags:?}");
8270 match &e {
8271 Expr::Binary {
8272 op: BinOp::Pow,
8273 right,
8274 ..
8275 } => {
8276 assert!(
8277 matches!(right.as_ref(), Expr::Binary { op: BinOp::Pow, .. }),
8278 "** should be right-assoc, got {right:?}"
8279 );
8280 }
8281 _ => panic!("expected Pow, got {e:?}"),
8282 }
8283 }
8284
8285 #[test]
8286 fn assoc_14_unary_chains() {
8287 let (e, diags) = parse_expr_str("--a");
8289 assert!(!diags.has_errors(), "{diags:?}");
8290 match &e {
8291 Expr::Unary {
8292 op: UnaryOp::Neg,
8293 operand,
8294 ..
8295 } => {
8296 assert!(
8297 matches!(
8298 operand.as_ref(),
8299 Expr::Unary {
8300 op: UnaryOp::Neg,
8301 ..
8302 }
8303 ),
8304 "unary should chain, got {operand:?}"
8305 );
8306 }
8307 _ => panic!("expected Neg(Neg), got {e:?}"),
8308 }
8309 }
8310
8311 #[test]
8312 fn assoc_15_postfix_chains_left() {
8313 let (e, diags) = parse_expr_str("a.b.c");
8315 assert!(!diags.has_errors(), "{diags:?}");
8316 match &e {
8317 Expr::FieldAccess { field, object, .. } => {
8318 assert_eq!(field.name, "c");
8319 assert!(
8320 matches!(object.as_ref(), Expr::FieldAccess { .. }),
8321 "postfix should chain left, got {object:?}"
8322 );
8323 }
8324 _ => panic!("expected FieldAccess, got {e:?}"),
8325 }
8326 }
8327
8328 #[test]
8331 fn module_qualified_record_construct() {
8332 let (e, diags) = parse_expr_str("Mod.Type { field: val }");
8334 assert!(!diags.has_errors(), "{diags:?}");
8335 match e {
8336 Expr::RecordConstruct { path, fields, .. } => {
8337 assert_eq!(path.segments.len(), 2);
8338 assert_eq!(path.segments[0].name, "Mod");
8339 assert_eq!(path.segments[1].name, "Type");
8340 assert_eq!(fields.len(), 1);
8341 assert_eq!(fields[0].name.name, "field");
8342 }
8343 _ => panic!("expected RecordConstruct, got {e:?}"),
8344 }
8345 }
8346
8347 #[test]
8348 fn deeply_qualified_record_construct() {
8349 let (e, diags) = parse_expr_str("A.B.C { x: 1 }");
8351 assert!(!diags.has_errors(), "{diags:?}");
8352 match e {
8353 Expr::RecordConstruct { path, fields, .. } => {
8354 assert_eq!(path.segments.len(), 3);
8355 assert_eq!(path.segments[0].name, "A");
8356 assert_eq!(path.segments[1].name, "B");
8357 assert_eq!(path.segments[2].name, "C");
8358 assert_eq!(fields.len(), 1);
8359 }
8360 _ => panic!("expected RecordConstruct, got {e:?}"),
8361 }
8362 }
8363
8364 #[test]
8365 fn lowercase_field_access_not_record() {
8366 let (e, diags) = parse_expr_str("Mod.field");
8369 assert!(!diags.has_errors(), "{diags:?}");
8370 assert!(
8371 matches!(e, Expr::FieldAccess { .. }),
8372 "expected FieldAccess, got {e:?}"
8373 );
8374 }
8375
8376 #[test]
8379 fn method_type_args_single() {
8380 let (e, diags) = parse_expr_str("obj.method[T]()");
8382 assert!(!diags.has_errors(), "{diags:?}");
8383 match e {
8384 Expr::MethodCall {
8385 method,
8386 type_args,
8387 args,
8388 ..
8389 } => {
8390 assert_eq!(method.name, "method");
8391 assert_eq!(type_args.len(), 1);
8392 assert!(args.is_empty());
8393 }
8394 _ => panic!("expected MethodCall, got {e:?}"),
8395 }
8396 }
8397
8398 #[test]
8399 fn method_type_args_multiple() {
8400 let (e, diags) = parse_expr_str("obj.convert[From, To](x)");
8402 assert!(!diags.has_errors(), "{diags:?}");
8403 match e {
8404 Expr::MethodCall {
8405 method,
8406 type_args,
8407 args,
8408 ..
8409 } => {
8410 assert_eq!(method.name, "convert");
8411 assert_eq!(type_args.len(), 2);
8412 assert_eq!(args.len(), 1);
8413 }
8414 _ => panic!("expected MethodCall, got {e:?}"),
8415 }
8416 }
8417
8418 #[test]
8419 fn index_access_not_type_args() {
8420 let (e, diags) = parse_expr_str("obj.data[0]");
8422 assert!(!diags.has_errors(), "{diags:?}");
8423 assert!(matches!(e, Expr::Index { .. }), "expected Index, got {e:?}");
8425 }
8426
8427 #[test]
8430 fn doc_comment_before_fn_no_error() {
8431 let (m, diags) = parse("/// Adds two numbers\nfn add(a: Int, b: Int) -> Int { a + b }\n");
8432 assert!(
8433 !diags.has_errors(),
8434 "doc comment before fn caused errors: {diags:?}"
8435 );
8436 assert_eq!(m.items.len(), 1);
8437 assert!(matches!(m.items[0], Item::Fn(_)));
8438 }
8439
8440 #[test]
8441 fn doc_comment_before_record_no_error() {
8442 let (m, diags) = parse("/// A user\nrecord User {\n name: String\n}\n");
8443 assert!(
8444 !diags.has_errors(),
8445 "doc comment before record caused errors: {diags:?}"
8446 );
8447 assert_eq!(m.items.len(), 1);
8448 assert!(matches!(m.items[0], Item::Record(_)));
8449 }
8450
8451 #[test]
8452 fn doc_comment_before_enum_no_error() {
8453 let (m, diags) = parse("/// Colors\nenum Color {\n Red\n Green\n}\n");
8454 assert!(
8455 !diags.has_errors(),
8456 "doc comment before enum caused errors: {diags:?}"
8457 );
8458 assert_eq!(m.items.len(), 1);
8459 assert!(matches!(m.items[0], Item::Enum(_)));
8460 }
8461
8462 #[test]
8463 fn doc_comment_before_trait_no_error() {
8464 let (m, diags) =
8465 parse("/// Greetable things\ntrait Greetable {\n fn greet() -> String\n}\n");
8466 assert!(
8467 !diags.has_errors(),
8468 "doc comment before trait caused errors: {diags:?}"
8469 );
8470 assert_eq!(m.items.len(), 1);
8471 assert!(matches!(m.items[0], Item::Trait(_)));
8472 }
8473
8474 #[test]
8475 fn multiple_consecutive_doc_comments() {
8476 let (m, diags) = parse("/// Line 1\n/// Line 2\n/// Line 3\nfn foo() {}\n");
8477 assert!(
8478 !diags.has_errors(),
8479 "multiple doc comments caused errors: {diags:?}"
8480 );
8481 assert_eq!(m.items.len(), 1);
8482 assert!(matches!(m.items[0], Item::Fn(_)));
8483 }
8484
8485 #[test]
8486 fn module_doc_comment_no_error() {
8487 let (m, diags) = parse("//! Module docs\n\nfn foo() {}\n");
8488 assert!(
8489 !diags.has_errors(),
8490 "module doc comment caused errors: {diags:?}"
8491 );
8492 assert_eq!(m.doc.len(), 1);
8493 assert_eq!(m.doc[0], "Module docs");
8494 }
8495
8496 #[test]
8497 fn module_doc_comment_after_module_decl() {
8498 let (m, diags) = parse("module foo\n\n//! After module\n//! More docs\n\nfn bar() {}\n");
8500 assert!(
8501 !diags.has_errors(),
8502 "//! after module decl caused errors: {diags:?}"
8503 );
8504 assert_eq!(m.doc.len(), 2);
8505 assert_eq!(m.doc[0], "After module");
8506 assert_eq!(m.doc[1], "More docs");
8507 assert_eq!(m.items.len(), 1);
8508 }
8509
8510 #[test]
8511 fn module_doc_comment_before_and_after_module_decl() {
8512 let (m, diags) = parse("//! Before\nmodule foo\n//! After\nfn bar() {}\n");
8514 assert!(
8515 !diags.has_errors(),
8516 "//! before+after module decl caused errors: {diags:?}"
8517 );
8518 assert_eq!(m.doc.len(), 2);
8519 assert_eq!(m.doc[0], "Before");
8520 assert_eq!(m.doc[1], "After");
8521 }
8522
8523 #[test]
8524 fn module_doc_comment_after_module_with_use_no_hang() {
8525 let (m, diags) = parse("module foo\n//! Docs\nuse bar.{baz}\nfn f() {}\n");
8527 assert!(
8528 !diags.has_errors(),
8529 "//! after module with use caused errors: {diags:?}"
8530 );
8531 assert_eq!(m.doc.len(), 1);
8532 assert_eq!(m.imports.len(), 1);
8533 }
8534
8535 #[test]
8536 fn doc_comment_trailing_no_error() {
8537 let (_m, diags) = parse("/// orphan doc\n");
8539 assert!(
8540 !diags.has_errors(),
8541 "trailing doc comment caused errors: {diags:?}"
8542 );
8543 }
8544}