1use crate::ast::{
8 Alt, Binding, ChoiceDecl, Consuming, Decl, DoStmt, Equation, ExpectedToken, Expr, FieldAssign,
9 FieldDecl, FunctionDecl, Identifier, ImportDecl, ImportStyle, InterfaceDecl,
10 InterfaceInstanceDecl, LitKind, MalformedSyntaxKind, Module, ModuleName, Operator,
11 ParseDiagnostic, ParseDiagnosticKind, Pat, SkippedDeclarationReason, Span, TemplateBodyDecl,
12 TemplateDecl, Type, TypeAnnotation, TypeAnnotationContext, UnsupportedSyntaxKind,
13};
14use crate::layout::resolve_layout;
15use crate::lexer::{lex, Pos, Token, TokenKind};
16use std::collections::HashMap;
17
18pub const MAX_RECURSION_DEPTH: u32 = 128;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct ParseModuleResult {
29 pub module: Module,
32 pub diagnostics: Vec<ParseDiagnostic>,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct ParseModuleError {
44 diagnostics: Vec<ParseDiagnostic>,
45 module: Box<Module>,
46}
47
48impl ParseModuleError {
49 #[must_use]
50 pub fn diagnostics(&self) -> &[ParseDiagnostic] {
51 &self.diagnostics
52 }
53
54 #[must_use]
55 pub fn module(&self) -> &Module {
56 &self.module
57 }
58
59 #[must_use]
60 pub fn into_parts(self) -> (Vec<ParseDiagnostic>, Module) {
61 (self.diagnostics, *self.module)
62 }
63}
64
65impl std::fmt::Display for ParseModuleError {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(
68 f,
69 "parse failed with {} diagnostic(s)",
70 self.diagnostics.len()
71 )?;
72 if let Some(first) = self.diagnostics.first() {
73 write!(f, ": {}", first.message)?;
74 }
75 Ok(())
76 }
77}
78
79impl std::error::Error for ParseModuleError {}
80
81#[derive(Clone, Copy, Debug)]
82enum DoExpressionMode {
83 Allow,
84 Disallow,
85}
86
87impl DoExpressionMode {
88 const fn allows_do(&self) -> bool {
89 matches!(self, Self::Allow)
90 }
91}
92
93impl ParseModuleResult {
94 #[must_use]
96 pub const fn has_errors(&self) -> bool {
97 !self.diagnostics.is_empty()
98 }
99
100 #[must_use]
102 pub fn into_parts(self) -> (Module, Vec<ParseDiagnostic>) {
103 (self.module, self.diagnostics)
104 }
105
106 pub fn into_result(self) -> Result<Module, ParseModuleError> {
116 if self.diagnostics.is_empty() {
117 Ok(self.module)
118 } else {
119 Err(ParseModuleError {
120 diagnostics: self.diagnostics,
121 module: Box::new(self.module),
122 })
123 }
124 }
125}
126
127#[must_use]
142pub fn parse_module(source: &str) -> ParseModuleResult {
143 let lexed = lex(source);
144 let tokens = lexed.tokens;
145 let lex_errors = lexed.errors;
146 let tokens = resolve_layout(tokens);
147 let mut p = Parser {
148 toks: tokens,
149 src_len: source.len(),
150 i: 0,
151 depth: 0,
152 diags: lex_errors
153 .into_iter()
154 .map(|e| {
155 let range = e.byte_range_in(source);
156 ParseDiagnostic::new(
157 ParseDiagnosticKind::Lex(e.kind.clone()),
158 e.to_string(),
159 e.pos,
160 crate::ast::Span::from_usize(range.start, range.end),
161 )
162 })
163 .collect(),
164 };
165 let mut module = p.module();
166 module.span = crate::ast::Span::from_usize(0, source.len());
167 ParseModuleResult {
168 module,
169 diagnostics: p.diags,
170 }
171}
172
173pub fn parse_module_strict(source: &str) -> Result<Module, ParseModuleError> {
201 parse_module(source).into_result()
202}
203
204struct Parser {
205 toks: Vec<Token>,
206 src_len: usize,
208 i: usize,
209 diags: Vec<ParseDiagnostic>,
210 depth: u32,
213}
214
215impl Parser {
216 fn node_span(&self, from: usize) -> crate::ast::Span {
222 let mut a = from;
223 while a < self.i && self.toks[a].is_virtual() {
224 a += 1;
225 }
226 let mut b = self.i;
227 while b > a && self.toks[b - 1].is_virtual() {
228 b -= 1;
229 }
230 if a >= b {
231 let p = self.byte_at(a);
236 return crate::ast::Span::from_usize(p, p);
237 }
238 crate::ast::Span::from_usize(self.toks[a].start, self.toks[b - 1].end)
239 }
240
241 fn byte_at(&self, i: usize) -> usize {
243 self.toks.get(i).map(|t| t.start).unwrap_or(self.src_len)
244 }
245
246 fn end_byte(&self) -> usize {
250 let mut b = self.i;
251 while b > 0 && self.toks[b - 1].is_virtual() {
252 b -= 1;
253 }
254 if b == 0 {
255 0
256 } else {
257 self.toks[b - 1].end
258 }
259 }
260}
261
262impl Parser {
263 fn peek(&self) -> Option<&TokenKind> {
266 self.toks.get(self.i).map(|t| &t.kind)
267 }
268
269 fn peek_at(&self, n: usize) -> Option<&TokenKind> {
270 self.toks.get(self.i + n).map(|t| &t.kind)
271 }
272
273 fn pos(&self) -> Pos {
274 self.toks
275 .get(self.i)
276 .or_else(|| self.toks.last())
277 .map_or(Pos { line: 1, column: 1 }, |t| t.pos)
278 }
279
280 fn bump(&mut self) -> Option<Token> {
281 let t = self.toks.get(self.i).cloned();
282 if t.is_some() {
283 self.i += 1;
284 }
285 t
286 }
287
288 fn at_keyword(&self, kw: &str) -> bool {
289 self.peek().is_some_and(|t| t.is_keyword(kw))
290 }
291
292 fn eat_keyword(&mut self, kw: &str) -> bool {
293 if self.at_keyword(kw) {
294 self.i += 1;
295 true
296 } else {
297 false
298 }
299 }
300
301 fn at_op(&self, op: &str) -> bool {
302 self.peek().is_some_and(|t| t.is_op(op))
303 }
304
305 fn eat_op(&mut self, op: &str) -> bool {
306 if self.at_op(op) {
307 self.i += 1;
308 true
309 } else {
310 false
311 }
312 }
313
314 fn at(&self, tok: &TokenKind) -> bool {
315 self.peek() == Some(tok)
316 }
317
318 fn eat(&mut self, tok: &TokenKind) -> bool {
319 if self.at(tok) {
320 self.i += 1;
321 true
322 } else {
323 false
324 }
325 }
326
327 fn diag_expected(&mut self, expected: ExpectedToken, message: impl Into<String>) {
329 self.diag_kind(ParseDiagnosticKind::ExpectedToken(expected), message);
330 }
331
332 fn diag_malformed(&mut self, kind: MalformedSyntaxKind, message: impl Into<String>) {
334 self.diag_kind(ParseDiagnosticKind::MalformedSyntax(kind), message);
335 }
336
337 fn diag_kind(&mut self, kind: ParseDiagnosticKind, message: impl Into<String>) {
341 let pos = self.pos();
342 let span = self.cur_span();
343 self.diags
344 .push(ParseDiagnostic::new(kind, message, pos, span));
345 }
346
347 fn parse_type_annotation(
348 &mut self,
349 type_start: usize,
350 type_end: usize,
351 context: TypeAnnotationContext,
352 ) -> TypeAnnotation {
353 let type_start = type_start.min(self.toks.len());
354 let type_end = type_end.min(self.toks.len());
355 let tokens = &self.toks[type_start..type_end];
356 let ty = parse_type_from_tokens(tokens).or_else(|| {
357 let trimmed = Self::trim_type_tokens_for_parse(tokens);
358 if trimmed < tokens.len() {
359 parse_type_from_tokens(&tokens[..trimmed])
360 } else {
361 None
362 }
363 });
364 match ty {
365 Some(ty) => TypeAnnotation::Present(ty),
366 None => {
367 let span = self.span_of_token_range(type_start, type_end);
368 self.diags.push(ParseDiagnostic::new(
369 ParseDiagnosticKind::MalformedTypeAnnotation(context),
370 format!("malformed {} type annotation", context.as_str()),
371 self.pos_of_token(type_start),
372 span,
373 ));
374 TypeAnnotation::Malformed { span }
375 }
376 }
377 }
378
379 fn trim_type_tokens_for_parse(tokens: &[Token]) -> usize {
384 let mut depth = 0usize;
385 let mut bracket_depth = 0usize;
386 let mut i = 0usize;
387 while i < tokens.len() {
388 match &tokens[i].kind {
389 TokenKind::LParen | TokenKind::LBracket => {
390 depth += 1;
391 i += 1;
392 }
393 TokenKind::RParen | TokenKind::RBracket => {
394 depth = depth.saturating_sub(1);
395 i += 1;
396 }
397 TokenKind::LBrace => {
398 bracket_depth += 1;
399 i += 1;
400 }
401 TokenKind::RBrace => {
402 bracket_depth = bracket_depth.saturating_sub(1);
403 i += 1;
404 }
405 TokenKind::Op(o) if o.as_str() == "=" && depth == 0 && bracket_depth == 0 => {
406 return i;
407 }
408 TokenKind::Semi | TokenKind::VSemi if depth == 0 && bracket_depth == 0 => {
409 return i;
410 }
411 TokenKind::Comma
412 if depth == 0
413 && bracket_depth == 0
414 && matches!(
415 tokens.get(i + 1),
416 Some(Token {
417 kind: TokenKind::LowerId {
418 qualifier: None,
419 ..
420 },
421 ..
422 })
423 )
424 && matches!(
425 tokens.get(i + 2),
426 Some(Token { kind: TokenKind::Op(o), .. }) if o.as_str() == ":"
427 ) =>
428 {
429 return i;
430 }
431 _ => {
432 i += 1;
433 }
434 }
435 }
436 tokens.len()
437 }
438
439 fn pos_of_token(&self, idx: usize) -> Pos {
440 self.toks.get(idx).map_or_else(|| self.pos(), |tok| tok.pos)
441 }
442
443 fn span_of_token_range(&self, start: usize, end: usize) -> Span {
444 let start = start.min(self.toks.len());
445 let end = end.min(self.toks.len());
446 let span_start = self.byte_at(start);
447 if end <= start {
448 return Span::from_usize(span_start, span_start);
449 }
450
451 let mut cursor = end;
452 while cursor > start {
453 cursor -= 1;
454 let token = &self.toks[cursor];
455 if !token.is_virtual() {
456 return Span::from_usize(span_start, token.end);
457 }
458 }
459
460 Span::from_usize(span_start, span_start)
461 }
462
463 fn cur_span(&self) -> crate::ast::Span {
466 let mut j = self.i;
467 while self.toks.get(j).is_some_and(|t| t.is_virtual()) {
468 j += 1;
469 }
470 self.toks.get(j).map_or_else(
471 || crate::ast::Span::from_usize(self.src_len, self.src_len),
472 |t| crate::ast::Span::from_usize(t.start, t.end),
473 )
474 }
475
476 fn skip_to_item_end(&mut self) {
479 let mut depth = 0usize;
480 let mut brackets = 0usize;
481 while let Some(t) = self.peek() {
482 match t {
483 TokenKind::VLBrace => depth += 1,
484 TokenKind::VRBrace => {
485 if depth == 0 {
486 return;
487 }
488 depth -= 1;
489 }
490 TokenKind::VSemi if depth == 0 && brackets == 0 => return,
491 TokenKind::LParen | TokenKind::LBracket | TokenKind::LBrace => brackets += 1,
492 TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace => {
493 if brackets == 0 {
494 return;
497 }
498 brackets -= 1;
499 }
500 _ => {}
501 }
502 self.i += 1;
503 }
504 }
505
506 fn slice_text(&self, start: usize) -> String {
508 render_token_slice(&self.toks[start..self.i])
509 }
510
511 fn module(&mut self) -> Module {
514 let pos = self.pos();
515 let header_start = self.i;
516 let mut header = crate::ast::Span::from_usize(0, 0);
517 let mut name = ModuleName::from("Unknown");
518
519 if self.eat_keyword("module") {
520 if let Some(TokenKind::UpperId { qualifier, name: n }) = self.peek().cloned() {
521 self.bump();
522 name = match qualifier {
523 Some(q) => format!("{q}.{n}").into(),
524 None => n.into(),
525 };
526 }
527 if self.at(&TokenKind::LParen) {
529 self.skip_balanced_parens();
530 }
531 if !self.eat_keyword("where") {
532 self.diag_expected(
533 ExpectedToken::WhereAfterModuleHeader,
534 "expected 'where' after module header",
535 );
536 }
537 header = self.node_span(header_start);
538 }
539
540 let mut imports = Vec::new();
541 let mut decls: Vec<Decl> = Vec::new();
542
543 let _ = self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace);
547 loop {
548 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
549 match self.peek() {
550 None => break,
551 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
552 self.bump();
553 break;
554 }
555 Some(TokenKind::RParen | TokenKind::RBracket) => {
560 let cpos = self.pos();
561 let cstart = self.i;
562 self.bump();
563 decls.push(Decl::Unknown {
564 raw: self.slice_text(cstart),
565 pos: cpos,
566 span: self.node_span(cstart),
567 });
568 continue;
569 }
570 _ => {}
571 }
572 let before = self.i;
573 self.declaration(&mut imports, &mut decls);
574 if self.i == before {
575 self.bump();
577 }
578 }
579
580 merge_functions(&mut decls);
581
582 Module {
583 name,
584 pos,
585 header,
586 imports,
587 decls,
588 span: crate::ast::Span::from_usize(0, self.src_len),
589 }
590 }
591
592 fn skip_balanced_parens(&mut self) {
593 let mut depth = 0usize;
594 while let Some(t) = self.peek() {
595 match t {
596 TokenKind::LParen => depth += 1,
597 TokenKind::RParen => {
598 if depth == 0 {
599 return;
600 }
601 depth -= 1;
602 if depth == 0 {
603 self.i += 1;
604 return;
605 }
606 }
607 _ => {}
608 }
609 self.i += 1;
610 }
611 }
612
613 fn try_infix_operator_decl(&mut self) -> bool {
617 let snap = self.i;
618 let saved_diags = self.diags.len();
619 if self.pattern().is_some()
620 && matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o))
621 {
622 self.skip_to_item_end();
623 return true;
624 }
625 self.i = snap;
626 self.diags.truncate(saved_diags);
627 false
628 }
629
630 fn declaration(&mut self, imports: &mut Vec<ImportDecl>, decls: &mut Vec<Decl>) {
631 let pos = self.pos();
632 let start = self.i;
633 if matches!(
634 self.peek(),
635 Some(TokenKind::UpperId { .. } | TokenKind::LBracket | TokenKind::LParen)
636 ) && self.try_infix_operator_decl()
637 {
638 decls.push(Decl::Unknown {
639 raw: self.slice_text(start),
640 pos,
641 span: self.node_span(start),
642 });
643 return;
644 }
645 match self.peek() {
646 Some(t) if t.is_keyword("import") => {
647 let imp = self.import_decl();
648 self.skip_to_item_end();
652 if let Some(mut imp) = imp {
653 imp.span = self.node_span(start);
654 imports.push(imp);
655 }
656 }
657 Some(t) if t.is_keyword("template") => {
658 match self.template_decl() {
661 Some(t) => decls.push(Decl::Template(t)),
662 None => {
663 self.skip_to_item_end();
664 decls.push(Decl::Unknown {
665 raw: self.slice_text(start),
666 span: self.node_span(start),
667 pos,
668 });
669 }
670 }
671 }
672 Some(t) if t.is_keyword("interface") => match self.interface_decl() {
673 Some(i) => decls.push(Decl::Interface(i)),
674 None => {
675 self.skip_to_item_end();
676 decls.push(Decl::Unknown {
677 raw: self.slice_text(start),
678 span: self.node_span(start),
679 pos,
680 });
681 }
682 },
683 Some(t)
684 if matches!(
685 t.keyword(),
686 Some("infix" | "infixl" | "infixr" | "default" | "pattern")
689 ) =>
690 {
691 self.skip_to_item_end();
692 decls.push(Decl::Unknown {
693 raw: self.slice_text(start),
694 pos,
695 span: self.node_span(start),
696 });
697 }
698 Some(t)
699 if matches!(
700 t.keyword(),
701 Some(
702 "data"
703 | "type"
704 | "newtype"
705 | "class"
706 | "instance"
707 | "exception"
708 | "deriving"
709 )
710 ) =>
711 {
712 let keyword = t
713 .keyword()
714 .expect("declaration-head keyword token")
715 .to_string();
716 self.bump();
717 let name = match self.peek() {
718 Some(TokenKind::UpperId { qualifier, name }) => {
719 let n = qualifier
720 .as_ref()
721 .map_or_else(|| name.to_string(), |q| format!("{q}.{name}"));
722 self.bump();
723 n
724 }
725 _ => String::new(),
726 };
727 self.skip_to_item_end();
728 decls.push(Decl::TypeDef {
729 keyword,
730 name: name.into(),
731 pos,
732 span: self.node_span(start),
733 });
734 }
735 Some(TokenKind::LowerId { .. }) => match self.function_item() {
736 Some(d) => decls.push(d),
737 None => {
738 self.skip_to_item_end();
739 decls.push(Decl::Unknown {
740 raw: self.slice_text(start),
741 span: self.node_span(start),
742 pos,
743 });
744 }
745 },
746 Some(TokenKind::LParen)
748 if matches!(self.peek_at(1), Some(TokenKind::Op(_)))
749 && self.peek_at(2) == Some(&TokenKind::RParen) =>
750 {
751 self.skip_to_item_end();
752 decls.push(Decl::Unknown {
753 raw: self.slice_text(start),
754 span: self.node_span(start),
755 pos,
756 });
757 }
758 Some(TokenKind::LParen | TokenKind::LBracket) => {
760 if self.binding().is_none() {
761 self.diag_kind(
762 ParseDiagnosticKind::SkippedDeclaration(
763 SkippedDeclarationReason::TopLevelPatternBinding,
764 ),
765 "unparseable top-level pattern binding",
766 );
767 }
768 self.skip_to_item_end();
769 decls.push(Decl::Unknown {
770 raw: self.slice_text(start),
771 span: self.node_span(start),
772 pos,
773 });
774 }
775 _ => {
776 self.diag_kind(
777 ParseDiagnosticKind::SkippedDeclaration(
778 SkippedDeclarationReason::UnrecognizedDeclaration,
779 ),
780 format!("unrecognized declaration: {:?}", self.peek()),
781 );
782 self.skip_to_item_end();
783 decls.push(Decl::Unknown {
784 raw: self.slice_text(start),
785 span: self.node_span(start),
786 pos,
787 });
788 }
789 }
790 }
791
792 fn import_decl(&mut self) -> Option<ImportDecl> {
795 let pos = self.pos();
796 let start_i = self.i;
797 self.bump(); let mut style = if self.eat_keyword("qualified") {
799 ImportStyle::Qualified
800 } else {
801 ImportStyle::Unqualified
802 };
803 if matches!(self.peek(), Some(TokenKind::StringLit(_))) {
805 self.bump();
806 }
807 let module_name = match self.peek().cloned() {
808 Some(TokenKind::UpperId { qualifier, name }) => {
809 self.bump();
810 match qualifier {
811 Some(q) => format!("{q}.{name}").into(),
812 None => name.into(),
813 }
814 }
815 _ => {
816 self.diag_expected(
817 ExpectedToken::ModuleNameAfterImport,
818 "expected module name after 'import'",
819 );
820 return None;
821 }
822 };
823 if self.eat_keyword("qualified") {
825 style = ImportStyle::Qualified;
826 }
827 let mut alias = None;
828 if self.eat_keyword("as") {
829 if let Some(TokenKind::UpperId { qualifier, name }) = self.peek().cloned() {
830 self.bump();
831 alias = Some(match qualifier {
832 Some(q) => format!("{q}.{name}").into(),
833 None => name.into(),
834 });
835 }
836 }
837 Some(ImportDecl {
839 module_name,
840 style,
841 alias,
842 pos,
843 span: self.node_span(start_i),
844 })
845 }
846
847 fn upper_name(&mut self) -> Option<ModuleName> {
850 match self.peek().cloned() {
851 Some(TokenKind::UpperId { qualifier, name }) => {
852 self.bump();
853 Some(match qualifier {
854 Some(q) => format!("{q}.{name}").into(),
855 None => name.into(),
856 })
857 }
858 _ => None,
859 }
860 }
861
862 fn template_decl(&mut self) -> Option<TemplateDecl> {
863 let pos = self.pos();
864 let start_i = self.i;
865 self.bump(); if self.at_keyword("instance") {
867 return None; }
869 let name = self.upper_name()?.to_string().into();
870
871 let fields = self
872 .eat_keyword("with")
873 .then(|| self.field_block())
874 .map(|parsed| parsed.fields)
875 .unwrap_or_default();
876 let body = if self.eat_keyword("where") {
877 self.template_body()
878 } else {
879 Vec::new()
880 };
881 Some(TemplateDecl {
882 name,
883 fields,
884 body,
885 pos,
886 span: self.node_span(start_i),
887 })
888 }
889
890 fn field_block(&mut self) -> FieldBlock {
897 let mut fields = Vec::new();
898 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
899 return FieldBlock {
900 fields,
901 dangling: false,
902 };
903 }
904 loop {
905 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
906 match self.peek() {
907 None => break,
908 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
909 self.bump();
910 break;
911 }
912 Some(TokenKind::RParen | TokenKind::RBracket) => {
917 self.bump();
918 continue;
919 }
920 _ => {}
921 }
922 {
927 let mut j = self.i;
928 while let Some(TokenKind::LowerId {
929 qualifier: None, ..
930 }) = self.toks.get(j).map(|t| &t.kind)
931 {
932 j += 1;
933 match self.toks.get(j).map(|t| &t.kind) {
934 Some(TokenKind::Comma) => j += 1,
935 _ => break,
936 }
937 }
938 let is_field = j > self.i
939 && self
940 .toks
941 .get(j)
942 .map(|t| &t.kind)
943 .is_some_and(|t| t.is_op(":"));
944 if !is_field {
945 return FieldBlock {
946 fields,
947 dangling: true,
948 };
949 }
950 }
951 let mut names: Vec<(Identifier, Pos, Span)> = Vec::new();
953 while let Some(TokenKind::LowerId {
954 qualifier: None,
955 name,
956 }) = self.peek().cloned()
957 {
958 let p = self.pos();
959 let nspan = Span::from_usize(self.toks[self.i].start, self.toks[self.i].end);
960 self.bump();
961 names.push((name, p, nspan));
962 if !self.eat(&TokenKind::Comma) {
963 break;
964 }
965 }
966 if names.is_empty() || !self.eat_op(":") {
967 self.diag_expected(
968 ExpectedToken::FieldNameTypePair,
969 "expected 'name : Type' field",
970 );
971 self.skip_to_item_end();
972 continue;
973 }
974 let ty_start = self.i;
975 self.skip_to_item_end();
976 let ty = self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Field);
977 let type_end = self.end_byte();
982 let last = names.len() - 1;
983 for (idx, (name, p, nspan)) in names.into_iter().enumerate() {
984 let span = if idx == last {
985 Span::from_usize(nspan.start_usize(), type_end.max(nspan.end_usize()))
986 } else {
987 nspan
988 };
989 fields.push(FieldDecl {
990 name: name.to_string().into(),
991 ty: ty.clone(),
992 pos: p,
993 span,
994 });
995 }
996 }
997 FieldBlock {
998 fields,
999 dangling: false,
1000 }
1001 }
1002
1003 fn template_body(&mut self) -> Vec<TemplateBodyDecl> {
1006 let mut body = Vec::new();
1007 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1008 return body;
1009 }
1010 loop {
1011 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1012 match self.peek() {
1013 None => break,
1014 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1015 self.bump();
1016 break;
1017 }
1018 Some(TokenKind::RParen | TokenKind::RBracket) => {
1023 self.bump();
1024 continue;
1025 }
1026 _ => {}
1027 }
1028 let pos = self.pos();
1029 let start = self.i;
1030 let decl = self.template_body_item(pos, start);
1031 body.push(decl);
1032 }
1033 body
1034 }
1035
1036 fn template_body_item(&mut self, pos: Pos, start: usize) -> TemplateBodyDecl {
1037 match self.peek().and_then(|t| t.keyword()) {
1038 Some("signatory") => {
1039 self.bump();
1040 let parties = self.expr_comma_list();
1041 self.skip_to_item_end();
1042 TemplateBodyDecl::Signatory {
1043 parties,
1044 pos,
1045 span: self.node_span(start),
1046 }
1047 }
1048 Some("observer") => {
1049 self.bump();
1050 let parties = self.expr_comma_list();
1051 self.skip_to_item_end();
1052 TemplateBodyDecl::Observer {
1053 parties,
1054 pos,
1055 span: self.node_span(start),
1056 }
1057 }
1058 Some("ensure") => {
1059 self.bump();
1060 let expr = self.expr();
1061 self.skip_to_item_end();
1062 TemplateBodyDecl::Ensure {
1063 expr,
1064 pos,
1065 span: self.node_span(start),
1066 }
1067 }
1068 Some("key") => {
1069 self.bump();
1070 let expr_start = self.i;
1071 let expr = self.expr();
1072 let ty = if self.eat_op(":") {
1073 let ty_start = self.i;
1074 self.skip_to_item_end();
1075 self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Key)
1076 } else {
1077 let mut depth = 0i32;
1080 let mut colon = None;
1081 for j in expr_start..self.i {
1082 match &self.toks[j].kind {
1083 TokenKind::LParen | TokenKind::LBracket => depth += 1,
1084 TokenKind::RParen | TokenKind::RBracket if depth > 0 => depth -= 1,
1085 TokenKind::Op(o) if o.as_str() == ":" && depth == 0 => colon = Some(j),
1086 _ => {}
1087 }
1088 }
1089 let ty = colon.map_or(TypeAnnotation::Absent, |j| {
1090 self.parse_type_annotation(j + 1, self.i, TypeAnnotationContext::Key)
1091 });
1092 self.skip_to_item_end();
1093 ty
1094 };
1095 TemplateBodyDecl::Key {
1096 expr,
1097 ty,
1098 pos,
1099 span: self.node_span(start),
1100 }
1101 }
1102 Some("maintainer") => {
1103 self.bump();
1104 let expr = self.expr();
1105 self.skip_to_item_end();
1106 TemplateBodyDecl::Maintainer {
1107 expr,
1108 pos,
1109 span: self.node_span(start),
1110 }
1111 }
1112 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1113 self.choice_decl().map_or_else(
1114 || {
1115 self.skip_to_item_end();
1116 TemplateBodyDecl::Other {
1117 raw: self.slice_text(start),
1118 span: self.node_span(start),
1119 pos,
1120 }
1121 },
1122 TemplateBodyDecl::Choice,
1123 )
1124 }
1125 Some("interface") => self.interface_instance_decl().map_or_else(
1126 || {
1127 self.skip_to_item_end();
1128 TemplateBodyDecl::Other {
1129 raw: self.slice_text(start),
1130 span: self.node_span(start),
1131 pos,
1132 }
1133 },
1134 TemplateBodyDecl::InterfaceInstance,
1135 ),
1136 Some("controller") => {
1137 self.diag_kind(
1141 ParseDiagnosticKind::UnsupportedSyntax(
1142 UnsupportedSyntaxKind::LegacyControllerCan,
1143 ),
1144 "legacy 'controller ... can' syntax is not supported; \
1145 choices inside this block are not analyzed",
1146 );
1147 self.skip_to_item_end();
1148 TemplateBodyDecl::Other {
1149 raw: self.slice_text(start),
1150 span: self.node_span(start),
1151 pos,
1152 }
1153 }
1154 _ => {
1155 self.skip_to_item_end();
1156 TemplateBodyDecl::Other {
1157 raw: self.slice_text(start),
1158 span: self.node_span(start),
1159 pos,
1160 }
1161 }
1162 }
1163 }
1164
1165 fn choice_decl(&mut self) -> Option<ChoiceDecl> {
1166 let pos = self.pos();
1167 let start_i = self.i;
1168 let consuming = match self.peek().and_then(|t| t.keyword()) {
1169 Some("nonconsuming") => {
1170 self.bump();
1171 Consuming::NonConsuming
1172 }
1173 Some("preconsuming") => {
1174 self.bump();
1175 Consuming::PreConsuming
1176 }
1177 Some("postconsuming") => {
1178 self.bump();
1179 Consuming::PostConsuming
1180 }
1181 _ => Consuming::Consuming,
1182 };
1183 if !self.eat_keyword("choice") {
1184 return None;
1185 }
1186 let name = self.upper_name()?.to_string().into();
1187 let return_ty = if self.eat_op(":") {
1188 let ty_start = self.i;
1189 self.skip_type_tokens();
1190 self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Choice)
1191 } else {
1192 TypeAnnotation::Absent
1193 };
1194 let (params, dangling) = if self.eat_keyword("with") {
1195 let parsed = self.field_block();
1196 (parsed.fields, parsed.dangling)
1197 } else {
1198 (Vec::new(), false)
1199 };
1200 let mut observers = Vec::new();
1201 let mut controllers = Vec::new();
1202 loop {
1203 if dangling {
1207 while self.eat(&TokenKind::VSemi) {}
1208 }
1209 if self.eat_keyword("observer") {
1210 observers = self.expr_comma_list_no_do();
1211 } else if self.eat_keyword("controller") {
1212 controllers = self.expr_comma_list_no_do();
1213 } else {
1214 break;
1215 }
1216 }
1217 if dangling {
1218 while self.eat(&TokenKind::VSemi) {}
1219 }
1220 let body = if self.peek().is_some_and(|t| {
1221 !matches!(
1222 t,
1223 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace
1224 )
1225 }) {
1226 Some(self.expr())
1227 } else {
1228 None
1229 };
1230 self.skip_to_item_end();
1231 if dangling {
1232 self.eat(&TokenKind::VRBrace);
1235 self.skip_to_item_end();
1236 }
1237 Some(ChoiceDecl {
1238 name,
1239 consuming,
1240 return_ty,
1241 params,
1242 controllers,
1243 observers,
1244 body,
1245 pos,
1246 span: self.node_span(start_i),
1247 })
1248 }
1249
1250 fn skip_type_tokens(&mut self) {
1253 let mut brackets = 0usize;
1254 while let Some(t) = self.peek() {
1255 match t {
1256 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::VLBrace | TokenKind::Semi => {
1257 return
1258 }
1259 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1260 TokenKind::RParen | TokenKind::RBracket => {
1261 if brackets == 0 {
1262 return;
1263 }
1264 brackets -= 1;
1265 }
1266 _ if brackets == 0
1267 && matches!(
1268 t.keyword(),
1269 Some("with" | "controller" | "observer" | "do" | "where")
1270 ) =>
1271 {
1272 return
1273 }
1274 _ => {}
1275 }
1276 self.i += 1;
1277 }
1278 }
1279
1280 fn interface_decl(&mut self) -> Option<InterfaceDecl> {
1283 let pos = self.pos();
1284 let start_i = self.i;
1285 self.bump(); if self.at_keyword("instance") {
1287 return None;
1289 }
1290 let name = self.upper_name()?.to_string().into();
1291 let mut requires = Vec::new();
1292 if self.eat_keyword("requires") {
1293 while let Some(r) = self.upper_name() {
1294 requires.push(r);
1295 if !self.eat(&TokenKind::Comma) {
1296 break;
1297 }
1298 }
1299 }
1300 if !self.eat_keyword("where") {
1301 return None;
1302 }
1303 let mut viewtype = None;
1304 let mut methods = Vec::new();
1305 let mut choices = Vec::new();
1306 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1307 return Some(InterfaceDecl {
1308 name,
1309 requires,
1310 viewtype,
1311 methods,
1312 choices,
1313 pos,
1314 span: self.node_span(start_i),
1315 });
1316 }
1317 loop {
1318 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1319 match self.peek() {
1320 None => break,
1321 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1322 self.bump();
1323 break;
1324 }
1325 Some(TokenKind::RParen | TokenKind::RBracket) => {
1330 self.bump();
1331 continue;
1332 }
1333 _ => {}
1334 }
1335 match self.peek().and_then(|t| t.keyword()) {
1336 Some("viewtype") => {
1337 self.bump();
1338 viewtype = self.upper_name();
1339 self.skip_to_item_end();
1340 }
1341 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1342 if let Some(c) = self.choice_decl() {
1343 choices.push(c);
1344 } else {
1345 self.skip_to_item_end();
1346 }
1347 }
1348 _ => {
1349 let mpos = self.pos();
1352 if let Some(TokenKind::LowerId {
1353 qualifier: None,
1354 name: mname,
1355 }) = self.peek().cloned()
1356 {
1357 if self.peek_at(1).is_some_and(|t| t.is_op(":")) {
1358 let mstart = self.toks[self.i].start;
1359 self.bump();
1360 self.bump();
1361 let ty_start = self.i;
1362 self.skip_to_item_end();
1363 methods.push(FieldDecl {
1365 name: mname,
1366 ty: self.parse_type_annotation(
1367 ty_start,
1368 self.i,
1369 TypeAnnotationContext::InterfaceMethod,
1370 ),
1371 pos: mpos,
1372 span: Span::from_usize(mstart, self.end_byte().max(mstart)),
1373 });
1374 continue;
1375 }
1376 }
1377 self.skip_to_item_end();
1378 }
1379 }
1380 }
1381 Some(InterfaceDecl {
1382 name,
1383 requires,
1384 viewtype,
1385 methods,
1386 choices,
1387 pos,
1388 span: self.node_span(start_i),
1389 })
1390 }
1391
1392 fn interface_instance_decl(&mut self) -> Option<InterfaceInstanceDecl> {
1394 let pos = self.pos();
1395 let start_i = self.i;
1396 self.bump(); if !self.eat_keyword("instance") {
1398 return None;
1399 }
1400 let interface_name = self.upper_name()?;
1401 let for_template = if self.eat_keyword("for") {
1402 self.upper_name().map_or_else(
1403 || {
1404 self.diag_expected(
1405 ExpectedToken::TemplateNameAfterInterfaceInstanceFor,
1406 "interface instance missing template name after 'for'",
1407 );
1408 None
1409 },
1410 Some,
1411 )
1412 } else {
1413 None
1414 };
1415 let mut methods = Vec::new();
1416 if self.eat_keyword("where")
1417 && (self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace))
1418 {
1419 loop {
1420 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1421 match self.peek() {
1422 None => break,
1423 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1424 self.bump();
1425 break;
1426 }
1427 Some(TokenKind::RParen | TokenKind::RBracket) => {
1429 self.bump();
1430 continue;
1431 }
1432 _ => {}
1433 }
1434 if let Some(b) = self.binding() {
1435 methods.push(b);
1436 } else {
1437 self.skip_to_item_end();
1438 }
1439 }
1440 }
1441 Some(InterfaceInstanceDecl {
1442 interface_name,
1443 for_template,
1444 methods,
1445 pos,
1446 span: self.node_span(start_i),
1447 })
1448 }
1449
1450 fn function_item(&mut self) -> Option<Decl> {
1456 let pos = self.pos();
1457 let start_i = self.i;
1458 let Some(TokenKind::LowerId {
1459 qualifier: None,
1460 name,
1461 }) = self.peek().cloned()
1462 else {
1463 return None;
1464 };
1465
1466 let mut j = self.i + 1;
1468 let mut is_sig = false;
1469 loop {
1470 match self.toks.get(j).map(|t| &t.kind) {
1471 Some(TokenKind::Comma) => {
1472 j += 1;
1473 if matches!(
1474 self.toks.get(j).map(|t| &t.kind),
1475 Some(TokenKind::LowerId {
1476 qualifier: None,
1477 ..
1478 })
1479 ) {
1480 j += 1;
1481 continue;
1482 }
1483 break;
1484 }
1485 Some(TokenKind::Op(o)) if o.as_str() == ":" => {
1486 is_sig = true;
1487 break;
1488 }
1489 _ => break,
1490 }
1491 }
1492 if is_sig {
1493 self.bump(); while self.eat(&TokenKind::Comma) {
1495 self.bump(); }
1497 self.eat_op(":");
1498 let ty_start = self.i;
1499 self.skip_to_item_end();
1500 let ty = self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Function);
1501 return Some(Decl::Function(FunctionDecl {
1502 name,
1503 ty,
1504 equations: Vec::new(),
1505 pos,
1506 sig_span: Some(self.node_span(start_i)),
1507 span: self.node_span(start_i),
1508 }));
1509 }
1510
1511 self.bump(); let mut params = Vec::new();
1514 while !self.at_op("=") && !self.at_op("|") {
1515 if self.at_op(":") {
1518 self.bump();
1519 let mut brackets = 0usize;
1520 while let Some(t) = self.peek() {
1521 match t {
1522 TokenKind::Op(o) if o.as_str() == "=" && brackets == 0 => break,
1523 TokenKind::VSemi
1524 | TokenKind::VRBrace
1525 | TokenKind::Semi
1526 | TokenKind::RBrace => break,
1527 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1528 TokenKind::RParen | TokenKind::RBracket => {
1529 brackets = brackets.saturating_sub(1)
1530 }
1531 _ => {}
1532 }
1533 self.i += 1;
1534 }
1535 continue;
1536 }
1537 if matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o)) {
1540 self.skip_to_item_end();
1541 return None;
1542 }
1543 match self.peek() {
1544 None
1545 | Some(
1546 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace,
1547 ) => {
1548 self.diag_malformed(
1549 MalformedSyntaxKind::FunctionEquation,
1550 format!("could not parse equation for '{name}'"),
1551 );
1552 return None;
1553 }
1554 _ => {}
1555 }
1556 match self.pattern_atom() {
1557 Some(p) => params.push(p),
1558 None => {
1559 self.diag_malformed(
1560 MalformedSyntaxKind::FunctionParameterPattern,
1561 format!("bad parameter pattern in '{name}'"),
1562 );
1563 return None;
1564 }
1565 }
1566 }
1567 let (body, guards) = self.equation_rhs()?;
1568 let where_bindings = if self.eat_keyword("where") {
1569 self.binding_block()
1570 } else {
1571 Vec::new()
1572 };
1573 self.skip_to_item_end();
1574 Some(Decl::Function(FunctionDecl {
1575 name,
1576 ty: TypeAnnotation::Absent,
1577 equations: vec![Equation {
1578 params,
1579 body,
1580 guards,
1581 where_bindings,
1582 pos,
1583 span: self.node_span(start_i),
1584 }],
1585 pos,
1586 sig_span: None,
1587 span: self.node_span(start_i),
1588 }))
1589 }
1590
1591 fn equation_rhs(&mut self) -> Option<(Expr, Vec<(Expr, Expr)>)> {
1593 if self.eat_op("=") {
1594 return Some((self.expr(), Vec::new()));
1595 }
1596 let mut guards = Vec::new();
1597 while self.eat_op("|") {
1598 let g = loop {
1601 let g = self.expr();
1602 if self.eat_op("<-") {
1603 let _ = self.expr(); }
1605 if !self.eat(&TokenKind::Comma) {
1606 break g;
1607 }
1608 };
1609 if !self.eat_op("=") {
1610 self.diag_expected(ExpectedToken::EqualsAfterGuard, "expected '=' after guard");
1611 return None;
1612 }
1613 let e = self.expr();
1614 guards.push((g, e));
1615 }
1616 if guards.is_empty() {
1617 self.diag_expected(
1618 ExpectedToken::EqualsOrGuardedRightHandSide,
1619 "expected '=' or guarded right-hand side in equation",
1620 );
1621 None
1622 } else {
1623 let first = guards[0].1.clone();
1624 Some((first, guards))
1625 }
1626 }
1627
1628 fn binding_block(&mut self) -> Vec<Binding> {
1630 let mut bindings = Vec::new();
1631 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1632 return bindings;
1633 }
1634 loop {
1635 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1636 match self.peek() {
1637 None => break,
1638 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1639 self.bump();
1640 break;
1641 }
1642 Some(TokenKind::RParen | TokenKind::RBracket) => {
1647 self.bump();
1648 continue;
1649 }
1650 _ => {}
1651 }
1652 match self.binding() {
1653 Some(b) => bindings.push(b),
1654 None => self.skip_to_item_end(),
1655 }
1656 }
1657 bindings
1658 }
1659
1660 fn binding(&mut self) -> Option<Binding> {
1663 let pos = self.pos();
1664 let start_i = self.i;
1665 if self.at(&TokenKind::LParen)
1668 && matches!(self.peek_at(1), Some(TokenKind::Op(_)))
1669 && self.peek_at(2) == Some(&TokenKind::RParen)
1670 {
1671 self.skip_to_item_end();
1672 return None;
1673 }
1674 let pat = self.pattern_atom()?;
1675 let mut params = Vec::new();
1676 loop {
1677 if self.at_op("=") {
1678 self.bump();
1679 let expr = self.expr();
1680 if self.eat_keyword("where") {
1682 let _ = self.binding_block();
1683 }
1684 return Some(Binding {
1685 pat,
1686 params,
1687 expr,
1688 pos,
1689 span: self.node_span(start_i),
1690 });
1691 }
1692 if self.at_op("|") {
1693 let (body, _) = self.equation_rhs()?;
1694 if self.eat_keyword("where") {
1695 let _ = self.binding_block();
1696 }
1697 return Some(Binding {
1698 pat,
1699 params,
1700 expr: body,
1701 pos,
1702 span: self.node_span(start_i),
1703 });
1704 }
1705 if self.at_op(":") {
1706 if params.is_empty() {
1707 self.skip_to_item_end();
1709 return None;
1710 }
1711 self.bump();
1714 let mut brackets = 0usize;
1715 while let Some(t) = self.peek() {
1716 match t {
1717 TokenKind::Op(o) if o.as_str() == "=" && brackets == 0 => break,
1718 TokenKind::VSemi
1719 | TokenKind::VRBrace
1720 | TokenKind::Semi
1721 | TokenKind::RBrace => break,
1722 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1723 TokenKind::RParen | TokenKind::RBracket => {
1724 brackets = brackets.saturating_sub(1)
1725 }
1726 _ => {}
1727 }
1728 self.i += 1;
1729 }
1730 continue;
1731 }
1732 if matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o)) {
1735 self.skip_to_item_end();
1736 return None;
1737 }
1738 match self.peek() {
1739 None
1740 | Some(
1741 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace,
1742 ) => return None,
1743 _ => {}
1744 }
1745 params.push(self.pattern_atom()?);
1746 }
1747 }
1748
1749 fn pattern_atom(&mut self) -> Option<Pat> {
1752 if self.depth >= MAX_RECURSION_DEPTH {
1753 return None;
1754 }
1755 self.depth += 1;
1756 let result = self.pattern_atom_inner();
1757 self.depth -= 1;
1758 result
1759 }
1760
1761 fn pattern_atom_inner(&mut self) -> Option<Pat> {
1762 let pos = self.pos();
1763 let start_i = self.i;
1764 if self.at_op("~") || self.at_op("!") {
1766 self.bump();
1767 return self.pattern_atom();
1768 }
1769 match self.peek().cloned() {
1770 Some(TokenKind::LowerId {
1771 qualifier: None,
1772 name,
1773 }) => {
1774 self.bump();
1775 if name == "_" {
1776 return Some(Pat::Wild {
1777 pos,
1778 span: self.node_span(start_i),
1779 });
1780 }
1781 if self.at_op("@") {
1782 self.bump();
1783 let inner = self.pattern_atom()?;
1784 return Some(Pat::As {
1785 name,
1786 pat: Box::new(inner),
1787 pos,
1788 span: self.node_span(start_i),
1789 });
1790 }
1791 Some(Pat::Var {
1792 name,
1793 pos,
1794 span: self.node_span(start_i),
1795 })
1796 }
1797 Some(TokenKind::Op(o)) if o.as_str() == "_" => {
1798 self.bump();
1799 Some(Pat::Wild {
1800 pos,
1801 span: self.node_span(start_i),
1802 })
1803 }
1804 Some(TokenKind::UpperId { qualifier, name }) => {
1805 self.bump();
1806 if self.at(&TokenKind::LBrace) {
1809 self.skip_balanced_braces();
1810 } else if self.eat_keyword("with") {
1811 let _ = self.record_fields();
1812 }
1813 Some(Pat::Con {
1814 qualifier,
1815 name,
1816 args: Vec::new(),
1817 pos,
1818 span: self.node_span(start_i),
1819 })
1820 }
1821 Some(TokenKind::IntLit(text)) => {
1822 self.bump();
1823 Some(Pat::Lit {
1824 kind: LitKind::Int,
1825 text,
1826 pos,
1827 span: self.node_span(start_i),
1828 })
1829 }
1830 Some(TokenKind::DecimalLit(text)) => {
1831 self.bump();
1832 Some(Pat::Lit {
1833 kind: LitKind::Decimal,
1834 text,
1835 pos,
1836 span: self.node_span(start_i),
1837 })
1838 }
1839 Some(TokenKind::StringLit(text)) => {
1840 self.bump();
1841 Some(Pat::Lit {
1842 kind: LitKind::Text,
1843 text,
1844 pos,
1845 span: self.node_span(start_i),
1846 })
1847 }
1848 Some(TokenKind::CharLit(text)) => {
1849 self.bump();
1850 Some(Pat::Lit {
1851 kind: LitKind::Char,
1852 text,
1853 pos,
1854 span: self.node_span(start_i),
1855 })
1856 }
1857 Some(TokenKind::LParen) => {
1858 self.bump();
1859 if self.eat(&TokenKind::RParen) {
1860 return Some(Pat::Con {
1861 qualifier: None,
1862 name: "()".into(),
1863 args: Vec::new(),
1864 pos,
1865 span: self.node_span(start_i),
1866 });
1867 }
1868 {
1874 let mut depth = 0usize;
1875 let mut j = self.i;
1876 let mut arrow = None;
1877 while let Some(t) = self.toks.get(j).map(|t| &t.kind) {
1878 match t {
1879 TokenKind::LParen | TokenKind::LBracket => depth += 1,
1880 TokenKind::RParen | TokenKind::RBracket => {
1881 if depth == 0 {
1882 break;
1883 }
1884 depth -= 1;
1885 }
1886 TokenKind::Op(o) if o.as_str() == ":" && depth == 0 => break,
1887 TokenKind::Op(o) if o.as_str() == "->" && depth == 0 => {
1888 arrow = Some(j);
1889 break;
1890 }
1891 TokenKind::VSemi | TokenKind::VRBrace => break,
1892 TokenKind::Op(o) if o.as_str() == "\\" => break,
1894 _ => {}
1895 }
1896 j += 1;
1897 }
1898 if let Some(j) = arrow {
1899 self.i = j + 1; let inner = self.pattern()?;
1901 self.eat(&TokenKind::RParen);
1902 return Some(inner);
1903 }
1904 }
1905 let first = self.pattern()?;
1906 if self.at_op(":") {
1908 let mut depth = 0usize;
1909 while let Some(t) = self.peek() {
1910 match t {
1911 TokenKind::LParen | TokenKind::LBracket => depth += 1,
1912 TokenKind::RParen if depth == 0 => break,
1913 TokenKind::RParen | TokenKind::RBracket => {
1914 depth = depth.saturating_sub(1)
1915 }
1916 TokenKind::VSemi | TokenKind::VRBrace => break,
1917 _ => {}
1918 }
1919 self.i += 1;
1920 }
1921 }
1922 if self.at(&TokenKind::Comma) {
1923 let mut items = vec![first];
1924 while self.eat(&TokenKind::Comma) {
1925 items.push(self.pattern()?);
1926 }
1927 self.eat(&TokenKind::RParen);
1928 return Some(Pat::Tuple {
1929 items,
1930 pos,
1931 span: self.node_span(start_i),
1932 });
1933 }
1934 self.eat(&TokenKind::RParen);
1935 Some(first)
1936 }
1937 Some(TokenKind::LBracket) => {
1938 self.bump();
1939 let mut items = Vec::new();
1940 if !self.eat(&TokenKind::RBracket) {
1941 loop {
1942 items.push(self.pattern()?);
1943 if !self.eat(&TokenKind::Comma) {
1944 break;
1945 }
1946 }
1947 self.eat(&TokenKind::RBracket);
1948 }
1949 Some(Pat::List {
1950 items,
1951 pos,
1952 span: self.node_span(start_i),
1953 })
1954 }
1955 _ => None,
1956 }
1957 }
1958
1959 fn pattern(&mut self) -> Option<Pat> {
1961 if self.depth >= MAX_RECURSION_DEPTH {
1962 return None;
1963 }
1964 self.depth += 1;
1965 let result = self.pattern_inner();
1966 self.depth -= 1;
1967 result
1968 }
1969
1970 fn pattern_inner(&mut self) -> Option<Pat> {
1971 let pos = self.pos();
1972 let start_i = self.i;
1973 let first = match self.peek().cloned() {
1974 Some(TokenKind::UpperId { qualifier, name }) => {
1975 self.bump();
1976 if self.at(&TokenKind::LBrace) || self.at_keyword("with") {
1977 if self.eat_keyword("with") {
1978 let _ = self.record_fields();
1979 } else {
1980 self.skip_balanced_braces();
1981 }
1982 Pat::Con {
1983 qualifier,
1984 name,
1985 args: Vec::new(),
1986 pos,
1987 span: self.node_span(start_i),
1988 }
1989 } else {
1990 let mut args = Vec::new();
1991 while let Some(a) = self.try_pattern_atom() {
1992 args.push(a);
1993 }
1994 Pat::Con {
1995 qualifier,
1996 name,
1997 args,
1998 pos,
1999 span: self.node_span(start_i),
2000 }
2001 }
2002 }
2003 _ => self.pattern_atom()?,
2004 };
2005 if self.at_op("::") {
2006 self.bump();
2007 let rest = self.pattern()?;
2008 return Some(Pat::Con {
2009 qualifier: None,
2010 name: "::".into(),
2011 args: vec![first, rest],
2012 pos,
2013 span: self.node_span(start_i),
2014 });
2015 }
2016 Some(first)
2017 }
2018
2019 fn try_pattern_atom(&mut self) -> Option<Pat> {
2020 match self.peek() {
2021 Some(
2022 TokenKind::LowerId {
2023 qualifier: None, ..
2024 }
2025 | TokenKind::UpperId { .. }
2026 | TokenKind::IntLit(_)
2027 | TokenKind::DecimalLit(_)
2028 | TokenKind::StringLit(_)
2029 | TokenKind::CharLit(_)
2030 | TokenKind::LParen
2031 | TokenKind::LBracket,
2032 ) => self.pattern_atom(),
2033 _ => None,
2034 }
2035 }
2036
2037 fn skip_balanced_braces(&mut self) {
2038 let mut depth = 0usize;
2039 while let Some(t) = self.peek() {
2040 match t {
2041 TokenKind::LBrace => depth += 1,
2042 TokenKind::RBrace => {
2043 if depth == 0 {
2044 return;
2045 }
2046 depth -= 1;
2047 if depth == 0 {
2048 self.i += 1;
2049 return;
2050 }
2051 }
2052 _ => {}
2053 }
2054 self.i += 1;
2055 }
2056 }
2057
2058 fn expr(&mut self) -> Expr {
2061 self.expr_prec(0, DoExpressionMode::Allow)
2062 }
2063
2064 fn expr_no_do(&mut self) -> Expr {
2065 self.expr_prec(0, DoExpressionMode::Disallow)
2066 }
2067
2068 fn expr_comma_list(&mut self) -> Vec<Expr> {
2070 let mut out = vec![self.expr()];
2071 while self.eat(&TokenKind::Comma) {
2072 out.push(self.expr());
2073 }
2074 out
2075 }
2076
2077 fn expr_comma_list_no_do(&mut self) -> Vec<Expr> {
2078 let mut out = vec![self.expr_no_do()];
2079 while self.eat(&TokenKind::Comma) {
2080 out.push(self.expr_no_do());
2081 }
2082 out
2083 }
2084
2085 fn expr_prec(&mut self, min_prec: u8, do_mode: DoExpressionMode) -> Expr {
2086 let pos = self.pos();
2087 let start_i = self.i;
2088 if self.depth >= MAX_RECURSION_DEPTH {
2089 self.diag_kind(
2094 ParseDiagnosticKind::RecursionLimit {
2095 limit: MAX_RECURSION_DEPTH,
2096 },
2097 "expression nesting too deep; truncated to raw text",
2098 );
2099 let start = self.i;
2100 self.skip_to_item_end();
2101 if self.i == start {
2102 self.bump();
2103 }
2104 return Expr::Error {
2105 raw: self.slice_text(start),
2106 span: self.node_span(start),
2107 pos,
2108 };
2109 }
2110 self.depth += 1;
2111 let result = self.expr_prec_inner(min_prec, do_mode, pos, start_i);
2112 self.depth -= 1;
2113 result
2114 }
2115
2116 fn expr_prec_inner(
2117 &mut self,
2118 min_prec: u8,
2119 do_mode: DoExpressionMode,
2120 pos: Pos,
2121 start_i: usize,
2122 ) -> Expr {
2123 let Some(mut lhs) = self.unary(do_mode) else {
2124 let start = self.i;
2126 self.skip_to_item_end();
2127 if self.i == start {
2128 self.bump();
2129 }
2130 return Expr::Error {
2131 raw: self.slice_text(start),
2132 span: self.node_span(start),
2133 pos,
2134 };
2135 };
2136 loop {
2137 let (op, prec, right_assoc) = match self.peek() {
2138 Some(TokenKind::Op(o)) => {
2139 let o = o.clone();
2140 if is_reserved_op(&o) {
2141 if o == ":" {
2143 self.bump();
2144 self.skip_type_tokens();
2145 continue;
2146 }
2147 break;
2148 }
2149 let (p, r) = fixity(&o);
2150 (o, p, r)
2151 }
2152 Some(TokenKind::Backtick) => {
2153 let name = match self.peek_at(1) {
2155 Some(
2156 TokenKind::LowerId { qualifier, name }
2157 | TokenKind::UpperId { qualifier, name },
2158 ) => qualifier
2159 .as_ref()
2160 .map_or_else(|| name.to_string(), |q| format!("{q}.{name}")),
2161 _ => break,
2162 };
2163 if self.peek_at(2) != Some(&TokenKind::Backtick) {
2164 break;
2165 }
2166 (format!("`{name}`").into(), 9, false)
2167 }
2168 _ => break,
2169 };
2170 if prec < min_prec {
2171 break;
2172 }
2173 self.bump();
2174 if op.starts_with('`') {
2175 self.bump();
2176 self.bump();
2177 }
2178 let next_min = if right_assoc { prec } else { prec + 1 };
2179 let rhs = self.expr_prec(next_min, do_mode);
2180 lhs = Expr::BinOp {
2181 op,
2182 lhs: Box::new(lhs),
2183 rhs: Box::new(rhs),
2184 pos,
2185 span: self.node_span(start_i),
2186 };
2187 }
2188 lhs
2189 }
2190
2191 fn unary(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2192 let pos = self.pos();
2193 let start_i = self.i;
2194 if self.at_op("-") {
2195 self.bump();
2196 let e = self.unary(do_mode)?;
2197 return Some(Expr::Neg {
2198 expr: Box::new(e),
2199 pos,
2200 span: self.node_span(start_i),
2201 });
2202 }
2203 self.application(do_mode)
2204 }
2205
2206 fn application(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2207 let pos = self.pos();
2208 let start_i = self.i;
2209 let head0 = self.atom(do_mode)?;
2210 let mut head = self.projection_tail(head0);
2211 let mut args = Vec::new();
2212 loop {
2213 if self.at_keyword("with") {
2216 let target = args.pop().unwrap_or_else(|| {
2217 std::mem::replace(
2218 &mut head,
2219 Expr::Error {
2220 raw: String::new(),
2221 pos,
2222 span: Span::default(),
2223 },
2224 )
2225 });
2226 self.bump(); let fields = self.record_fields();
2228 let tpos = target.pos();
2229 let sp = Span::from_usize(target.span().start_usize(), self.end_byte());
2230 let rec = Expr::Record {
2231 base: Box::new(target),
2232 fields,
2233 pos: tpos,
2234 span: sp,
2235 };
2236 if matches!(head, Expr::Error { ref raw, .. } if raw.is_empty()) {
2237 head = rec;
2238 } else {
2239 args.push(rec);
2240 }
2241 continue;
2242 }
2243 if !do_mode.allows_do() && self.at_keyword("do") {
2244 break;
2245 }
2246 if self.at_op("@") {
2248 self.bump();
2249 match self.peek() {
2250 Some(TokenKind::UpperId { .. } | TokenKind::LowerId { .. }) => {
2251 self.bump();
2252 }
2253 Some(TokenKind::LParen) => self.skip_balanced_parens(),
2254 Some(TokenKind::LBracket) => {
2255 let mut depth = 0usize;
2256 while let Some(t) = self.peek() {
2257 match t {
2258 TokenKind::LBracket => depth += 1,
2259 TokenKind::RBracket => {
2260 if depth == 0 {
2261 break;
2262 }
2263 depth -= 1;
2264 if depth == 0 {
2265 self.i += 1;
2266 break;
2267 }
2268 }
2269 _ => {}
2270 }
2271 self.i += 1;
2272 }
2273 }
2274 _ => {}
2275 }
2276 continue;
2277 }
2278 match self.try_atom(do_mode) {
2279 Some(a) => args.push(self.projection_tail(a)),
2280 None => break,
2281 }
2282 }
2283 if args.is_empty() {
2284 Some(head)
2285 } else {
2286 Some(Expr::App {
2287 func: Box::new(head),
2288 args,
2289 pos,
2290 span: self.node_span(start_i),
2291 })
2292 }
2293 }
2294
2295 fn record_fields(&mut self) -> Vec<FieldAssign> {
2297 let mut fields = Vec::new();
2298 let explicit = self.at(&TokenKind::LBrace);
2299 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
2300 return fields;
2301 }
2302 loop {
2303 while self.eat(&TokenKind::VSemi)
2304 || self.eat(&TokenKind::Semi)
2305 || self.eat(&TokenKind::Comma)
2306 {}
2307 match self.peek() {
2308 None => break,
2309 Some(TokenKind::VRBrace) if !explicit => {
2310 self.bump();
2311 break;
2312 }
2313 Some(TokenKind::RBrace) => {
2314 self.bump();
2315 break;
2316 }
2317 Some(TokenKind::RParen | TokenKind::RBracket) => {
2319 self.bump();
2320 continue;
2321 }
2322 _ => {}
2323 }
2324 let pos = self.pos();
2325 let start_i = self.i;
2326 if self.at_op("..") {
2327 self.bump();
2328 fields.push(FieldAssign::Wildcard {
2329 pos,
2330 span: self.node_span(start_i),
2331 });
2332 continue;
2333 }
2334 let name = match self.peek().cloned() {
2335 Some(TokenKind::LowerId {
2336 qualifier: None,
2337 name,
2338 }) => {
2339 self.bump();
2340 name
2341 }
2342 _ => {
2343 self.skip_to_item_end();
2344 continue;
2345 }
2346 };
2347 if self.eat_op("=") {
2348 let value = self.expr_prec(1, DoExpressionMode::Allow);
2349 fields.push(FieldAssign::Assign {
2350 name,
2351 value,
2352 pos,
2353 span: self.node_span(start_i),
2354 });
2355 } else {
2356 fields.push(FieldAssign::Pun {
2358 name,
2359 pos,
2360 span: self.node_span(start_i),
2361 });
2362 }
2363 }
2364 fields
2365 }
2366
2367 fn try_atom(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2368 match self.peek() {
2369 Some(TokenKind::LowerId { .. }) => {
2370 let kw = self.peek().and_then(|t| t.keyword());
2371 match kw {
2372 Some("do") if do_mode.allows_do() => self.atom(do_mode),
2374 Some(
2377 "if" | "case" | "do" | "let" | "try" | "where" | "then" | "else" | "of"
2378 | "in" | "controller" | "with" | "catch",
2379 ) => None,
2380 _ => self.atom(do_mode),
2381 }
2382 }
2383 Some(
2384 TokenKind::UpperId { .. }
2385 | TokenKind::IntLit(_)
2386 | TokenKind::DecimalLit(_)
2387 | TokenKind::StringLit(_)
2388 | TokenKind::CharLit(_)
2389 | TokenKind::LParen
2390 | TokenKind::LBracket,
2391 ) => self.atom(do_mode),
2392 Some(TokenKind::Op(o)) if o.as_str() == "\\" => self.atom(do_mode),
2394 _ => None,
2395 }
2396 }
2397
2398 fn projection_tail(&mut self, mut base: Expr) -> Expr {
2405 while self.at_tight_projection() {
2406 let start = base.span().start_usize();
2407 let pos = base.pos();
2408 self.bump(); let Some(field_tok) = self.bump() else {
2410 self.diag_expected(
2411 ExpectedToken::ProjectionFieldAfterDot,
2412 "expected projection field after '.'",
2413 );
2414 return base;
2415 };
2416 let TokenKind::LowerId { qualifier, name } = field_tok.kind else {
2417 self.diag_expected(
2418 ExpectedToken::ProjectionFieldAfterDot,
2419 "expected projection field after '.'",
2420 );
2421 return base;
2422 };
2423 let field = Expr::Var {
2424 qualifier,
2425 name,
2426 pos: field_tok.pos,
2427 span: Span::from_usize(field_tok.start, field_tok.end),
2428 };
2429 base = Expr::BinOp {
2430 op: ".".into(),
2431 lhs: Box::new(base),
2432 rhs: Box::new(field),
2433 pos,
2434 span: Span::from_usize(start, self.end_byte()),
2435 };
2436 }
2437 base
2438 }
2439
2440 fn at_tight_projection(&self) -> bool {
2444 if self.i == 0 {
2445 return false;
2446 }
2447 let Some(dot) = self.toks.get(self.i) else {
2448 return false;
2449 };
2450 if !matches!(&dot.kind, TokenKind::Op(o) if o.as_str() == ".") {
2451 return false;
2452 }
2453 let prev = &self.toks[self.i - 1];
2457 if prev.is_virtual() || prev.end != dot.start {
2458 return false;
2459 }
2460 self.toks.get(self.i + 1).is_some_and(|t| {
2462 matches!(
2463 &t.kind,
2464 TokenKind::LowerId {
2465 qualifier: None,
2466 ..
2467 }
2468 ) && t.start == dot.end
2469 })
2470 }
2471
2472 fn atom(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2473 let pos = self.pos();
2474 let start_i = self.i;
2475 match self.peek().cloned() {
2476 Some(TokenKind::LowerId { qualifier, name }) => {
2477 match name.as_str() {
2478 "if" if qualifier.is_none() => return self.if_expr(),
2479 "case" if qualifier.is_none() => return self.case_expr(),
2480 "do" if qualifier.is_none() => {
2481 if !do_mode.allows_do() {
2482 return None;
2483 }
2484 return self.do_expr();
2485 }
2486 "let" if qualifier.is_none() => return self.let_expr(),
2487 "try" if qualifier.is_none() => return self.try_expr(),
2488 _ => {}
2489 }
2490 self.bump();
2491 Some(Expr::Var {
2492 qualifier,
2493 name,
2494 pos,
2495 span: self.node_span(start_i),
2496 })
2497 }
2498 Some(TokenKind::UpperId { qualifier, name }) => {
2499 self.bump();
2500 let base = Expr::Con {
2501 qualifier,
2502 name,
2503 pos,
2504 span: self.node_span(start_i),
2505 };
2506 if self.at(&TokenKind::LBrace) {
2508 let fields = self.record_fields();
2509 return Some(Expr::Record {
2510 base: Box::new(base),
2511 fields,
2512 pos,
2513 span: self.node_span(start_i),
2514 });
2515 }
2516 Some(base)
2517 }
2518 Some(TokenKind::IntLit(text)) => {
2519 self.bump();
2520 Some(Expr::Lit {
2521 kind: LitKind::Int,
2522 text,
2523 pos,
2524 span: self.node_span(start_i),
2525 })
2526 }
2527 Some(TokenKind::DecimalLit(text)) => {
2528 self.bump();
2529 Some(Expr::Lit {
2530 kind: LitKind::Decimal,
2531 text,
2532 pos,
2533 span: self.node_span(start_i),
2534 })
2535 }
2536 Some(TokenKind::StringLit(text)) => {
2537 self.bump();
2538 Some(Expr::Lit {
2539 kind: LitKind::Text,
2540 text,
2541 pos,
2542 span: self.node_span(start_i),
2543 })
2544 }
2545 Some(TokenKind::CharLit(text)) => {
2546 self.bump();
2547 Some(Expr::Lit {
2548 kind: LitKind::Char,
2549 text,
2550 pos,
2551 span: self.node_span(start_i),
2552 })
2553 }
2554 Some(TokenKind::Op(o)) if o.as_str() == "\\" => self.lambda_expr(),
2555 Some(TokenKind::LParen) => self.paren_expr(),
2556 Some(TokenKind::LBracket) => self.list_expr(),
2557 _ => None,
2558 }
2559 }
2560
2561 fn if_expr(&mut self) -> Option<Expr> {
2562 let pos = self.pos();
2563 let start_i = self.i;
2564 self.bump(); let cond = self.expr();
2566 self.eat(&TokenKind::VSemi); if !self.eat_keyword("then") {
2568 self.diag_expected(ExpectedToken::ThenKeyword, "expected 'then'");
2569 return Some(Expr::Error {
2570 raw: format!("if {}", cond.render()),
2571 pos,
2572 span: self.node_span(start_i),
2573 });
2574 }
2575 let then_branch = self.expr();
2576 self.eat(&TokenKind::VSemi);
2577 if !self.eat_keyword("else") {
2578 self.diag_expected(ExpectedToken::ElseKeyword, "expected 'else'");
2579 return Some(Expr::Error {
2580 raw: format!("if {} then {}", cond.render(), then_branch.render()),
2581 pos,
2582 span: self.node_span(start_i),
2583 });
2584 }
2585 let else_branch = self.expr();
2586 Some(Expr::If {
2587 cond: Box::new(cond),
2588 then_branch: Box::new(then_branch),
2589 else_branch: Box::new(else_branch),
2590 pos,
2591 span: self.node_span(start_i),
2592 })
2593 }
2594
2595 fn case_expr(&mut self) -> Option<Expr> {
2596 let pos = self.pos();
2597 let start_i = self.i;
2598 self.bump(); let scrutinee = self.expr_no_do();
2600 if !self.eat_keyword("of") {
2601 self.diag_expected(
2602 ExpectedToken::OfKeywordInCaseExpression,
2603 "expected 'of' in case expression",
2604 );
2605 return Some(Expr::Error {
2606 raw: format!("case {}", scrutinee.render()),
2607 pos,
2608 span: self.node_span(start_i),
2609 });
2610 }
2611 let mut alts = Vec::new();
2612 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2613 loop {
2614 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2615 match self.peek() {
2616 None => break,
2617 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2618 self.bump();
2619 break;
2620 }
2621 Some(TokenKind::RParen | TokenKind::RBracket) => {
2623 self.bump();
2624 continue;
2625 }
2626 _ => {}
2627 }
2628 if self.eat_keyword("where") {
2630 let _ = self.binding_block();
2631 continue;
2632 }
2633 match self.case_alt() {
2634 Some(a) => alts.push(a),
2635 None => self.skip_to_item_end(),
2636 }
2637 }
2638 }
2639 Some(Expr::Case {
2640 scrutinee: Box::new(scrutinee),
2641 alts,
2642 pos,
2643 span: self.node_span(start_i),
2644 })
2645 }
2646
2647 fn case_alt(&mut self) -> Option<Alt> {
2648 let pos = self.pos();
2649 let start_i = self.i;
2650 let pat = self.pattern()?;
2651 if self.at_op("|") {
2652 let mut first: Option<Expr> = None;
2656 while self.eat_op("|") {
2657 loop {
2658 let _guard = self.expr();
2659 if self.eat_op("<-") {
2660 let _ = self.expr();
2661 }
2662 if !self.eat(&TokenKind::Comma) {
2663 break;
2664 }
2665 }
2666 if !self.eat_op("->") {
2667 self.diag_expected(
2668 ExpectedToken::ArrowInGuardedCaseAlternative,
2669 "expected '->' in guarded case alternative",
2670 );
2671 return None;
2672 }
2673 let body = self.expr();
2674 if first.is_none() {
2675 first = Some(body);
2676 }
2677 }
2678 return Some(Alt {
2679 pat,
2680 body: first?,
2681 pos,
2682 span: self.node_span(start_i),
2683 });
2684 }
2685 if !self.eat_op("->") {
2686 self.diag_expected(
2687 ExpectedToken::ArrowInCaseAlternative,
2688 "expected '->' in case alternative",
2689 );
2690 return None;
2691 }
2692 let body = self.expr();
2693 Some(Alt {
2694 pat,
2695 body,
2696 pos,
2697 span: self.node_span(start_i),
2698 })
2699 }
2700
2701 fn do_expr(&mut self) -> Option<Expr> {
2702 let pos = self.pos();
2703 let start_i = self.i;
2704 self.bump(); let mut stmts = Vec::new();
2706 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2707 loop {
2708 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2709 match self.peek() {
2710 None => break,
2711 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2712 self.bump();
2713 break;
2714 }
2715 Some(TokenKind::RParen | TokenKind::RBracket) => {
2717 self.bump();
2718 continue;
2719 }
2720 _ => {}
2721 }
2722 stmts.push(self.do_stmt());
2723 }
2724 }
2725 Some(Expr::Do {
2726 stmts,
2727 pos,
2728 span: self.node_span(start_i),
2729 })
2730 }
2731
2732 fn do_stmt(&mut self) -> DoStmt {
2733 let pos = self.pos();
2734 let start_i = self.i;
2735 if self.at_keyword("let") {
2736 self.bump();
2737 let bindings = self.binding_block();
2738 if self.eat_keyword("in") {
2740 let body = self.expr();
2741 return DoStmt::Expr {
2742 expr: Expr::LetIn {
2743 bindings,
2744 body: Box::new(body),
2745 pos,
2746 span: self.node_span(start_i),
2747 },
2748 pos,
2749 span: self.node_span(start_i),
2750 };
2751 }
2752 return DoStmt::Let {
2753 bindings,
2754 pos,
2755 span: self.node_span(start_i),
2756 };
2757 }
2758 let snapshot = self.i;
2760 if let Some(pat) = self.try_bind_pattern() {
2761 if self.at_op("<-") {
2762 self.bump();
2763 let expr = self.expr();
2764 return DoStmt::Bind {
2765 pat,
2766 expr,
2767 pos,
2768 span: self.node_span(start_i),
2769 };
2770 }
2771 }
2772 self.i = snapshot;
2773 let expr = self.expr();
2774 DoStmt::Expr {
2775 expr,
2776 pos,
2777 span: self.node_span(start_i),
2778 }
2779 }
2780
2781 fn try_bind_pattern(&mut self) -> Option<Pat> {
2784 self.pattern()
2785 }
2786
2787 fn let_expr(&mut self) -> Option<Expr> {
2788 let pos = self.pos();
2789 let start_i = self.i;
2790 self.bump(); let bindings = self.binding_block();
2792 if self.eat_keyword("in") {
2793 let body = self.expr();
2794 return Some(Expr::LetIn {
2795 bindings,
2796 body: Box::new(body),
2797 pos,
2798 span: self.node_span(start_i),
2799 });
2800 }
2801 Some(Expr::LetIn {
2803 bindings,
2804 body: Box::new(Expr::Error {
2805 raw: String::new(),
2806 pos,
2807 span: self.node_span(start_i),
2808 }),
2809 pos,
2810 span: self.node_span(start_i),
2811 })
2812 }
2813
2814 fn try_expr(&mut self) -> Option<Expr> {
2815 let pos = self.pos();
2816 let start_i = self.i;
2817 self.bump(); let body = self.expr();
2819 let mut handlers = Vec::new();
2820 self.eat(&TokenKind::VSemi);
2821 if self.eat_keyword("catch") {
2822 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2823 loop {
2824 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2825 match self.peek() {
2826 None => break,
2827 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2828 self.bump();
2829 break;
2830 }
2831 Some(TokenKind::RParen | TokenKind::RBracket) => {
2833 self.bump();
2834 continue;
2835 }
2836 _ => {}
2837 }
2838 match self.case_alt() {
2839 Some(a) => handlers.push(a),
2840 None => self.skip_to_item_end(),
2841 }
2842 }
2843 } else if let Some(a) = self.case_alt() {
2844 handlers.push(a);
2846 }
2847 }
2848 Some(Expr::Try {
2849 body: Box::new(body),
2850 handlers,
2851 pos,
2852 span: self.node_span(start_i),
2853 })
2854 }
2855
2856 fn lambda_expr(&mut self) -> Option<Expr> {
2857 let pos = self.pos();
2858 let start_i = self.i;
2859 self.bump(); if self.eat_keyword("case") {
2862 let mut alts = Vec::new();
2863 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2864 loop {
2865 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2866 match self.peek() {
2867 None => break,
2868 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2869 self.bump();
2870 break;
2871 }
2872 Some(TokenKind::RParen | TokenKind::RBracket) => {
2873 self.bump();
2874 continue;
2875 }
2876 _ => {}
2877 }
2878 match self.case_alt() {
2879 Some(a) => alts.push(a),
2880 None => self.skip_to_item_end(),
2881 }
2882 }
2883 }
2884 return Some(Expr::Lambda {
2885 params: vec![Pat::Var {
2886 name: "_".into(),
2887 pos,
2888 span: Span::from_usize(self.byte_at(start_i), self.byte_at(start_i)),
2889 }],
2890 body: Box::new(Expr::Case {
2891 scrutinee: Box::new(Expr::Var {
2892 qualifier: None,
2893 name: "_".into(),
2894 pos,
2895 span: Span::from_usize(self.byte_at(start_i), self.byte_at(start_i)),
2896 }),
2897 alts,
2898 pos,
2899 span: self.node_span(start_i),
2900 }),
2901 pos,
2902 span: self.node_span(start_i),
2903 });
2904 }
2905 let mut params = Vec::new();
2906 while !self.at_op("->") {
2907 match self.pattern_atom() {
2908 Some(p) => params.push(p),
2909 None => {
2910 self.diag_malformed(
2911 MalformedSyntaxKind::LambdaParameter,
2912 "bad lambda parameter",
2913 );
2914 let start = self.i;
2915 self.skip_to_item_end();
2916 return Some(Expr::Error {
2917 raw: format!("\\{}", self.slice_text(start)),
2918 pos,
2919 span: self.node_span(start_i),
2920 });
2921 }
2922 }
2923 }
2924 self.bump(); let body = self.expr();
2926 Some(Expr::Lambda {
2927 params,
2928 body: Box::new(body),
2929 pos,
2930 span: self.node_span(start_i),
2931 })
2932 }
2933
2934 fn paren_expr(&mut self) -> Option<Expr> {
2935 let pos = self.pos();
2936 let start_i = self.i;
2937 self.bump(); if self.eat(&TokenKind::RParen) {
2939 return Some(Expr::Con {
2940 qualifier: None,
2941 name: "()".into(),
2942 pos,
2943 span: self.node_span(start_i),
2944 });
2945 }
2946 if let Some(TokenKind::Op(o)) = self.peek().cloned() {
2948 if !is_reserved_op(&o) && o != "\\" && o != "-" {
2949 self.bump();
2950 if self.eat(&TokenKind::RParen) {
2951 return Some(Expr::OperatorRef {
2952 op: o,
2953 pos,
2954 span: self.node_span(start_i),
2955 });
2956 }
2957 let operand = self.expr();
2958 self.eat(&TokenKind::RParen);
2959 return Some(Expr::RightSection {
2960 op: o,
2961 operand: Box::new(operand),
2962 pos,
2963 span: self.node_span(start_i),
2964 });
2965 }
2966 }
2967 let first = self.expr();
2968 if self.at(&TokenKind::Comma) {
2969 let mut items = vec![first];
2970 while self.eat(&TokenKind::Comma) {
2971 items.push(self.expr());
2972 }
2973 self.eat(&TokenKind::RParen);
2974 return Some(Expr::Tuple {
2975 items,
2976 pos,
2977 span: self.node_span(start_i),
2978 });
2979 }
2980 if let Some(TokenKind::Op(o)) = self.peek().cloned() {
2982 if !is_reserved_op(&o) && self.peek_at(1) == Some(&TokenKind::RParen) {
2983 self.bump();
2984 self.bump();
2985 return Some(Expr::LeftSection {
2986 op: o,
2987 operand: Box::new(first),
2988 pos,
2989 span: self.node_span(start_i),
2990 });
2991 }
2992 }
2993 self.eat(&TokenKind::RParen);
2994 Some(first)
2995 }
2996
2997 fn list_expr(&mut self) -> Option<Expr> {
2998 let pos = self.pos();
2999 let start_i = self.i;
3000 self.bump(); let mut items = Vec::new();
3002 if self.eat(&TokenKind::RBracket) {
3003 return Some(Expr::List {
3004 items,
3005 pos,
3006 span: self.node_span(start_i),
3007 });
3008 }
3009 loop {
3010 let e = self.expr();
3011 if self.at_op("..") {
3013 self.bump();
3014 let hi = if self.at(&TokenKind::RBracket) {
3015 Expr::Error {
3016 raw: String::new(),
3017 pos,
3018 span: self.node_span(start_i),
3019 }
3020 } else {
3021 self.expr()
3022 };
3023 self.eat(&TokenKind::RBracket);
3024 return Some(Expr::BinOp {
3025 op: "..".into(),
3026 lhs: Box::new(e),
3027 rhs: Box::new(hi),
3028 pos,
3029 span: self.node_span(start_i),
3030 });
3031 }
3032 if self.at_op("|") {
3034 let start = self.i;
3035 let mut brackets = 1usize;
3036 while let Some(t) = self.peek() {
3037 match t {
3038 TokenKind::LBracket => brackets += 1,
3039 TokenKind::RBracket => {
3040 brackets -= 1;
3041 if brackets == 0 {
3042 break;
3043 }
3044 }
3045 TokenKind::VSemi | TokenKind::VRBrace => break,
3046 _ => {}
3047 }
3048 self.i += 1;
3049 }
3050 let raw = self.slice_text(start);
3051 self.eat(&TokenKind::RBracket);
3052 return Some(Expr::App {
3053 func: Box::new(e),
3054 args: vec![Expr::Error {
3055 raw,
3056 pos,
3057 span: self.node_span(start_i),
3058 }],
3059 pos,
3060 span: self.node_span(start_i),
3061 });
3062 }
3063 items.push(e);
3064 if !self.eat(&TokenKind::Comma) {
3065 break;
3066 }
3067 }
3068 self.eat(&TokenKind::RBracket);
3069 Some(Expr::List {
3070 items,
3071 pos,
3072 span: self.node_span(start_i),
3073 })
3074 }
3075}
3076
3077fn is_reserved_op(op: &str) -> bool {
3080 matches!(op, "=" | "<-" | "->" | "|" | ":" | "=>" | "@" | "\\" | "..")
3081}
3082
3083fn fixity(op: &str) -> (u8, bool) {
3086 match op {
3087 "$" | "$!" => (1, true),
3088 ">>=" | ">>" | "=<<" | "<&>" => (2, false),
3089 "||" => (3, true),
3090 "&&" => (4, true),
3091 "==" | "/=" | "<" | "<=" | ">" | ">=" => (5, false),
3092 "::" | "++" | "<>" => (6, true),
3093 "+" | "-" => (7, false),
3094 "*" | "/" => (8, false),
3095 "^" | "**" => (9, true),
3096 "." | "!!" => (10, true),
3097 _ => (9, false),
3098 }
3099}
3100
3101fn equations_extent(eqs: &[Equation]) -> Option<Span> {
3106 let mut it = eqs.iter();
3107 let first = it.next()?;
3108 let mut s = first.span;
3109 for e in it {
3110 s.start = s.start.min(e.span.start);
3111 s.end = s.end.max(e.span.end);
3112 }
3113 Some(s)
3114}
3115
3116fn merge_functions(decls: &mut Vec<Decl>) {
3117 let mut out: Vec<Decl> = Vec::with_capacity(decls.len());
3118 let mut function_index_by_name: HashMap<Identifier, usize> = HashMap::new();
3119 for decl in decls.drain(..) {
3120 match decl {
3121 Decl::Function(f) => {
3122 if let Some(existing_index) = function_index_by_name.get(&f.name).copied() {
3123 let Decl::Function(g) = &mut out[existing_index] else {
3124 out.push(Decl::Function(f));
3125 continue;
3126 };
3127 if g.ty.is_absent() {
3128 g.ty = f.ty.clone();
3129 }
3130 if g.sig_span.is_none() {
3131 g.sig_span = f.sig_span;
3132 }
3133 if g.equations.is_empty() && !f.equations.is_empty() {
3136 g.pos = f.pos;
3137 }
3138 g.equations.extend(f.equations);
3139 g.span = equations_extent(&g.equations)
3146 .or(g.sig_span)
3147 .unwrap_or(g.span);
3148 } else {
3149 function_index_by_name.insert(f.name.clone(), out.len());
3150 out.push(Decl::Function(f));
3151 }
3152 }
3153 other => out.push(other),
3154 }
3155 }
3156 *decls = out;
3157}
3158
3159pub(crate) fn parse_type_from_tokens(tokens: &[Token]) -> Option<Type> {
3168 let real_tokens: Vec<&Token> = tokens.iter().filter(|t| !t.is_virtual()).collect();
3171 if real_tokens.is_empty() {
3172 return None;
3173 }
3174 let mut parser = TypeTokenParser {
3175 tokens: &real_tokens,
3176 cursor: 0,
3177 };
3178 let ty = parser.parse_type()?;
3179 if parser.cursor == real_tokens.len() {
3182 Some(ty)
3183 } else {
3184 None
3185 }
3186}
3187
3188struct TypeTokenParser<'a> {
3189 tokens: &'a [&'a Token],
3190 cursor: usize,
3191}
3192
3193#[derive(Debug)]
3194struct FieldBlock {
3195 fields: Vec<FieldDecl>,
3196 dangling: bool,
3197}
3198
3199enum TypeAtom {
3202 ParsedType(Type),
3203 DroppedLiteral(Span),
3204}
3205
3206impl<'a> TypeTokenParser<'a> {
3207 fn peek(&self) -> Option<&'a Token> {
3208 self.tokens.get(self.cursor).copied()
3209 }
3210
3211 fn eat_op(&mut self, op: &str) -> bool {
3212 if self.peek().is_some_and(|t| t.kind.is_op(op)) {
3213 self.cursor += 1;
3214 true
3215 } else {
3216 false
3217 }
3218 }
3219
3220 fn parse_type(&mut self) -> Option<Type> {
3223 let lhs = if self.eat_keyword("forall") {
3224 self.parse_forall_type()?
3225 } else {
3226 self.parse_application_type()?
3227 };
3228 if self.eat_op("=>") {
3229 let body = self.parse_type()?;
3231 let span = Span::from_usize(lhs.span().start_usize(), body.span().end_usize());
3232 return Some(Type::Constrained(Box::new(body), span));
3233 }
3234 if self.eat_op("->") {
3235 let rhs = self.parse_type()?;
3236 let span = Span::from_usize(lhs.span().start_usize(), rhs.span().end_usize());
3237 return Some(Type::Fun(Box::new(lhs), Box::new(rhs), span));
3238 }
3239 Some(lhs)
3240 }
3241
3242 fn parse_application_type(&mut self) -> Option<Type> {
3244 let head = match self.parse_atom()? {
3245 TypeAtom::ParsedType(t) => t,
3246 TypeAtom::DroppedLiteral(_) => return None,
3248 };
3249 let mut args = Vec::new();
3250 let start = head.span().start_usize();
3251 let mut end = head.span().end_usize();
3252 loop {
3253 if !self.is_at_type_atom_start() {
3256 break;
3257 }
3258 match self.parse_atom()? {
3259 TypeAtom::ParsedType(t) => {
3260 end = t.span().end_usize();
3261 args.push(t);
3262 }
3263 TypeAtom::DroppedLiteral(span) => {
3264 end = span.end_usize();
3267 }
3268 }
3269 }
3270 let span = Span::from_usize(start, end);
3271 if args.is_empty() {
3272 Some(head.with_span(span))
3273 } else {
3274 Some(Type::App(Box::new(head), args, span))
3275 }
3276 }
3277
3278 fn is_at_type_atom_start(&self) -> bool {
3281 matches!(
3282 self.peek().map(|t| &t.kind),
3283 Some(
3284 TokenKind::UpperId { .. }
3285 | TokenKind::LowerId { .. }
3286 | TokenKind::IntLit(_)
3287 | TokenKind::DecimalLit(_)
3288 | TokenKind::StringLit(_)
3289 | TokenKind::CharLit(_)
3290 | TokenKind::LBracket
3291 | TokenKind::LParen
3292 )
3293 )
3294 }
3295
3296 fn parse_atom(&mut self) -> Option<TypeAtom> {
3297 let tok = self.peek()?;
3298 match &tok.kind {
3299 TokenKind::UpperId { qualifier, name } => {
3300 let con = Type::Con {
3301 qualifier: qualifier.clone(),
3302 name: name.clone(),
3303 span: Span::from_usize(tok.start, tok.end),
3304 };
3305 self.cursor += 1;
3306 Some(TypeAtom::ParsedType(con))
3307 }
3308 TokenKind::LowerId { name, .. } => {
3309 let var = Type::Var(name.clone(), Span::from_usize(tok.start, tok.end));
3312 self.cursor += 1;
3313 Some(TypeAtom::ParsedType(var))
3314 }
3315 TokenKind::IntLit(_) | TokenKind::DecimalLit(_) => {
3316 self.cursor += 1;
3318 Some(TypeAtom::DroppedLiteral(Span::from_usize(
3319 tok.start, tok.end,
3320 )))
3321 }
3322 TokenKind::StringLit(text) => {
3323 self.cursor += 1;
3324 Some(TypeAtom::ParsedType(Type::Lit {
3325 kind: LitKind::Text,
3326 text: text.clone(),
3327 span: Span::from_usize(tok.start, tok.end),
3328 }))
3329 }
3330 TokenKind::CharLit(text) => {
3331 self.cursor += 1;
3332 Some(TypeAtom::ParsedType(Type::Lit {
3333 kind: LitKind::Char,
3334 text: text.clone(),
3335 span: Span::from_usize(tok.start, tok.end),
3336 }))
3337 }
3338 TokenKind::LBracket => {
3339 let start = tok.start;
3340 self.cursor += 1;
3341 let inner = self.parse_type()?;
3342 self.eat_token(&TokenKind::RBracket).map(|end| {
3343 TypeAtom::ParsedType(Type::List(
3344 Box::new(inner),
3345 Span::from_usize(start, end.end),
3346 ))
3347 })
3348 }
3349 TokenKind::LParen => {
3350 let start = tok.start;
3351 self.cursor += 1;
3352 if let Some(op) = self.eat_token_if_operator() {
3353 let mut name = op.as_str().to_string();
3354 while matches!(
3355 self.tokens.get(self.cursor).map(|t| &t.kind),
3356 Some(TokenKind::Op(_))
3357 ) {
3358 self.cursor += 1;
3359 if let TokenKind::Op(o) = &self.tokens[self.cursor - 1].kind {
3360 name.push_str(o.as_str());
3361 }
3362 }
3363 if self.eat_token(&TokenKind::RParen).is_some()
3364 && self
3365 .tokens
3366 .get(self.cursor)
3367 .is_some_and(|t| Self::is_type_atom_start(&t.kind))
3368 {
3369 let end = self.tokens[self.cursor - 1];
3370 return Some(TypeAtom::ParsedType(Type::Con {
3371 qualifier: None,
3372 name: name.into(),
3373 span: Span::from_usize(start, end.end),
3374 }));
3375 }
3376 return None;
3377 }
3378 if matches!(
3379 self.tokens.get(self.cursor).map(|t| &t.kind),
3380 Some(TokenKind::Comma)
3381 ) {
3382 let mut name = String::from(",");
3383 self.cursor += 1;
3384 while matches!(
3385 self.tokens.get(self.cursor).map(|t| &t.kind),
3386 Some(TokenKind::Comma)
3387 ) {
3388 self.cursor += 1;
3389 name.push(',');
3390 }
3391 if self.eat_token(&TokenKind::RParen).is_some()
3392 && self
3393 .tokens
3394 .get(self.cursor)
3395 .is_some_and(|t| Self::is_type_atom_start(&t.kind))
3396 {
3397 let end = self.tokens[self.cursor - 1];
3398 return Some(TypeAtom::ParsedType(Type::Con {
3399 qualifier: None,
3400 name: name.into(),
3401 span: Span::from_usize(start, end.end),
3402 }));
3403 }
3404 return None;
3405 }
3406 if let Some(end) = self.eat_token(&TokenKind::RParen) {
3407 return Some(TypeAtom::ParsedType(Type::Unit(Span::from_usize(
3409 start, end.end,
3410 ))));
3411 }
3412 let first = self.parse_type()?;
3413 if self.peek().map(|t| &t.kind) == Some(&TokenKind::Comma) {
3414 let mut items = vec![first];
3415 while self.eat_token(&TokenKind::Comma).is_some() {
3416 items.push(self.parse_type()?);
3417 }
3418 self.eat_token(&TokenKind::RParen).map(|end| {
3419 TypeAtom::ParsedType(Type::Tuple(items, Span::from_usize(start, end.end)))
3420 })
3421 } else {
3422 self.eat_token(&TokenKind::RParen).map(|end| {
3423 TypeAtom::ParsedType(first.with_span(Span::from_usize(start, end.end)))
3425 })
3426 }
3427 }
3428 _ => None,
3429 }
3430 }
3431
3432 fn eat_keyword(&mut self, kw: &str) -> bool {
3433 if self.peek().is_some_and(|t| t.kind.is_keyword(kw)) {
3434 self.cursor += 1;
3435 true
3436 } else {
3437 false
3438 }
3439 }
3440
3441 fn parse_forall_type(&mut self) -> Option<Type> {
3442 let start = self
3443 .tokens
3444 .get(self.cursor.wrapping_sub(1))
3445 .map(|t| t.start)
3446 .unwrap_or_default();
3447 while self.cursor < self.tokens.len() {
3448 if self.peek().is_some_and(|t| t.kind.is_op(".")) {
3449 self.cursor += 1;
3450 let body = self.parse_type()?;
3451 let body_span = body.span();
3452 return Some(body.with_span(Span::from_usize(start, body_span.end_usize())));
3453 }
3454 self.cursor += 1;
3455 }
3456 None
3457 }
3458
3459 fn eat_token(&mut self, tok: &TokenKind) -> Option<&'a Token> {
3460 if self.peek().is_some_and(|t| t.kind == *tok) {
3461 let t = self.peek();
3462 self.cursor += 1;
3463 t
3464 } else {
3465 None
3466 }
3467 }
3468
3469 fn eat_token_if_operator(&mut self) -> Option<&'a Operator> {
3470 match self.peek() {
3471 Some(Token {
3472 kind: TokenKind::Op(op),
3473 ..
3474 }) => {
3475 self.cursor += 1;
3476 Some(op)
3477 }
3478 _ => None,
3479 }
3480 }
3481
3482 const fn is_type_atom_start(kind: &TokenKind) -> bool {
3483 matches!(
3484 kind,
3485 TokenKind::UpperId { .. }
3486 | TokenKind::LowerId { .. }
3487 | TokenKind::IntLit(_)
3488 | TokenKind::DecimalLit(_)
3489 | TokenKind::StringLit(_)
3490 | TokenKind::CharLit(_)
3491 | TokenKind::LParen
3492 | TokenKind::LBracket
3493 )
3494 }
3495}
3496
3497fn render_token_slice(tokens: &[Token]) -> String {
3498 let mut s = String::new();
3499 let mut prev_no_space_after = true;
3500 for t in tokens {
3501 let (text, no_space_before, no_space_after): (String, bool, bool) = match &t.kind {
3502 TokenKind::LowerId { qualifier, name } | TokenKind::UpperId { qualifier, name } => (
3503 qualifier
3504 .as_ref()
3505 .map_or_else(|| name.to_string(), |q| format!("{q}.{name}")),
3506 false,
3507 false,
3508 ),
3509 TokenKind::Op(o) => (o.to_string(), false, false),
3510 TokenKind::IntLit(n) | TokenKind::DecimalLit(n) => (n.clone(), false, false),
3511 TokenKind::StringLit(v) => (format!("{v:?}"), false, false),
3512 TokenKind::CharLit(v) => (format!("'{v}'"), false, false),
3513 TokenKind::LParen => ("(".to_string(), false, true),
3514 TokenKind::RParen => (")".to_string(), true, false),
3515 TokenKind::LBracket => ("[".to_string(), false, true),
3516 TokenKind::RBracket => ("]".to_string(), true, false),
3517 TokenKind::LBrace => ("{".to_string(), false, true),
3518 TokenKind::RBrace => ("}".to_string(), true, false),
3519 TokenKind::Comma => (",".to_string(), true, false),
3520 TokenKind::Semi | TokenKind::VSemi => (";".to_string(), true, false),
3521 TokenKind::Backtick => ("`".to_string(), false, false),
3522 TokenKind::VLBrace | TokenKind::VRBrace => continue,
3523 };
3524 if !s.is_empty() && !no_space_before && !prev_no_space_after {
3525 s.push(' ');
3526 }
3527 s.push_str(&text);
3528 prev_no_space_after = no_space_after;
3529 }
3530 s
3531}
3532
3533#[cfg(test)]
3536mod type_tests {
3537 use super::*;
3538 use crate::lexer::lex;
3539
3540 fn ty(s: &str) -> Option<Type> {
3544 let (toks, errs) = lex(s).into_parts();
3545 assert!(errs.is_empty(), "lex errors for {s:?}: {errs:?}");
3546 parse_type_from_tokens(&toks)
3547 }
3548
3549 fn con(name: &str) -> Type {
3550 Type::Con {
3551 qualifier: None,
3552 name: name.into(),
3553 span: Span::default(),
3554 }
3555 }
3556
3557 fn qualified_con(qualifier: &str, name: &str) -> Type {
3558 Type::Con {
3559 qualifier: Some(qualifier.into()),
3560 name: name.into(),
3561 span: Span::default(),
3562 }
3563 }
3564
3565 fn app(head: Type, args: Vec<Type>) -> Type {
3566 Type::App(Box::new(head), args, Span::default())
3567 }
3568
3569 fn list(inner: Type) -> Type {
3570 Type::List(Box::new(inner), Span::default())
3571 }
3572
3573 fn tuple(items: Vec<Type>) -> Type {
3574 Type::Tuple(items, Span::default())
3575 }
3576
3577 fn fun(param: Type, result: Type) -> Type {
3578 Type::Fun(Box::new(param), Box::new(result), Span::default())
3579 }
3580
3581 fn var(name: &str) -> Type {
3582 Type::Var(name.into(), Span::default())
3583 }
3584
3585 fn unit() -> Type {
3586 Type::Unit(Span::default())
3587 }
3588
3589 fn constrained(body: Type) -> Type {
3590 Type::Constrained(Box::new(body), Span::default())
3591 }
3592
3593 fn text_lit(value: &str) -> Type {
3594 Type::Lit {
3595 kind: LitKind::Text,
3596 text: value.to_string(),
3597 span: Span::default(),
3598 }
3599 }
3600
3601 fn char_lit(value: &str) -> Type {
3602 Type::Lit {
3603 kind: LitKind::Char,
3604 text: value.to_string(),
3605 span: Span::default(),
3606 }
3607 }
3608
3609 #[test]
3610 fn atoms() {
3611 assert_eq!(ty("Party"), Some(con("Party")));
3612 assert_eq!(ty("Decimal"), Some(con("Decimal")));
3613 assert_eq!(ty("a"), Some(var("a")));
3614 assert_eq!(ty("()"), Some(unit()));
3615 }
3616
3617 #[test]
3618 fn application_vs_constructor() {
3619 assert_eq!(
3622 ty("ContractId Foo"),
3623 Some(app(con("ContractId"), vec![con("Foo")]))
3624 );
3625 assert_eq!(
3626 ty("Optional (ContractId Foo)"),
3627 Some(app(
3628 con("Optional"),
3629 vec![app(con("ContractId"), vec![con("Foo")])]
3630 ))
3631 );
3632 assert_eq!(
3633 ty("Map Text Int"),
3634 Some(app(con("Map"), vec![con("Text"), con("Int")]))
3635 );
3636 }
3637
3638 #[test]
3639 fn qualified_constructor_keeps_qualifier() {
3640 assert_eq!(
3641 ty("DA.Map.Map Text Int"),
3642 Some(app(
3643 qualified_con("DA.Map", "Map"),
3644 vec![con("Text"), con("Int")]
3645 ))
3646 );
3647 }
3648
3649 #[test]
3650 fn list_and_tuple() {
3651 assert_eq!(ty("[Text]"), Some(list(con("Text"))));
3652 assert_eq!(
3653 ty("(Int, Text)"),
3654 Some(tuple(vec![con("Int"), con("Text")]))
3655 );
3656 assert_eq!(
3658 ty("(a, b, c)"),
3659 Some(tuple(vec![var("a"), var("b"), var("c")]))
3660 );
3661 assert_eq!(ty("(Text)"), Some(con("Text")));
3663 }
3664
3665 #[test]
3666 fn function_types_are_arrows_not_names() {
3667 assert_eq!(ty("Int -> Int"), Some(fun(con("Int"), con("Int"))));
3670 assert_eq!(
3672 ty("Int -> Text -> Bool"),
3673 Some(fun(con("Int"), fun(con("Text"), con("Bool"))))
3674 );
3675 assert_eq!(
3676 ty("Party -> Script ()"),
3677 Some(fun(con("Party"), app(con("Script"), vec![unit()])))
3678 );
3679 }
3680
3681 #[test]
3682 fn script_application() {
3683 assert_eq!(ty("Script ()"), Some(app(con("Script"), vec![unit()])));
3686 }
3687
3688 #[test]
3689 fn numeric_nat_literal_is_dropped() {
3690 assert_eq!(ty("Numeric 10"), Some(con("Numeric")));
3693 assert_eq!(ty("Numeric n"), Some(app(con("Numeric"), vec![var("n")])));
3694 }
3695
3696 #[test]
3697 fn string_and_char_type_literals_are_structured() {
3698 assert_eq!(
3701 ty(r#"HasField "observers""#),
3702 Some(app(con("HasField"), vec![text_lit("observers")]))
3703 );
3704 assert_eq!(
3705 ty(r#"HasField "observers" t PartiesMap"#),
3706 Some(app(
3707 con("HasField"),
3708 vec![text_lit("observers"), var("t"), con("PartiesMap")]
3709 ))
3710 );
3711 assert_eq!(
3712 ty(r"HasField 'x'"),
3713 Some(app(con("HasField"), vec![char_lit("x")]))
3714 );
3715 }
3716
3717 #[test]
3718 fn constraint_context_is_dropped_body_kept() {
3719 assert_eq!(
3722 ty("NumericScale n => Numeric 37 -> Numeric n"),
3723 Some(constrained(fun(
3724 con("Numeric"),
3725 app(con("Numeric"), vec![var("n")])
3726 )))
3727 );
3728 assert_eq!(ty("(Eq a, Show a) => a"), Some(constrained(var("a"))));
3730 }
3731
3732 #[test]
3733 fn unparseable_is_none() {
3734 assert_eq!(ty("Int ->"), None);
3737 assert_eq!(ty("-> Int"), None);
3738 }
3739}