1use crate::ast::{
8 Alt, AltBranch, Binding, ChoiceDecl, Consuming, Decl, DoStmt, Equation, ExpectedToken, Expr,
9 FieldAssign, FieldDecl, FixityAssoc, FixityDecl, FixityTarget, FunctionDecl, GuardQualifier,
10 Identifier, ImportDecl, ImportPackageLabel, ImportStyle, InterfaceDecl,
11 InterfaceInstanceBodyItem, InterfaceInstanceDecl, LitKind, MalformedSyntaxKind, Module,
12 ModuleName, Operator, ParseDiagnostic, ParseDiagnosticKind, Pat, PatFieldAssign,
13 RecordPatternSyntax, SkippedDeclarationReason, Span, TemplateBodyDecl, TemplateDecl, Type,
14 TypeAnnotation, TypeAnnotationContext, UnsupportedSyntaxKind,
15};
16use crate::layout::resolve_layout;
17use crate::lexer::{lex, Pos, Token, TokenKind};
18use std::collections::HashMap;
19
20pub const MAX_RECURSION_DEPTH: u32 = 128;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct ParseModuleResult {
31 pub module: Module,
34 pub diagnostics: Vec<ParseDiagnostic>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct ParseModuleError {
46 diagnostics: Vec<ParseDiagnostic>,
47 module: Box<Module>,
48}
49
50impl ParseModuleError {
51 #[must_use]
52 pub fn diagnostics(&self) -> &[ParseDiagnostic] {
53 &self.diagnostics
54 }
55
56 #[must_use]
57 pub fn module(&self) -> &Module {
58 &self.module
59 }
60
61 #[must_use]
62 pub fn into_parts(self) -> (Vec<ParseDiagnostic>, Module) {
63 (self.diagnostics, *self.module)
64 }
65}
66
67impl std::fmt::Display for ParseModuleError {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(
70 f,
71 "parse failed with {} diagnostic(s)",
72 self.diagnostics.len()
73 )?;
74 if let Some(first) = self.diagnostics.first() {
75 write!(f, ": {}", first.message)?;
76 }
77 Ok(())
78 }
79}
80
81impl std::error::Error for ParseModuleError {}
82
83#[derive(Clone, Copy, Debug)]
84enum DoExpressionMode {
85 Allow,
86 Disallow,
87}
88
89impl DoExpressionMode {
90 const fn allows_do(&self) -> bool {
91 matches!(self, Self::Allow)
92 }
93}
94
95impl ParseModuleResult {
96 #[must_use]
98 pub const fn has_errors(&self) -> bool {
99 !self.diagnostics.is_empty()
100 }
101
102 #[must_use]
104 pub fn into_parts(self) -> (Module, Vec<ParseDiagnostic>) {
105 (self.module, self.diagnostics)
106 }
107
108 pub fn into_result(self) -> Result<Module, ParseModuleError> {
129 if self.diagnostics.is_empty() {
130 Ok(self.module)
131 } else {
132 Err(ParseModuleError {
133 diagnostics: self.diagnostics,
134 module: Box::new(self.module),
135 })
136 }
137 }
138}
139
140#[must_use]
155pub fn parse_module(source: &str) -> ParseModuleResult {
156 let lexed = lex(source);
157 let tokens = lexed.tokens;
158 let lex_errors = lexed.errors;
159 let tokens = resolve_layout(tokens);
160 let mut p = Parser {
161 toks: tokens,
162 src_len: source.len(),
163 i: 0,
164 depth: 0,
165 fixity_env: HashMap::new(),
166 diags: lex_errors
167 .into_iter()
168 .map(|e| {
169 let range = e.byte_range_in(source);
170 ParseDiagnostic::new(
171 ParseDiagnosticKind::Lex(e.kind.clone()),
172 e.to_string(),
173 e.pos,
174 crate::ast::Span::from_usize(range.start, range.end),
175 )
176 })
177 .collect(),
178 };
179 let mut module = p.module();
180 module.span = crate::ast::Span::from_usize(0, source.len());
181 ParseModuleResult {
182 module,
183 diagnostics: p.diags,
184 }
185}
186
187pub fn parse_module_strict(source: &str) -> Result<Module, ParseModuleError> {
215 parse_module(source).into_result()
216}
217
218struct Parser {
219 toks: Vec<Token>,
220 src_len: usize,
222 i: usize,
223 diags: Vec<ParseDiagnostic>,
224 depth: u32,
227 fixity_env: HashMap<String, (u8, bool)>,
230}
231
232impl Parser {
233 fn node_span(&self, from: usize) -> crate::ast::Span {
239 let mut a = from;
240 while a < self.i && self.toks[a].is_virtual() {
241 a += 1;
242 }
243 let mut b = self.i;
244 while b > a && self.toks[b - 1].is_virtual() {
245 b -= 1;
246 }
247 if a >= b {
248 let p = self.byte_at(a);
253 return crate::ast::Span::from_usize(p, p);
254 }
255 crate::ast::Span::from_usize(self.toks[a].start, self.toks[b - 1].end)
256 }
257
258 fn byte_at(&self, i: usize) -> usize {
260 self.toks.get(i).map(|t| t.start).unwrap_or(self.src_len)
261 }
262
263 fn end_byte(&self) -> usize {
267 let mut b = self.i;
268 while b > 0 && self.toks[b - 1].is_virtual() {
269 b -= 1;
270 }
271 if b == 0 {
272 0
273 } else {
274 self.toks[b - 1].end
275 }
276 }
277}
278
279impl Parser {
280 fn peek(&self) -> Option<&TokenKind> {
283 self.toks.get(self.i).map(|t| &t.kind)
284 }
285
286 fn peek_at(&self, n: usize) -> Option<&TokenKind> {
287 self.toks.get(self.i + n).map(|t| &t.kind)
288 }
289
290 fn pos(&self) -> Pos {
291 self.toks
292 .get(self.i)
293 .or_else(|| self.toks.last())
294 .map_or(Pos { line: 1, column: 1 }, |t| t.pos)
295 }
296
297 fn bump(&mut self) -> Option<Token> {
298 let t = self.toks.get(self.i).cloned();
299 if t.is_some() {
300 self.i += 1;
301 }
302 t
303 }
304
305 fn at_keyword(&self, kw: &str) -> bool {
306 self.peek().is_some_and(|t| t.is_keyword(kw))
307 }
308
309 fn eat_keyword(&mut self, kw: &str) -> bool {
310 if self.at_keyword(kw) {
311 self.i += 1;
312 true
313 } else {
314 false
315 }
316 }
317
318 fn at_op(&self, op: &str) -> bool {
319 self.peek().is_some_and(|t| t.is_op(op))
320 }
321
322 fn eat_op(&mut self, op: &str) -> bool {
323 if self.at_op(op) {
324 self.i += 1;
325 true
326 } else {
327 false
328 }
329 }
330
331 fn at(&self, tok: &TokenKind) -> bool {
332 self.peek() == Some(tok)
333 }
334
335 fn eat(&mut self, tok: &TokenKind) -> bool {
336 if self.at(tok) {
337 self.i += 1;
338 true
339 } else {
340 false
341 }
342 }
343
344 fn diag_expected(&mut self, expected: ExpectedToken, message: impl Into<String>) {
346 self.diag_kind(ParseDiagnosticKind::ExpectedToken(expected), message);
347 }
348
349 fn diag_malformed(&mut self, kind: MalformedSyntaxKind, message: impl Into<String>) {
351 self.diag_kind(ParseDiagnosticKind::MalformedSyntax(kind), message);
352 }
353
354 fn diag_kind(&mut self, kind: ParseDiagnosticKind, message: impl Into<String>) {
358 let pos = self.pos();
359 let span = self.cur_span();
360 self.diags
361 .push(ParseDiagnostic::new(kind, message, pos, span));
362 }
363
364 fn parse_type_annotation(
365 &mut self,
366 type_start: usize,
367 type_end: usize,
368 context: TypeAnnotationContext,
369 ) -> TypeAnnotation {
370 let type_start = type_start.min(self.toks.len());
371 let type_end = type_end.min(self.toks.len());
372 let tokens = &self.toks[type_start..type_end];
373 let ty = parse_type_from_tokens(tokens).or_else(|| {
374 let trimmed = Self::trim_type_tokens_for_parse(tokens);
375 if trimmed < tokens.len() {
376 parse_type_from_tokens(&tokens[..trimmed])
377 } else {
378 None
379 }
380 });
381 match ty {
382 Some(ty) => TypeAnnotation::Present(ty),
383 None => {
384 let span = self.span_of_token_range(type_start, type_end);
385 self.diags.push(ParseDiagnostic::new(
386 ParseDiagnosticKind::MalformedTypeAnnotation(context),
387 format!("malformed {} type annotation", context.as_str()),
388 self.pos_of_token(type_start),
389 span,
390 ));
391 TypeAnnotation::Malformed { span }
392 }
393 }
394 }
395
396 fn trim_type_tokens_for_parse(tokens: &[Token]) -> usize {
401 let mut depth = 0usize;
402 let mut bracket_depth = 0usize;
403 let mut i = 0usize;
404 while i < tokens.len() {
405 match &tokens[i].kind {
406 TokenKind::LParen | TokenKind::LBracket => {
407 depth += 1;
408 i += 1;
409 }
410 TokenKind::RParen | TokenKind::RBracket => {
411 depth = depth.saturating_sub(1);
412 i += 1;
413 }
414 TokenKind::LBrace => {
415 bracket_depth += 1;
416 i += 1;
417 }
418 TokenKind::RBrace => {
419 bracket_depth = bracket_depth.saturating_sub(1);
420 i += 1;
421 }
422 TokenKind::Op(o) if o.as_str() == "=" && depth == 0 && bracket_depth == 0 => {
423 return i;
424 }
425 TokenKind::Semi | TokenKind::VSemi if depth == 0 && bracket_depth == 0 => {
426 return i;
427 }
428 TokenKind::Comma
429 if depth == 0
430 && bracket_depth == 0
431 && matches!(
432 tokens.get(i + 1),
433 Some(Token {
434 kind: TokenKind::LowerId {
435 qualifier: None,
436 ..
437 },
438 ..
439 })
440 )
441 && matches!(
442 tokens.get(i + 2),
443 Some(Token { kind: TokenKind::Op(o), .. }) if o.as_str() == ":"
444 ) =>
445 {
446 return i;
447 }
448 _ => {
449 i += 1;
450 }
451 }
452 }
453 tokens.len()
454 }
455
456 fn pos_of_token(&self, idx: usize) -> Pos {
457 self.toks.get(idx).map_or_else(|| self.pos(), |tok| tok.pos)
458 }
459
460 fn span_of_token_range(&self, start: usize, end: usize) -> Span {
461 let start = start.min(self.toks.len());
462 let end = end.min(self.toks.len());
463 let span_start = self.byte_at(start);
464 if end <= start {
465 return Span::from_usize(span_start, span_start);
466 }
467
468 let mut cursor = end;
469 while cursor > start {
470 cursor -= 1;
471 let token = &self.toks[cursor];
472 if !token.is_virtual() {
473 return Span::from_usize(span_start, token.end);
474 }
475 }
476
477 Span::from_usize(span_start, span_start)
478 }
479
480 fn cur_span(&self) -> crate::ast::Span {
483 let mut j = self.i;
484 while self.toks.get(j).is_some_and(|t| t.is_virtual()) {
485 j += 1;
486 }
487 self.toks.get(j).map_or_else(
488 || crate::ast::Span::from_usize(self.src_len, self.src_len),
489 |t| crate::ast::Span::from_usize(t.start, t.end),
490 )
491 }
492
493 fn skip_to_item_end(&mut self) {
496 let mut depth = 0usize;
497 let mut brackets = 0usize;
498 while let Some(t) = self.peek() {
499 match t {
500 TokenKind::VLBrace => depth += 1,
501 TokenKind::VRBrace => {
502 if depth == 0 {
503 return;
504 }
505 depth -= 1;
506 }
507 TokenKind::VSemi if depth == 0 && brackets == 0 => return,
508 TokenKind::LParen | TokenKind::LBracket | TokenKind::LBrace => brackets += 1,
509 TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace => {
510 if brackets == 0 {
511 return;
514 }
515 brackets -= 1;
516 }
517 _ => {}
518 }
519 self.i += 1;
520 }
521 }
522
523 fn slice_text(&self, start: usize) -> String {
525 render_token_slice(&self.toks[start..self.i])
526 }
527
528 fn module(&mut self) -> Module {
531 let pos = self.pos();
532 let header_start = self.i;
533 let mut header = crate::ast::Span::from_usize(0, 0);
534 let mut name = ModuleName::from("Unknown");
535
536 if self.eat_keyword("module") {
537 if let Some(TokenKind::UpperId { qualifier, name: n }) = self.peek().cloned() {
538 self.bump();
539 name = match qualifier {
540 Some(q) => format!("{q}.{n}").into(),
541 None => n.into(),
542 };
543 }
544 if self.at(&TokenKind::LParen) {
546 self.skip_balanced_parens();
547 }
548 if !self.eat_keyword("where") {
549 self.diag_expected(
550 ExpectedToken::WhereAfterModuleHeader,
551 "expected 'where' after module header",
552 );
553 }
554 header = self.node_span(header_start);
555 }
556
557 let mut imports = Vec::new();
558 let mut decls: Vec<Decl> = Vec::new();
559
560 let _ = self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace);
564 self.fixity_env = scan_module_fixity_env(&self.toks, self.i);
565 loop {
566 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
567 match self.peek() {
568 None => break,
569 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
570 self.bump();
571 break;
572 }
573 Some(TokenKind::RParen | TokenKind::RBracket) => {
578 let cpos = self.pos();
579 let cstart = self.i;
580 self.bump();
581 decls.push(Decl::Unknown {
582 raw: self.slice_text(cstart),
583 pos: cpos,
584 span: self.node_span(cstart),
585 });
586 continue;
587 }
588 _ => {}
589 }
590 let before = self.i;
591 self.declaration(&mut imports, &mut decls);
592 if self.i == before {
593 self.bump();
595 }
596 }
597
598 merge_functions(&mut decls);
599
600 Module {
601 name,
602 pos,
603 header,
604 imports,
605 decls,
606 span: crate::ast::Span::from_usize(0, self.src_len),
607 }
608 }
609
610 fn skip_balanced_parens(&mut self) {
611 let mut depth = 0usize;
612 while let Some(t) = self.peek() {
613 match t {
614 TokenKind::LParen => depth += 1,
615 TokenKind::RParen => {
616 if depth == 0 {
617 return;
618 }
619 depth -= 1;
620 if depth == 0 {
621 self.i += 1;
622 return;
623 }
624 }
625 _ => {}
626 }
627 self.i += 1;
628 }
629 }
630
631 fn try_infix_operator_decl(&mut self) -> bool {
635 let snap = self.i;
636 let saved_diags = self.diags.len();
637 if self.pattern().is_some()
638 && matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o))
639 {
640 self.skip_to_item_end();
641 return true;
642 }
643 self.i = snap;
644 self.diags.truncate(saved_diags);
645 false
646 }
647
648 fn declaration(&mut self, imports: &mut Vec<ImportDecl>, decls: &mut Vec<Decl>) {
649 let pos = self.pos();
650 let start = self.i;
651 if matches!(
652 self.peek(),
653 Some(TokenKind::UpperId { .. } | TokenKind::LBracket | TokenKind::LParen)
654 ) && self.try_infix_operator_decl()
655 {
656 decls.push(Decl::Unknown {
657 raw: self.slice_text(start),
658 pos,
659 span: self.node_span(start),
660 });
661 return;
662 }
663 match self.peek() {
664 Some(t) if t.is_keyword("import") => {
665 let imp = self.import_decl();
666 self.skip_to_item_end();
670 if let Some(mut imp) = imp {
671 imp.span = self.node_span(start);
672 imports.push(imp);
673 }
674 }
675 Some(t) if t.is_keyword("template") => {
676 match self.template_decl() {
679 Some(t) => decls.push(Decl::Template(t)),
680 None => {
681 self.skip_to_item_end();
682 decls.push(Decl::Unknown {
683 raw: self.slice_text(start),
684 span: self.node_span(start),
685 pos,
686 });
687 }
688 }
689 }
690 Some(t) if t.is_keyword("interface") => match self.interface_decl() {
691 Some(i) => decls.push(Decl::Interface(i)),
692 None => {
693 self.skip_to_item_end();
694 decls.push(Decl::Unknown {
695 raw: self.slice_text(start),
696 span: self.node_span(start),
697 pos,
698 });
699 }
700 },
701 Some(t) if matches!(t.keyword(), Some("infix" | "infixl" | "infixr")) => {
702 if let Some(fixity) = self.fixity_decl() {
703 decls.push(Decl::Fixity(fixity));
704 } else {
705 self.skip_to_item_end();
706 decls.push(Decl::Unknown {
707 raw: self.slice_text(start),
708 pos,
709 span: self.node_span(start),
710 });
711 }
712 }
713 Some(t) if t.is_keyword("pattern") => {
714 self.skip_to_item_end();
715 decls.push(Decl::UnsupportedSyntax {
716 kind: UnsupportedSyntaxKind::PatternSynonym,
717 raw: self.slice_text(start),
718 pos,
719 span: self.node_span(start),
720 });
721 }
722 Some(t) if t.is_keyword("default") => {
723 self.skip_to_item_end();
724 decls.push(Decl::Unknown {
725 raw: self.slice_text(start),
726 pos,
727 span: self.node_span(start),
728 });
729 }
730 Some(t)
731 if matches!(
732 t.keyword(),
733 Some(
734 "data"
735 | "type"
736 | "newtype"
737 | "class"
738 | "instance"
739 | "exception"
740 | "deriving"
741 )
742 ) =>
743 {
744 let keyword = t
745 .keyword()
746 .expect("declaration-head keyword token")
747 .to_string();
748 self.bump();
749 let name = match self.peek() {
750 Some(TokenKind::UpperId { qualifier, name }) => {
751 let n = qualifier
752 .as_ref()
753 .map_or_else(|| name.to_string(), |q| format!("{q}.{name}"));
754 self.bump();
755 n
756 }
757 _ => String::new(),
758 };
759 self.skip_to_item_end();
760 decls.push(Decl::TypeDef {
761 keyword,
762 name: name.into(),
763 pos,
764 span: self.node_span(start),
765 });
766 }
767 Some(TokenKind::LowerId { .. }) => match self.function_item() {
768 Some(d) => decls.push(d),
769 None => {
770 self.skip_to_item_end();
771 decls.push(Decl::Unknown {
772 raw: self.slice_text(start),
773 span: self.node_span(start),
774 pos,
775 });
776 }
777 },
778 Some(TokenKind::LParen)
780 if matches!(self.peek_at(1), Some(TokenKind::Op(_)))
781 && self.peek_at(2) == Some(&TokenKind::RParen) =>
782 {
783 match self.operator_function_item() {
784 Some(d) => decls.push(d),
785 None => {
786 self.skip_to_item_end();
787 decls.push(Decl::Unknown {
788 raw: self.slice_text(start),
789 span: self.node_span(start),
790 pos,
791 });
792 }
793 }
794 }
795 Some(TokenKind::LParen | TokenKind::LBracket) => {
797 if self.binding().is_none() {
798 self.diag_kind(
799 ParseDiagnosticKind::SkippedDeclaration(
800 SkippedDeclarationReason::TopLevelPatternBinding,
801 ),
802 "unparseable top-level pattern binding",
803 );
804 }
805 self.skip_to_item_end();
806 decls.push(Decl::Unknown {
807 raw: self.slice_text(start),
808 span: self.node_span(start),
809 pos,
810 });
811 }
812 _ => {
813 self.diag_kind(
814 ParseDiagnosticKind::SkippedDeclaration(
815 SkippedDeclarationReason::UnrecognizedDeclaration,
816 ),
817 format!("unrecognized declaration: {:?}", self.peek()),
818 );
819 self.skip_to_item_end();
820 decls.push(Decl::Unknown {
821 raw: self.slice_text(start),
822 span: self.node_span(start),
823 pos,
824 });
825 }
826 }
827 }
828
829 fn import_decl(&mut self) -> Option<ImportDecl> {
832 let pos = self.pos();
833 let start_i = self.i;
834 self.bump(); let mut style = if self.eat_keyword("qualified") {
836 ImportStyle::Qualified
837 } else {
838 ImportStyle::Unqualified
839 };
840 let package_label = if let Some(TokenKind::StringLit(value)) = self.peek().cloned() {
842 let tok = self.bump().expect("string literal peeked");
843 Some(ImportPackageLabel {
844 value,
845 span: crate::ast::Span::from_usize(tok.start, tok.end),
846 })
847 } else {
848 None
849 };
850 let module_name = match self.peek().cloned() {
851 Some(TokenKind::UpperId { qualifier, name }) => {
852 self.bump();
853 match qualifier {
854 Some(q) => format!("{q}.{name}").into(),
855 None => name.into(),
856 }
857 }
858 _ => {
859 self.diag_expected(
860 ExpectedToken::ModuleNameAfterImport,
861 "expected module name after 'import'",
862 );
863 return None;
864 }
865 };
866 if self.eat_keyword("qualified") {
868 style = ImportStyle::Qualified;
869 }
870 let mut alias = None;
871 if self.eat_keyword("as") {
872 if let Some(TokenKind::UpperId { qualifier, name }) = self.peek().cloned() {
873 self.bump();
874 alias = Some(match qualifier {
875 Some(q) => format!("{q}.{name}").into(),
876 None => name.into(),
877 });
878 }
879 }
880 Some(ImportDecl {
882 module_name,
883 style,
884 alias,
885 package_label,
886 pos,
887 span: self.node_span(start_i),
888 })
889 }
890
891 fn upper_name(&mut self) -> Option<ModuleName> {
894 match self.peek().cloned() {
895 Some(TokenKind::UpperId { qualifier, name }) => {
896 self.bump();
897 Some(match qualifier {
898 Some(q) => format!("{q}.{name}").into(),
899 None => name.into(),
900 })
901 }
902 _ => None,
903 }
904 }
905
906 fn template_decl(&mut self) -> Option<TemplateDecl> {
907 let pos = self.pos();
908 let start_i = self.i;
909 self.bump(); if self.at_keyword("instance") {
911 return None; }
913 let name = self.upper_name()?.to_string().into();
914
915 let fields = self
916 .eat_keyword("with")
917 .then(|| self.field_block())
918 .map(|parsed| parsed.fields)
919 .unwrap_or_default();
920 let body = if self.eat_keyword("where") {
921 self.template_body()
922 } else {
923 Vec::new()
924 };
925 Some(TemplateDecl {
926 name,
927 fields,
928 body,
929 pos,
930 span: self.node_span(start_i),
931 })
932 }
933
934 fn field_block(&mut self) -> FieldBlock {
941 let mut fields = Vec::new();
942 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
943 return FieldBlock {
944 fields,
945 dangling: false,
946 };
947 }
948 loop {
949 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
950 match self.peek() {
951 None => break,
952 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
953 self.bump();
954 break;
955 }
956 Some(TokenKind::RParen | TokenKind::RBracket) => {
961 self.bump();
962 continue;
963 }
964 _ => {}
965 }
966 {
971 let mut j = self.i;
972 while let Some(TokenKind::LowerId {
973 qualifier: None, ..
974 }) = self.toks.get(j).map(|t| &t.kind)
975 {
976 j += 1;
977 match self.toks.get(j).map(|t| &t.kind) {
978 Some(TokenKind::Comma) => j += 1,
979 _ => break,
980 }
981 }
982 let is_field = j > self.i
983 && self
984 .toks
985 .get(j)
986 .map(|t| &t.kind)
987 .is_some_and(|t| t.is_op(":"));
988 if !is_field {
989 return FieldBlock {
990 fields,
991 dangling: true,
992 };
993 }
994 }
995 let mut names: Vec<(Identifier, Pos, Span)> = Vec::new();
997 while let Some(TokenKind::LowerId {
998 qualifier: None,
999 name,
1000 }) = self.peek().cloned()
1001 {
1002 let p = self.pos();
1003 let nspan = Span::from_usize(self.toks[self.i].start, self.toks[self.i].end);
1004 self.bump();
1005 names.push((name, p, nspan));
1006 if !self.eat(&TokenKind::Comma) {
1007 break;
1008 }
1009 }
1010 if names.is_empty() || !self.eat_op(":") {
1011 self.diag_expected(
1012 ExpectedToken::FieldNameTypePair,
1013 "expected 'name : Type' field",
1014 );
1015 self.skip_to_item_end();
1016 continue;
1017 }
1018 let ty_start = self.i;
1019 self.skip_to_item_end();
1020 let ty = self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Field);
1021 let type_end = self.end_byte();
1026 let last = names.len() - 1;
1027 for (idx, (name, p, nspan)) in names.into_iter().enumerate() {
1028 let span = if idx == last {
1029 Span::from_usize(nspan.start_usize(), type_end.max(nspan.end_usize()))
1030 } else {
1031 nspan
1032 };
1033 fields.push(FieldDecl {
1034 name: name.to_string().into(),
1035 ty: ty.clone(),
1036 pos: p,
1037 span,
1038 });
1039 }
1040 }
1041 FieldBlock {
1042 fields,
1043 dangling: false,
1044 }
1045 }
1046
1047 fn template_body(&mut self) -> Vec<TemplateBodyDecl> {
1050 let mut body = Vec::new();
1051 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1052 return body;
1053 }
1054 loop {
1055 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1056 match self.peek() {
1057 None => break,
1058 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1059 self.bump();
1060 break;
1061 }
1062 Some(TokenKind::RParen | TokenKind::RBracket) => {
1067 self.bump();
1068 continue;
1069 }
1070 _ => {}
1071 }
1072 let pos = self.pos();
1073 let start = self.i;
1074 let decl = self.template_body_item(pos, start);
1075 body.push(decl);
1076 }
1077 body
1078 }
1079
1080 fn template_body_item(&mut self, pos: Pos, start: usize) -> TemplateBodyDecl {
1081 match self.peek().and_then(|t| t.keyword()) {
1082 Some("signatory") => {
1083 self.bump();
1084 let parties = self.expr_comma_list();
1085 self.skip_to_item_end();
1086 TemplateBodyDecl::Signatory {
1087 parties,
1088 pos,
1089 span: self.node_span(start),
1090 }
1091 }
1092 Some("observer") => {
1093 self.bump();
1094 let parties = self.expr_comma_list();
1095 self.skip_to_item_end();
1096 TemplateBodyDecl::Observer {
1097 parties,
1098 pos,
1099 span: self.node_span(start),
1100 }
1101 }
1102 Some("ensure") => {
1103 self.bump();
1104 let expr = self.expr();
1105 self.skip_to_item_end();
1106 TemplateBodyDecl::Ensure {
1107 expr,
1108 pos,
1109 span: self.node_span(start),
1110 }
1111 }
1112 Some("key") => {
1113 self.bump();
1114 let expr_start = self.i;
1115 let expr = self.expr();
1116 let ty = if self.eat_op(":") {
1117 let ty_start = self.i;
1118 self.skip_to_item_end();
1119 self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Key)
1120 } else {
1121 let mut depth = 0i32;
1124 let mut colon = None;
1125 for j in expr_start..self.i {
1126 match &self.toks[j].kind {
1127 TokenKind::LParen | TokenKind::LBracket => depth += 1,
1128 TokenKind::RParen | TokenKind::RBracket if depth > 0 => depth -= 1,
1129 TokenKind::Op(o) if o.as_str() == ":" && depth == 0 => colon = Some(j),
1130 _ => {}
1131 }
1132 }
1133 let ty = colon.map_or(TypeAnnotation::Absent, |j| {
1134 self.parse_type_annotation(j + 1, self.i, TypeAnnotationContext::Key)
1135 });
1136 self.skip_to_item_end();
1137 ty
1138 };
1139 TemplateBodyDecl::Key {
1140 expr,
1141 ty,
1142 pos,
1143 span: self.node_span(start),
1144 }
1145 }
1146 Some("maintainer") => {
1147 self.bump();
1148 let expr = self.expr();
1149 self.skip_to_item_end();
1150 TemplateBodyDecl::Maintainer {
1151 expr,
1152 pos,
1153 span: self.node_span(start),
1154 }
1155 }
1156 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1157 self.choice_decl().map_or_else(
1158 || {
1159 self.skip_to_item_end();
1160 TemplateBodyDecl::Other {
1161 raw: self.slice_text(start),
1162 span: self.node_span(start),
1163 pos,
1164 }
1165 },
1166 TemplateBodyDecl::Choice,
1167 )
1168 }
1169 Some("interface") => self.interface_instance_decl().map_or_else(
1170 || {
1171 self.skip_to_item_end();
1172 TemplateBodyDecl::Other {
1173 raw: self.slice_text(start),
1174 span: self.node_span(start),
1175 pos,
1176 }
1177 },
1178 TemplateBodyDecl::InterfaceInstance,
1179 ),
1180 Some("controller") => {
1181 self.diag_kind(
1185 ParseDiagnosticKind::UnsupportedSyntax(
1186 UnsupportedSyntaxKind::LegacyControllerCan,
1187 ),
1188 "legacy 'controller ... can' syntax is not supported; \
1189 choices inside this block are not analyzed",
1190 );
1191 self.skip_to_item_end();
1192 TemplateBodyDecl::Other {
1193 raw: self.slice_text(start),
1194 span: self.node_span(start),
1195 pos,
1196 }
1197 }
1198 _ => {
1199 self.skip_to_item_end();
1200 TemplateBodyDecl::Other {
1201 raw: self.slice_text(start),
1202 span: self.node_span(start),
1203 pos,
1204 }
1205 }
1206 }
1207 }
1208
1209 fn parse_choice_metadata_item(
1210 &mut self,
1211 observers: &mut Vec<Expr>,
1212 controllers: &mut Vec<Expr>,
1213 authority_exprs: &mut Vec<Expr>,
1214 ) -> bool {
1215 if self.eat_keyword("observer") {
1216 *observers = self.expr_comma_list_no_do();
1217 true
1218 } else if self.eat_keyword("controller") {
1219 *controllers = self.expr_comma_list_no_do();
1220 true
1221 } else if self.eat_keyword("authority") {
1222 *authority_exprs = self.expr_comma_list_no_do();
1223 true
1224 } else {
1225 false
1226 }
1227 }
1228
1229 fn choice_metadata_block(
1230 &mut self,
1231 observers: &mut Vec<Expr>,
1232 controllers: &mut Vec<Expr>,
1233 authority_exprs: &mut Vec<Expr>,
1234 ) {
1235 loop {
1236 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1237 match self.peek() {
1238 None => break,
1239 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1240 self.bump();
1241 break;
1242 }
1243 Some(TokenKind::RParen | TokenKind::RBracket) => {
1244 self.bump();
1245 continue;
1246 }
1247 _ => {}
1248 }
1249 if !self.parse_choice_metadata_item(observers, controllers, authority_exprs) {
1250 self.skip_to_item_end();
1251 }
1252 }
1253 }
1254
1255 fn choice_decl(&mut self) -> Option<ChoiceDecl> {
1256 let pos = self.pos();
1257 let start_i = self.i;
1258 let consuming = match self.peek().and_then(|t| t.keyword()) {
1259 Some("nonconsuming") => {
1260 self.bump();
1261 Consuming::NonConsuming
1262 }
1263 Some("preconsuming") => {
1264 self.bump();
1265 Consuming::PreConsuming
1266 }
1267 Some("postconsuming") => {
1268 self.bump();
1269 Consuming::PostConsuming
1270 }
1271 _ => Consuming::Consuming,
1272 };
1273 if !self.eat_keyword("choice") {
1274 return None;
1275 }
1276 let name = self.upper_name()?.to_string().into();
1277 let return_ty = if self.eat_op(":") {
1278 let ty_start = self.i;
1279 self.skip_type_tokens();
1280 self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Choice)
1281 } else {
1282 TypeAnnotation::Absent
1283 };
1284 let (params, dangling) = if self.eat_keyword("with") {
1285 let parsed = self.field_block();
1286 (parsed.fields, parsed.dangling)
1287 } else {
1288 (Vec::new(), false)
1289 };
1290 let mut observers = Vec::new();
1291 let mut controllers = Vec::new();
1292 let mut authority_exprs = Vec::new();
1293 if self.eat_keyword("where") {
1294 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
1295 self.choice_metadata_block(&mut observers, &mut controllers, &mut authority_exprs);
1296 }
1297 } else {
1298 loop {
1299 if dangling {
1303 while self.eat(&TokenKind::VSemi) {}
1304 }
1305 if !self.parse_choice_metadata_item(
1306 &mut observers,
1307 &mut controllers,
1308 &mut authority_exprs,
1309 ) {
1310 break;
1311 }
1312 }
1313 }
1314 if dangling {
1315 while self.eat(&TokenKind::VSemi) {}
1316 }
1317 let body = if self.peek().is_some_and(|t| {
1318 !matches!(
1319 t,
1320 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace
1321 )
1322 }) {
1323 Some(self.expr())
1324 } else {
1325 None
1326 };
1327 self.skip_to_item_end();
1328 if dangling {
1329 self.eat(&TokenKind::VRBrace);
1332 self.skip_to_item_end();
1333 }
1334 Some(ChoiceDecl {
1335 name,
1336 consuming,
1337 return_ty,
1338 params,
1339 controllers,
1340 observers,
1341 authority_exprs,
1342 body,
1343 pos,
1344 span: self.node_span(start_i),
1345 })
1346 }
1347
1348 fn skip_type_tokens(&mut self) {
1351 let mut brackets = 0usize;
1352 while let Some(t) = self.peek() {
1353 match t {
1354 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::VLBrace | TokenKind::Semi => {
1355 return
1356 }
1357 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1358 TokenKind::RParen | TokenKind::RBracket => {
1359 if brackets == 0 {
1360 return;
1361 }
1362 brackets -= 1;
1363 }
1364 _ if brackets == 0
1365 && matches!(
1366 t.keyword(),
1367 Some("with" | "controller" | "observer" | "authority" | "do" | "where")
1368 ) =>
1369 {
1370 return
1371 }
1372 _ => {}
1373 }
1374 self.i += 1;
1375 }
1376 }
1377
1378 fn interface_decl(&mut self) -> Option<InterfaceDecl> {
1381 let pos = self.pos();
1382 let start_i = self.i;
1383 self.bump(); if self.at_keyword("instance") {
1385 return None;
1387 }
1388 let name = self.upper_name()?.to_string().into();
1389 let mut requires = Vec::new();
1390 if self.eat_keyword("requires") {
1391 while let Some(r) = self.upper_name() {
1392 requires.push(r);
1393 if !self.eat(&TokenKind::Comma) {
1394 break;
1395 }
1396 }
1397 }
1398 if !self.eat_keyword("where") {
1399 return None;
1400 }
1401 let mut viewtype = None;
1402 let mut methods = Vec::new();
1403 let mut choices = Vec::new();
1404 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1405 return Some(InterfaceDecl {
1406 name,
1407 requires,
1408 viewtype,
1409 methods,
1410 choices,
1411 pos,
1412 span: self.node_span(start_i),
1413 });
1414 }
1415 loop {
1416 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1417 match self.peek() {
1418 None => break,
1419 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1420 self.bump();
1421 break;
1422 }
1423 Some(TokenKind::RParen | TokenKind::RBracket) => {
1428 self.bump();
1429 continue;
1430 }
1431 _ => {}
1432 }
1433 match self.peek().and_then(|t| t.keyword()) {
1434 Some("viewtype") => {
1435 self.bump();
1436 viewtype = self.upper_name();
1437 self.skip_to_item_end();
1438 }
1439 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1440 if let Some(c) = self.choice_decl() {
1441 choices.push(c);
1442 } else {
1443 self.skip_to_item_end();
1444 }
1445 }
1446 _ => {
1447 let mpos = self.pos();
1450 if let Some(TokenKind::LowerId {
1451 qualifier: None,
1452 name: mname,
1453 }) = self.peek().cloned()
1454 {
1455 if self.peek_at(1).is_some_and(|t| t.is_op(":")) {
1456 let mstart = self.toks[self.i].start;
1457 self.bump();
1458 self.bump();
1459 let ty_start = self.i;
1460 self.skip_to_item_end();
1461 methods.push(FieldDecl {
1463 name: mname,
1464 ty: self.parse_type_annotation(
1465 ty_start,
1466 self.i,
1467 TypeAnnotationContext::InterfaceMethod,
1468 ),
1469 pos: mpos,
1470 span: Span::from_usize(mstart, self.end_byte().max(mstart)),
1471 });
1472 continue;
1473 }
1474 }
1475 self.skip_to_item_end();
1476 }
1477 }
1478 }
1479 Some(InterfaceDecl {
1480 name,
1481 requires,
1482 viewtype,
1483 methods,
1484 choices,
1485 pos,
1486 span: self.node_span(start_i),
1487 })
1488 }
1489
1490 fn interface_instance_decl(&mut self) -> Option<InterfaceInstanceDecl> {
1492 let pos = self.pos();
1493 let start_i = self.i;
1494 self.bump(); if !self.eat_keyword("instance") {
1496 return None;
1497 }
1498 let interface_name = self.upper_name()?;
1499 let for_template = if self.eat_keyword("for") {
1500 self.upper_name().map_or_else(
1501 || {
1502 self.diag_expected(
1503 ExpectedToken::TemplateNameAfterInterfaceInstanceFor,
1504 "interface instance missing template name after 'for'",
1505 );
1506 None
1507 },
1508 Some,
1509 )
1510 } else {
1511 None
1512 };
1513 let mut items = Vec::new();
1514 if self.eat_keyword("where")
1515 && (self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace))
1516 {
1517 loop {
1518 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1519 match self.peek() {
1520 None => break,
1521 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1522 self.bump();
1523 break;
1524 }
1525 Some(TokenKind::RParen | TokenKind::RBracket) => {
1527 self.bump();
1528 continue;
1529 }
1530 _ => {}
1531 }
1532 if let Some(item) = self.interface_instance_body_item() {
1533 items.push(item);
1534 } else {
1535 self.skip_to_item_end();
1536 }
1537 }
1538 }
1539 Some(InterfaceInstanceDecl {
1540 interface_name,
1541 for_template,
1542 items,
1543 pos,
1544 span: self.node_span(start_i),
1545 })
1546 }
1547
1548 fn interface_instance_body_item(&mut self) -> Option<InterfaceInstanceBodyItem> {
1550 let pos = self.pos();
1551 let start_i = self.i;
1552 if self.at_keyword("view") && self.peek_at(1).is_some_and(|t| t.is_op("=")) {
1553 self.bump(); self.bump(); let expr = self.expr();
1556 self.skip_to_item_end();
1557 return Some(InterfaceInstanceBodyItem::View {
1558 expr,
1559 pos,
1560 span: self.node_span(start_i),
1561 });
1562 }
1563 self.binding().map(InterfaceInstanceBodyItem::Method)
1564 }
1565
1566 fn fixity_decl(&mut self) -> Option<FixityDecl> {
1569 let pos = self.pos();
1570 let start_i = self.i;
1571 let assoc = match self.peek() {
1572 Some(t) if t.is_keyword("infixr") => FixityAssoc::InfixR,
1573 Some(t) if t.is_keyword("infixl") => FixityAssoc::InfixL,
1574 Some(t) if t.is_keyword("infix") => FixityAssoc::Infix,
1575 _ => return None,
1576 };
1577 self.bump();
1578 let precedence = match self.peek() {
1579 Some(TokenKind::IntLit(n)) => {
1580 let parsed: u8 = n.parse().ok()?;
1581 self.bump();
1582 parsed
1583 }
1584 _ => {
1585 self.diag_malformed(
1586 MalformedSyntaxKind::FunctionEquation,
1587 "expected precedence number in fixity declaration",
1588 );
1589 return None;
1590 }
1591 };
1592 let mut operators = Vec::new();
1593 loop {
1594 match self.peek().cloned() {
1595 Some(TokenKind::Backtick) => {
1596 self.bump();
1597 let name = match self.peek().cloned() {
1598 Some(
1599 TokenKind::LowerId {
1600 qualifier: None,
1601 name,
1602 }
1603 | TokenKind::UpperId {
1604 qualifier: None,
1605 name,
1606 },
1607 ) => {
1608 self.bump();
1609 name
1610 }
1611 _ => {
1612 self.diag_malformed(
1613 MalformedSyntaxKind::FunctionEquation,
1614 "expected identifier in backtick fixity target",
1615 );
1616 return None;
1617 }
1618 };
1619 if !self.eat(&TokenKind::Backtick) {
1620 self.diag_malformed(
1621 MalformedSyntaxKind::FunctionEquation,
1622 "expected closing backtick in fixity declaration",
1623 );
1624 return None;
1625 }
1626 operators.push(FixityTarget::Backtick(name));
1627 }
1628 Some(TokenKind::Op(op)) if !is_reserved_op(&op) => {
1629 self.bump();
1630 operators.push(FixityTarget::Operator(op));
1631 }
1632 _ => break,
1633 }
1634 if !self.eat(&TokenKind::Comma) {
1635 break;
1636 }
1637 }
1638 if operators.is_empty() {
1639 self.diag_malformed(
1640 MalformedSyntaxKind::FunctionEquation,
1641 "fixity declaration must name at least one operator",
1642 );
1643 return None;
1644 }
1645 self.skip_to_item_end();
1646 Some(FixityDecl {
1647 assoc,
1648 precedence,
1649 operators,
1650 pos,
1651 span: self.node_span(start_i),
1652 })
1653 }
1654
1655 fn operator_function_item(&mut self) -> Option<Decl> {
1657 let pos = self.pos();
1658 let start_i = self.i;
1659 if !self.eat(&TokenKind::LParen) {
1660 return None;
1661 }
1662 let Some(TokenKind::Op(op)) = self.peek().cloned() else {
1663 return None;
1664 };
1665 if is_reserved_op(&op) {
1666 return None;
1667 }
1668 self.bump();
1669 if !self.eat(&TokenKind::RParen) {
1670 return None;
1671 }
1672 let name = Identifier::from(op.as_str());
1673
1674 if self.at_op(":") {
1675 self.eat_op(":");
1676 let ty_start = self.i;
1677 self.skip_to_item_end();
1678 let ty = self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Function);
1679 return Some(Decl::Function(FunctionDecl {
1680 name,
1681 ty,
1682 equations: Vec::new(),
1683 pos,
1684 sig_span: Some(self.node_span(start_i)),
1685 span: self.node_span(start_i),
1686 }));
1687 }
1688
1689 if self.at_op("=") || self.at_op("|") {
1690 let (body, guards) = self.equation_rhs()?;
1691 let where_bindings = if self.eat_keyword("where") {
1692 self.binding_block()
1693 } else {
1694 Vec::new()
1695 };
1696 self.skip_to_item_end();
1697 return Some(Decl::Function(FunctionDecl {
1698 name,
1699 ty: TypeAnnotation::Absent,
1700 equations: vec![Equation {
1701 params: Vec::new(),
1702 body,
1703 guards,
1704 where_bindings,
1705 pos,
1706 span: self.node_span(start_i),
1707 }],
1708 pos,
1709 sig_span: None,
1710 span: self.node_span(start_i),
1711 }));
1712 }
1713
1714 None
1715 }
1716
1717 fn try_infix_operator_function(&mut self) -> Option<Decl> {
1718 let pos = self.pos();
1719 let start_i = self.i;
1720 let Some(TokenKind::LowerId {
1721 qualifier: None,
1722 name: lhs,
1723 }) = self.peek().cloned()
1724 else {
1725 return None;
1726 };
1727 let lhs_start = self.i;
1728 self.bump();
1729 let Some(TokenKind::Op(op)) = self.peek().cloned() else {
1730 return None;
1731 };
1732 if is_reserved_op(&op) {
1733 return None;
1734 }
1735 self.bump();
1736 let rhs_start = self.i;
1737 let Some(TokenKind::LowerId {
1738 qualifier: None,
1739 name: rhs,
1740 }) = self.peek().cloned()
1741 else {
1742 return None;
1743 };
1744 self.bump();
1745 if !(self.at_op("=") || self.at_op("|")) {
1746 return None;
1747 }
1748 let name = Identifier::from(op.as_str());
1749 let lhs_pat = Pat::Var {
1750 name: lhs,
1751 pos: self.pos_of_token(lhs_start),
1752 span: self.node_span(lhs_start),
1753 };
1754 let rhs_pat = Pat::Var {
1755 name: rhs,
1756 pos: self.pos_of_token(rhs_start),
1757 span: self.node_span(rhs_start),
1758 };
1759 let (body, guards) = self.equation_rhs()?;
1760 let where_bindings = if self.eat_keyword("where") {
1761 self.binding_block()
1762 } else {
1763 Vec::new()
1764 };
1765 self.skip_to_item_end();
1766 Some(Decl::Function(FunctionDecl {
1767 name,
1768 ty: TypeAnnotation::Absent,
1769 equations: vec![Equation {
1770 params: vec![lhs_pat, rhs_pat],
1771 body,
1772 guards,
1773 where_bindings,
1774 pos,
1775 span: self.node_span(start_i),
1776 }],
1777 pos,
1778 sig_span: None,
1779 span: self.node_span(start_i),
1780 }))
1781 }
1782
1783 fn function_item(&mut self) -> Option<Decl> {
1787 let snap = self.i;
1788 let saved_diags = self.diags.len();
1789 if let Some(decl) = self.try_infix_operator_function() {
1790 return Some(decl);
1791 }
1792 self.i = snap;
1793 self.diags.truncate(saved_diags);
1794
1795 let pos = self.pos();
1796 let start_i = self.i;
1797 let Some(TokenKind::LowerId {
1798 qualifier: None,
1799 name,
1800 }) = self.peek().cloned()
1801 else {
1802 return None;
1803 };
1804
1805 let mut j = self.i + 1;
1807 let mut is_sig = false;
1808 loop {
1809 match self.toks.get(j).map(|t| &t.kind) {
1810 Some(TokenKind::Comma) => {
1811 j += 1;
1812 if matches!(
1813 self.toks.get(j).map(|t| &t.kind),
1814 Some(TokenKind::LowerId {
1815 qualifier: None,
1816 ..
1817 })
1818 ) {
1819 j += 1;
1820 continue;
1821 }
1822 break;
1823 }
1824 Some(TokenKind::Op(o)) if o.as_str() == ":" => {
1825 is_sig = true;
1826 break;
1827 }
1828 _ => break,
1829 }
1830 }
1831 if is_sig {
1832 self.bump(); while self.eat(&TokenKind::Comma) {
1834 self.bump(); }
1836 self.eat_op(":");
1837 let ty_start = self.i;
1838 self.skip_to_item_end();
1839 let ty = self.parse_type_annotation(ty_start, self.i, TypeAnnotationContext::Function);
1840 return Some(Decl::Function(FunctionDecl {
1841 name,
1842 ty,
1843 equations: Vec::new(),
1844 pos,
1845 sig_span: Some(self.node_span(start_i)),
1846 span: self.node_span(start_i),
1847 }));
1848 }
1849
1850 self.bump(); let mut params = Vec::new();
1853 while !self.at_op("=") && !self.at_op("|") {
1854 if self.at_op(":") {
1857 self.bump();
1858 let mut brackets = 0usize;
1859 while let Some(t) = self.peek() {
1860 match t {
1861 TokenKind::Op(o) if o.as_str() == "=" && brackets == 0 => break,
1862 TokenKind::VSemi
1863 | TokenKind::VRBrace
1864 | TokenKind::Semi
1865 | TokenKind::RBrace => break,
1866 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1867 TokenKind::RParen | TokenKind::RBracket => {
1868 brackets = brackets.saturating_sub(1)
1869 }
1870 _ => {}
1871 }
1872 self.i += 1;
1873 }
1874 continue;
1875 }
1876 if matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o)) {
1879 self.skip_to_item_end();
1880 return None;
1881 }
1882 match self.peek() {
1883 None
1884 | Some(
1885 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace,
1886 ) => {
1887 self.diag_malformed(
1888 MalformedSyntaxKind::FunctionEquation,
1889 format!("could not parse equation for '{name}'"),
1890 );
1891 return None;
1892 }
1893 _ => {}
1894 }
1895 match self.pattern_atom() {
1896 Some(p) => params.push(p),
1897 None => {
1898 self.diag_malformed(
1899 MalformedSyntaxKind::FunctionParameterPattern,
1900 format!("bad parameter pattern in '{name}'"),
1901 );
1902 return None;
1903 }
1904 }
1905 }
1906 let (body, guards) = self.equation_rhs()?;
1907 let where_bindings = if self.eat_keyword("where") {
1908 self.binding_block()
1909 } else {
1910 Vec::new()
1911 };
1912 self.skip_to_item_end();
1913 Some(Decl::Function(FunctionDecl {
1914 name,
1915 ty: TypeAnnotation::Absent,
1916 equations: vec![Equation {
1917 params,
1918 body,
1919 guards,
1920 where_bindings,
1921 pos,
1922 span: self.node_span(start_i),
1923 }],
1924 pos,
1925 sig_span: None,
1926 span: self.node_span(start_i),
1927 }))
1928 }
1929
1930 fn equation_rhs(&mut self) -> Option<(Expr, Vec<(Expr, Expr)>)> {
1932 if self.eat_op("=") {
1933 return Some((self.expr(), Vec::new()));
1934 }
1935 let mut guards = Vec::new();
1936 while self.eat_op("|") {
1937 let g = loop {
1940 let g = self.expr();
1941 if self.eat_op("<-") {
1942 let _ = self.expr(); }
1944 if !self.eat(&TokenKind::Comma) {
1945 break g;
1946 }
1947 };
1948 if !self.eat_op("=") {
1949 self.diag_expected(ExpectedToken::EqualsAfterGuard, "expected '=' after guard");
1950 return None;
1951 }
1952 let e = self.expr();
1953 guards.push((g, e));
1954 }
1955 if guards.is_empty() {
1956 self.diag_expected(
1957 ExpectedToken::EqualsOrGuardedRightHandSide,
1958 "expected '=' or guarded right-hand side in equation",
1959 );
1960 None
1961 } else {
1962 let first = guards[0].1.clone();
1963 Some((first, guards))
1964 }
1965 }
1966
1967 fn binding_block(&mut self) -> Vec<Binding> {
1969 let mut bindings = Vec::new();
1970 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1971 return bindings;
1972 }
1973 loop {
1974 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1975 match self.peek() {
1976 None => break,
1977 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1978 self.bump();
1979 break;
1980 }
1981 Some(TokenKind::RParen | TokenKind::RBracket) => {
1986 self.bump();
1987 continue;
1988 }
1989 _ => {}
1990 }
1991 match self.binding() {
1992 Some(b) => bindings.push(b),
1993 None => self.skip_to_item_end(),
1994 }
1995 }
1996 bindings
1997 }
1998
1999 fn binding(&mut self) -> Option<Binding> {
2002 let pos = self.pos();
2003 let start_i = self.i;
2004 if self.at(&TokenKind::LParen)
2007 && matches!(self.peek_at(1), Some(TokenKind::Op(_)))
2008 && self.peek_at(2) == Some(&TokenKind::RParen)
2009 {
2010 self.skip_to_item_end();
2011 return None;
2012 }
2013 let pat = self.pattern_atom()?;
2014 let mut params = Vec::new();
2015 loop {
2016 if self.at_op("=") {
2017 self.bump();
2018 let expr = self.expr();
2019 if self.eat_keyword("where") {
2021 let _ = self.binding_block();
2022 }
2023 return Some(Binding {
2024 pat,
2025 params,
2026 expr,
2027 pos,
2028 span: self.node_span(start_i),
2029 });
2030 }
2031 if self.at_op("|") {
2032 let (body, _) = self.equation_rhs()?;
2033 if self.eat_keyword("where") {
2034 let _ = self.binding_block();
2035 }
2036 return Some(Binding {
2037 pat,
2038 params,
2039 expr: body,
2040 pos,
2041 span: self.node_span(start_i),
2042 });
2043 }
2044 if self.at_op(":") {
2045 if params.is_empty() {
2046 self.skip_to_item_end();
2048 return None;
2049 }
2050 self.bump();
2053 let mut brackets = 0usize;
2054 while let Some(t) = self.peek() {
2055 match t {
2056 TokenKind::Op(o) if o.as_str() == "=" && brackets == 0 => break,
2057 TokenKind::VSemi
2058 | TokenKind::VRBrace
2059 | TokenKind::Semi
2060 | TokenKind::RBrace => break,
2061 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
2062 TokenKind::RParen | TokenKind::RBracket => {
2063 brackets = brackets.saturating_sub(1)
2064 }
2065 _ => {}
2066 }
2067 self.i += 1;
2068 }
2069 continue;
2070 }
2071 if matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o)) {
2074 self.skip_to_item_end();
2075 return None;
2076 }
2077 match self.peek() {
2078 None
2079 | Some(
2080 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace,
2081 ) => return None,
2082 _ => {}
2083 }
2084 params.push(self.pattern_atom()?);
2085 }
2086 }
2087
2088 fn pattern_atom(&mut self) -> Option<Pat> {
2091 if self.depth >= MAX_RECURSION_DEPTH {
2092 return None;
2093 }
2094 self.depth += 1;
2095 let result = self.pattern_atom_inner();
2096 self.depth -= 1;
2097 result
2098 }
2099
2100 fn pattern_atom_inner(&mut self) -> Option<Pat> {
2101 let pos = self.pos();
2102 let start_i = self.i;
2103 if self.at_op("~") || self.at_op("!") {
2105 self.bump();
2106 return self.pattern_atom();
2107 }
2108 match self.peek().cloned() {
2109 Some(TokenKind::LowerId {
2110 qualifier: None,
2111 name,
2112 }) => {
2113 self.bump();
2114 if name == "_" {
2115 return Some(Pat::Wild {
2116 pos,
2117 span: self.node_span(start_i),
2118 });
2119 }
2120 if self.at_op("@") {
2121 self.bump();
2122 let inner = self.pattern_atom()?;
2123 return Some(Pat::As {
2124 name,
2125 pat: Box::new(inner),
2126 pos,
2127 span: self.node_span(start_i),
2128 });
2129 }
2130 Some(Pat::Var {
2131 name,
2132 pos,
2133 span: self.node_span(start_i),
2134 })
2135 }
2136 Some(TokenKind::Op(o)) if o.as_str() == "_" => {
2137 self.bump();
2138 Some(Pat::Wild {
2139 pos,
2140 span: self.node_span(start_i),
2141 })
2142 }
2143 Some(TokenKind::UpperId { qualifier, name }) => {
2144 self.bump();
2145 if let Some(record) =
2146 self.try_parse_record_pattern(qualifier.clone(), name.clone(), pos, start_i)
2147 {
2148 return Some(record);
2149 }
2150 Some(Pat::Con {
2151 qualifier,
2152 name,
2153 args: Vec::new(),
2154 pos,
2155 span: self.node_span(start_i),
2156 })
2157 }
2158 Some(TokenKind::IntLit(text)) => {
2159 self.bump();
2160 Some(Pat::Lit {
2161 kind: LitKind::Int,
2162 text,
2163 pos,
2164 span: self.node_span(start_i),
2165 })
2166 }
2167 Some(TokenKind::DecimalLit(text)) => {
2168 self.bump();
2169 Some(Pat::Lit {
2170 kind: LitKind::Decimal,
2171 text,
2172 pos,
2173 span: self.node_span(start_i),
2174 })
2175 }
2176 Some(TokenKind::StringLit(text)) => {
2177 self.bump();
2178 Some(Pat::Lit {
2179 kind: LitKind::Text,
2180 text,
2181 pos,
2182 span: self.node_span(start_i),
2183 })
2184 }
2185 Some(TokenKind::CharLit(text)) => {
2186 self.bump();
2187 Some(Pat::Lit {
2188 kind: LitKind::Char,
2189 text,
2190 pos,
2191 span: self.node_span(start_i),
2192 })
2193 }
2194 Some(TokenKind::LParen) => {
2195 self.bump();
2196 if self.eat(&TokenKind::RParen) {
2197 return Some(Pat::Con {
2198 qualifier: None,
2199 name: "()".into(),
2200 args: Vec::new(),
2201 pos,
2202 span: self.node_span(start_i),
2203 });
2204 }
2205 {
2211 let mut depth = 0usize;
2212 let mut j = self.i;
2213 let mut arrow = None;
2214 while let Some(t) = self.toks.get(j).map(|t| &t.kind) {
2215 match t {
2216 TokenKind::LParen | TokenKind::LBracket => depth += 1,
2217 TokenKind::RParen | TokenKind::RBracket => {
2218 if depth == 0 {
2219 break;
2220 }
2221 depth -= 1;
2222 }
2223 TokenKind::Op(o) if o.as_str() == ":" && depth == 0 => break,
2224 TokenKind::Op(o) if o.as_str() == "->" && depth == 0 => {
2225 arrow = Some(j);
2226 break;
2227 }
2228 TokenKind::VSemi | TokenKind::VRBrace => break,
2229 TokenKind::Op(o) if o.as_str() == "\\" => break,
2231 _ => {}
2232 }
2233 j += 1;
2234 }
2235 if let Some(j) = arrow {
2236 self.i = j + 1; let inner = self.pattern()?;
2238 self.eat(&TokenKind::RParen);
2239 return Some(inner);
2240 }
2241 }
2242 let first = self.pattern()?;
2243 if self.at_op(":") {
2245 let mut depth = 0usize;
2246 while let Some(t) = self.peek() {
2247 match t {
2248 TokenKind::LParen | TokenKind::LBracket => depth += 1,
2249 TokenKind::RParen if depth == 0 => break,
2250 TokenKind::RParen | TokenKind::RBracket => {
2251 depth = depth.saturating_sub(1)
2252 }
2253 TokenKind::VSemi | TokenKind::VRBrace => break,
2254 _ => {}
2255 }
2256 self.i += 1;
2257 }
2258 }
2259 if self.at(&TokenKind::Comma) {
2260 let mut items = vec![first];
2261 while self.eat(&TokenKind::Comma) {
2262 items.push(self.pattern()?);
2263 }
2264 self.eat(&TokenKind::RParen);
2265 return Some(Pat::Tuple {
2266 items,
2267 pos,
2268 span: self.node_span(start_i),
2269 });
2270 }
2271 self.eat(&TokenKind::RParen);
2272 Some(first)
2273 }
2274 Some(TokenKind::LBracket) => {
2275 self.bump();
2276 let mut items = Vec::new();
2277 if !self.eat(&TokenKind::RBracket) {
2278 loop {
2279 items.push(self.pattern()?);
2280 if !self.eat(&TokenKind::Comma) {
2281 break;
2282 }
2283 }
2284 self.eat(&TokenKind::RBracket);
2285 }
2286 Some(Pat::List {
2287 items,
2288 pos,
2289 span: self.node_span(start_i),
2290 })
2291 }
2292 _ => None,
2293 }
2294 }
2295
2296 fn pattern(&mut self) -> Option<Pat> {
2298 if self.depth >= MAX_RECURSION_DEPTH {
2299 return None;
2300 }
2301 self.depth += 1;
2302 let result = self.pattern_inner();
2303 self.depth -= 1;
2304 result
2305 }
2306
2307 fn pattern_inner(&mut self) -> Option<Pat> {
2308 let pos = self.pos();
2309 let start_i = self.i;
2310 let first = match self.peek().cloned() {
2311 Some(TokenKind::UpperId { qualifier, name }) => {
2312 self.bump();
2313 self.try_parse_record_pattern(qualifier.clone(), name.clone(), pos, start_i)
2314 .unwrap_or_else(|| {
2315 let mut args = Vec::new();
2316 while let Some(a) = self.try_pattern_atom() {
2317 args.push(a);
2318 }
2319 Pat::Con {
2320 qualifier,
2321 name,
2322 args,
2323 pos,
2324 span: self.node_span(start_i),
2325 }
2326 })
2327 }
2328 _ => self.pattern_atom()?,
2329 };
2330 if self.at_op("::") {
2331 self.bump();
2332 let rest = self.pattern()?;
2333 return Some(Pat::Con {
2334 qualifier: None,
2335 name: "::".into(),
2336 args: vec![first, rest],
2337 pos,
2338 span: self.node_span(start_i),
2339 });
2340 }
2341 Some(first)
2342 }
2343
2344 fn try_pattern_atom(&mut self) -> Option<Pat> {
2345 match self.peek() {
2346 Some(
2347 TokenKind::LowerId {
2348 qualifier: None, ..
2349 }
2350 | TokenKind::UpperId { .. }
2351 | TokenKind::IntLit(_)
2352 | TokenKind::DecimalLit(_)
2353 | TokenKind::StringLit(_)
2354 | TokenKind::CharLit(_)
2355 | TokenKind::LParen
2356 | TokenKind::LBracket,
2357 ) => self.pattern_atom(),
2358 _ => None,
2359 }
2360 }
2361
2362 fn expr(&mut self) -> Expr {
2365 self.expr_prec(0, DoExpressionMode::Allow)
2366 }
2367
2368 fn expr_no_do(&mut self) -> Expr {
2369 self.expr_prec(0, DoExpressionMode::Disallow)
2370 }
2371
2372 fn expr_comma_list(&mut self) -> Vec<Expr> {
2374 let mut out = vec![self.expr()];
2375 while self.eat(&TokenKind::Comma) {
2376 out.push(self.expr());
2377 }
2378 out
2379 }
2380
2381 fn expr_comma_list_no_do(&mut self) -> Vec<Expr> {
2382 let mut out = vec![self.expr_no_do()];
2383 while self.eat(&TokenKind::Comma) {
2384 out.push(self.expr_no_do());
2385 }
2386 out
2387 }
2388
2389 fn expr_prec(&mut self, min_prec: u8, do_mode: DoExpressionMode) -> Expr {
2390 let pos = self.pos();
2391 let start_i = self.i;
2392 if self.depth >= MAX_RECURSION_DEPTH {
2393 self.diag_kind(
2398 ParseDiagnosticKind::RecursionLimit {
2399 limit: MAX_RECURSION_DEPTH,
2400 },
2401 "expression nesting too deep; truncated to raw text",
2402 );
2403 let start = self.i;
2404 self.skip_to_item_end();
2405 if self.i == start {
2406 self.bump();
2407 }
2408 return Expr::Error {
2409 raw: self.slice_text(start),
2410 span: self.node_span(start),
2411 pos,
2412 };
2413 }
2414 self.depth += 1;
2415 let result = self.expr_prec_inner(min_prec, do_mode, pos, start_i);
2416 self.depth -= 1;
2417 result
2418 }
2419
2420 fn expr_prec_inner(
2421 &mut self,
2422 min_prec: u8,
2423 do_mode: DoExpressionMode,
2424 pos: Pos,
2425 start_i: usize,
2426 ) -> Expr {
2427 let Some(mut lhs) = self.unary(do_mode) else {
2428 let start = self.i;
2430 self.skip_to_item_end();
2431 if self.i == start {
2432 self.bump();
2433 }
2434 return Expr::Error {
2435 raw: self.slice_text(start),
2436 span: self.node_span(start),
2437 pos,
2438 };
2439 };
2440 loop {
2441 let (op, prec, right_assoc) = match self.peek() {
2442 Some(TokenKind::Op(o)) => {
2443 let o = o.clone();
2444 if is_reserved_op(&o) {
2445 if o == ":" {
2447 self.bump();
2448 self.skip_type_tokens();
2449 continue;
2450 }
2451 break;
2452 }
2453 let (p, r) = self.lookup_fixity(&o);
2454 (o, p, r)
2455 }
2456 Some(TokenKind::Backtick) => {
2457 let name = match self.peek_at(1) {
2459 Some(
2460 TokenKind::LowerId { qualifier, name }
2461 | TokenKind::UpperId { qualifier, name },
2462 ) => qualifier
2463 .as_ref()
2464 .map_or_else(|| name.to_string(), |q| format!("{q}.{name}")),
2465 _ => break,
2466 };
2467 if self.peek_at(2) != Some(&TokenKind::Backtick) {
2468 break;
2469 }
2470 let op_key = format!("`{name}`");
2471 let (p, r) = self.fixity_env.get(&op_key).copied().unwrap_or((9, false));
2472 (op_key.into(), p, r)
2473 }
2474 _ => break,
2475 };
2476 if prec < min_prec {
2477 break;
2478 }
2479 self.bump();
2480 if op.starts_with('`') {
2481 self.bump();
2482 self.bump();
2483 }
2484 let next_min = if right_assoc { prec } else { prec + 1 };
2485 let rhs = self.expr_prec(next_min, do_mode);
2486 lhs = Expr::BinOp {
2487 op,
2488 lhs: Box::new(lhs),
2489 rhs: Box::new(rhs),
2490 pos,
2491 span: self.node_span(start_i),
2492 };
2493 }
2494 lhs
2495 }
2496
2497 fn unary(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2498 let pos = self.pos();
2499 let start_i = self.i;
2500 if self.at_op("-") {
2501 self.bump();
2502 let e = self.unary(do_mode)?;
2503 return Some(Expr::Neg {
2504 expr: Box::new(e),
2505 pos,
2506 span: self.node_span(start_i),
2507 });
2508 }
2509 self.application(do_mode)
2510 }
2511
2512 fn application(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2513 let pos = self.pos();
2514 let start_i = self.i;
2515 let head0 = self.atom(do_mode)?;
2516 let mut head = self.projection_tail(head0);
2517 let mut args = Vec::new();
2518 loop {
2519 if self.at_keyword("with") {
2522 let target = args.pop().unwrap_or_else(|| {
2523 std::mem::replace(
2524 &mut head,
2525 Expr::Error {
2526 raw: String::new(),
2527 pos,
2528 span: Span::default(),
2529 },
2530 )
2531 });
2532 self.bump(); let fields = self.record_fields();
2534 let tpos = target.pos();
2535 let sp = Span::from_usize(target.span().start_usize(), self.end_byte());
2536 let rec = Expr::Record {
2537 base: Box::new(target),
2538 fields,
2539 pos: tpos,
2540 span: sp,
2541 };
2542 if matches!(head, Expr::Error { ref raw, .. } if raw.is_empty()) {
2543 head = rec;
2544 } else {
2545 args.push(rec);
2546 }
2547 continue;
2548 }
2549 if !do_mode.allows_do() && self.at_keyword("do") {
2550 break;
2551 }
2552 if self.at_op("@") {
2554 self.bump();
2555 match self.peek() {
2556 Some(TokenKind::UpperId { .. } | TokenKind::LowerId { .. }) => {
2557 self.bump();
2558 }
2559 Some(TokenKind::LParen) => self.skip_balanced_parens(),
2560 Some(TokenKind::LBracket) => {
2561 let mut depth = 0usize;
2562 while let Some(t) = self.peek() {
2563 match t {
2564 TokenKind::LBracket => depth += 1,
2565 TokenKind::RBracket => {
2566 if depth == 0 {
2567 break;
2568 }
2569 depth -= 1;
2570 if depth == 0 {
2571 self.i += 1;
2572 break;
2573 }
2574 }
2575 _ => {}
2576 }
2577 self.i += 1;
2578 }
2579 }
2580 _ => {}
2581 }
2582 continue;
2583 }
2584 match self.try_atom(do_mode) {
2585 Some(a) => args.push(self.projection_tail(a)),
2586 None => break,
2587 }
2588 }
2589 if args.is_empty() {
2590 Some(head)
2591 } else {
2592 Some(Expr::App {
2593 func: Box::new(head),
2594 args,
2595 pos,
2596 span: self.node_span(start_i),
2597 })
2598 }
2599 }
2600
2601 fn record_fields(&mut self) -> Vec<FieldAssign> {
2603 let mut fields = Vec::new();
2604 let explicit = self.at(&TokenKind::LBrace);
2605 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
2606 return fields;
2607 }
2608 loop {
2609 while self.eat(&TokenKind::VSemi)
2610 || self.eat(&TokenKind::Semi)
2611 || self.eat(&TokenKind::Comma)
2612 {}
2613 match self.peek() {
2614 None => break,
2615 Some(TokenKind::VRBrace) if !explicit => {
2616 self.bump();
2617 break;
2618 }
2619 Some(TokenKind::RBrace) => {
2620 self.bump();
2621 break;
2622 }
2623 Some(TokenKind::RParen | TokenKind::RBracket) => {
2625 self.bump();
2626 continue;
2627 }
2628 _ => {}
2629 }
2630 let pos = self.pos();
2631 let start_i = self.i;
2632 if self.at_op("..") {
2633 self.bump();
2634 fields.push(FieldAssign::Wildcard {
2635 pos,
2636 span: self.node_span(start_i),
2637 });
2638 continue;
2639 }
2640 let name = match self.peek().cloned() {
2641 Some(TokenKind::LowerId {
2642 qualifier: None,
2643 name,
2644 }) => {
2645 self.bump();
2646 name
2647 }
2648 _ => {
2649 self.skip_to_item_end();
2650 continue;
2651 }
2652 };
2653 if self.eat_op("=") {
2654 let value = self.expr_prec(1, DoExpressionMode::Allow);
2655 fields.push(FieldAssign::Assign {
2656 name,
2657 value,
2658 pos,
2659 span: self.node_span(start_i),
2660 });
2661 } else {
2662 fields.push(FieldAssign::Pun {
2664 name,
2665 pos,
2666 span: self.node_span(start_i),
2667 });
2668 }
2669 }
2670 fields
2671 }
2672
2673 fn try_parse_record_pattern(
2674 &mut self,
2675 qualifier: Option<ModuleName>,
2676 name: Identifier,
2677 pos: Pos,
2678 start_i: usize,
2679 ) -> Option<Pat> {
2680 let syntax = if self.at(&TokenKind::LBrace) {
2681 RecordPatternSyntax::Braces
2682 } else if self.at_keyword("with") {
2683 self.bump();
2684 RecordPatternSyntax::With
2685 } else {
2686 return None;
2687 };
2688 let fields = self.record_pattern_fields(syntax);
2689 Some(Pat::Record {
2690 qualifier,
2691 name,
2692 syntax,
2693 fields,
2694 pos,
2695 span: self.node_span(start_i),
2696 })
2697 }
2698
2699 fn record_pattern_fields(&mut self, syntax: RecordPatternSyntax) -> Vec<PatFieldAssign> {
2701 let mut fields = Vec::new();
2702 let explicit = matches!(syntax, RecordPatternSyntax::Braces) || self.at(&TokenKind::LBrace);
2703 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
2704 return fields;
2705 }
2706 loop {
2707 while self.eat(&TokenKind::VSemi)
2708 || self.eat(&TokenKind::Semi)
2709 || self.eat(&TokenKind::Comma)
2710 {}
2711 if self.at_op("->") || self.at_op("|") {
2712 break;
2713 }
2714 match self.peek() {
2715 None => break,
2716 Some(TokenKind::VRBrace) if !explicit => {
2717 self.bump();
2718 break;
2719 }
2720 Some(TokenKind::RBrace) => {
2721 self.bump();
2722 break;
2723 }
2724 Some(TokenKind::RParen | TokenKind::RBracket) => {
2725 self.bump();
2726 continue;
2727 }
2728 _ => {}
2729 }
2730 let pos = self.pos();
2731 let start_i = self.i;
2732 if self.at_op("..") {
2733 self.bump();
2734 fields.push(PatFieldAssign::Wildcard {
2735 pos,
2736 span: self.node_span(start_i),
2737 });
2738 continue;
2739 }
2740 let name = match self.peek().cloned() {
2741 Some(TokenKind::LowerId {
2742 qualifier: None,
2743 name,
2744 }) => {
2745 self.bump();
2746 name
2747 }
2748 _ => {
2749 if self.at_op("->") || self.at_op("|") {
2750 break;
2751 }
2752 self.skip_to_item_end();
2753 continue;
2754 }
2755 };
2756 if self.eat_op("=") {
2757 let Some(pat) = self.pattern() else {
2758 self.skip_to_item_end();
2759 continue;
2760 };
2761 fields.push(PatFieldAssign::Assign {
2762 name,
2763 pat,
2764 pos,
2765 span: self.node_span(start_i),
2766 });
2767 } else {
2768 fields.push(PatFieldAssign::Pun {
2769 name,
2770 pos,
2771 span: self.node_span(start_i),
2772 });
2773 }
2774 }
2775 fields
2776 }
2777
2778 fn try_atom(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2779 match self.peek() {
2780 Some(TokenKind::LowerId { .. }) => {
2781 let kw = self.peek().and_then(|t| t.keyword());
2782 match kw {
2783 Some("do") if do_mode.allows_do() => self.atom(do_mode),
2785 Some(
2788 "if" | "case" | "do" | "let" | "try" | "where" | "then" | "else" | "of"
2789 | "in" | "controller" | "with" | "catch",
2790 ) => None,
2791 _ => self.atom(do_mode),
2792 }
2793 }
2794 Some(
2795 TokenKind::UpperId { .. }
2796 | TokenKind::IntLit(_)
2797 | TokenKind::DecimalLit(_)
2798 | TokenKind::StringLit(_)
2799 | TokenKind::CharLit(_)
2800 | TokenKind::LParen
2801 | TokenKind::LBracket,
2802 ) => self.atom(do_mode),
2803 Some(TokenKind::Op(o)) if o.as_str() == "\\" => self.atom(do_mode),
2805 _ => None,
2806 }
2807 }
2808
2809 fn projection_tail(&mut self, mut base: Expr) -> Expr {
2816 while self.at_tight_projection() {
2817 let start = base.span().start_usize();
2818 let pos = base.pos();
2819 self.bump(); let Some(field_tok) = self.bump() else {
2821 self.diag_expected(
2822 ExpectedToken::ProjectionFieldAfterDot,
2823 "expected projection field after '.'",
2824 );
2825 return base;
2826 };
2827 let TokenKind::LowerId { qualifier, name } = field_tok.kind else {
2828 self.diag_expected(
2829 ExpectedToken::ProjectionFieldAfterDot,
2830 "expected projection field after '.'",
2831 );
2832 return base;
2833 };
2834 let field = Expr::Var {
2835 qualifier,
2836 name,
2837 pos: field_tok.pos,
2838 span: Span::from_usize(field_tok.start, field_tok.end),
2839 };
2840 base = Expr::BinOp {
2841 op: ".".into(),
2842 lhs: Box::new(base),
2843 rhs: Box::new(field),
2844 pos,
2845 span: Span::from_usize(start, self.end_byte()),
2846 };
2847 }
2848 base
2849 }
2850
2851 fn at_tight_projection(&self) -> bool {
2855 if self.i == 0 {
2856 return false;
2857 }
2858 let Some(dot) = self.toks.get(self.i) else {
2859 return false;
2860 };
2861 if !matches!(&dot.kind, TokenKind::Op(o) if o.as_str() == ".") {
2862 return false;
2863 }
2864 let prev = &self.toks[self.i - 1];
2868 if prev.is_virtual() || prev.end != dot.start {
2869 return false;
2870 }
2871 self.toks.get(self.i + 1).is_some_and(|t| {
2873 matches!(
2874 &t.kind,
2875 TokenKind::LowerId {
2876 qualifier: None,
2877 ..
2878 }
2879 ) && t.start == dot.end
2880 })
2881 }
2882
2883 fn atom(&mut self, do_mode: DoExpressionMode) -> Option<Expr> {
2884 let pos = self.pos();
2885 let start_i = self.i;
2886 match self.peek().cloned() {
2887 Some(TokenKind::LowerId { qualifier, name }) => {
2888 match name.as_str() {
2889 "if" if qualifier.is_none() => return self.if_expr(),
2890 "case" if qualifier.is_none() => return self.case_expr(),
2891 "do" if qualifier.is_none() => {
2892 if !do_mode.allows_do() {
2893 return None;
2894 }
2895 return self.do_expr();
2896 }
2897 "let" if qualifier.is_none() => return self.let_expr(),
2898 "try" if qualifier.is_none() => return self.try_expr(),
2899 _ => {}
2900 }
2901 self.bump();
2902 Some(Expr::Var {
2903 qualifier,
2904 name,
2905 pos,
2906 span: self.node_span(start_i),
2907 })
2908 }
2909 Some(TokenKind::UpperId { qualifier, name }) => {
2910 self.bump();
2911 let base = Expr::Con {
2912 qualifier,
2913 name,
2914 pos,
2915 span: self.node_span(start_i),
2916 };
2917 if self.at(&TokenKind::LBrace) {
2919 let fields = self.record_fields();
2920 return Some(Expr::Record {
2921 base: Box::new(base),
2922 fields,
2923 pos,
2924 span: self.node_span(start_i),
2925 });
2926 }
2927 Some(base)
2928 }
2929 Some(TokenKind::IntLit(text)) => {
2930 self.bump();
2931 Some(Expr::Lit {
2932 kind: LitKind::Int,
2933 text,
2934 pos,
2935 span: self.node_span(start_i),
2936 })
2937 }
2938 Some(TokenKind::DecimalLit(text)) => {
2939 self.bump();
2940 Some(Expr::Lit {
2941 kind: LitKind::Decimal,
2942 text,
2943 pos,
2944 span: self.node_span(start_i),
2945 })
2946 }
2947 Some(TokenKind::StringLit(text)) => {
2948 self.bump();
2949 Some(Expr::Lit {
2950 kind: LitKind::Text,
2951 text,
2952 pos,
2953 span: self.node_span(start_i),
2954 })
2955 }
2956 Some(TokenKind::CharLit(text)) => {
2957 self.bump();
2958 Some(Expr::Lit {
2959 kind: LitKind::Char,
2960 text,
2961 pos,
2962 span: self.node_span(start_i),
2963 })
2964 }
2965 Some(TokenKind::Op(o)) if o.as_str() == "\\" => self.lambda_expr(),
2966 Some(TokenKind::LParen) => self.paren_expr(),
2967 Some(TokenKind::LBracket) => self.list_expr(),
2968 _ => None,
2969 }
2970 }
2971
2972 fn if_expr(&mut self) -> Option<Expr> {
2973 let pos = self.pos();
2974 let start_i = self.i;
2975 self.bump(); let cond = self.expr();
2977 self.eat(&TokenKind::VSemi); if !self.eat_keyword("then") {
2979 self.diag_expected(ExpectedToken::ThenKeyword, "expected 'then'");
2980 return Some(Expr::Error {
2981 raw: format!("if {}", cond.render()),
2982 pos,
2983 span: self.node_span(start_i),
2984 });
2985 }
2986 let then_branch = self.expr();
2987 self.eat(&TokenKind::VSemi);
2988 if !self.eat_keyword("else") {
2989 self.diag_expected(ExpectedToken::ElseKeyword, "expected 'else'");
2990 return Some(Expr::Error {
2991 raw: format!("if {} then {}", cond.render(), then_branch.render()),
2992 pos,
2993 span: self.node_span(start_i),
2994 });
2995 }
2996 let else_branch = self.expr();
2997 Some(Expr::If {
2998 cond: Box::new(cond),
2999 then_branch: Box::new(then_branch),
3000 else_branch: Box::new(else_branch),
3001 pos,
3002 span: self.node_span(start_i),
3003 })
3004 }
3005
3006 fn case_expr(&mut self) -> Option<Expr> {
3007 let pos = self.pos();
3008 let start_i = self.i;
3009 self.bump(); let scrutinee = self.expr_no_do();
3011 if !self.eat_keyword("of") {
3012 self.diag_expected(
3013 ExpectedToken::OfKeywordInCaseExpression,
3014 "expected 'of' in case expression",
3015 );
3016 return Some(Expr::Error {
3017 raw: format!("case {}", scrutinee.render()),
3018 pos,
3019 span: self.node_span(start_i),
3020 });
3021 }
3022 let mut alts = Vec::new();
3023 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
3024 loop {
3025 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
3026 match self.peek() {
3027 None => break,
3028 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
3029 self.bump();
3030 break;
3031 }
3032 Some(TokenKind::RParen | TokenKind::RBracket) => {
3034 self.bump();
3035 continue;
3036 }
3037 _ => {}
3038 }
3039 let alt_start = self.i;
3040 match self.case_alt() {
3041 Some(mut alt) => {
3042 if self.eat_keyword("where") {
3043 alt.where_bindings = self.binding_block();
3044 }
3045 alt.span = self.node_span(alt_start);
3046 alts.push(alt);
3047 }
3048 None => self.skip_to_item_end(),
3049 }
3050 }
3051 }
3052 Some(Expr::Case {
3053 scrutinee: Box::new(scrutinee),
3054 alts,
3055 pos,
3056 span: self.node_span(start_i),
3057 })
3058 }
3059
3060 fn guard_qualifier(&mut self) -> GuardQualifier {
3061 let pos = self.pos();
3062 let start_i = self.i;
3063 let snapshot = self.i;
3064 if let Some(pat) = self.try_bind_pattern() {
3065 if self.at_op("<-") {
3066 self.bump();
3067 let expr = self.expr();
3068 return GuardQualifier::Pattern {
3069 pat,
3070 expr,
3071 pos,
3072 span: self.node_span(start_i),
3073 };
3074 }
3075 }
3076 self.i = snapshot;
3077 let expr = self.expr();
3078 GuardQualifier::Bool {
3079 expr,
3080 pos,
3081 span: self.node_span(start_i),
3082 }
3083 }
3084
3085 fn case_alt(&mut self) -> Option<Alt> {
3086 let pos = self.pos();
3087 let start_i = self.i;
3088 let pat = self.pattern()?;
3089 let mut branches = Vec::new();
3090 if self.at_op("|") {
3091 while self.at_op("|") {
3092 let branch_pos = self.pos();
3093 let branch_start = self.i;
3094 self.eat_op("|");
3095 let mut guards = Vec::new();
3096 loop {
3097 guards.push(self.guard_qualifier());
3098 if !self.eat(&TokenKind::Comma) {
3099 break;
3100 }
3101 }
3102 if !self.eat_op("->") {
3103 self.diag_expected(
3104 ExpectedToken::ArrowInGuardedCaseAlternative,
3105 "expected '->' in guarded case alternative",
3106 );
3107 return None;
3108 }
3109 let body = self.expr();
3110 branches.push(AltBranch {
3111 guards,
3112 body,
3113 pos: branch_pos,
3114 span: self.node_span(branch_start),
3115 });
3116 }
3117 } else {
3118 if !self.at_op("->") {
3119 self.diag_expected(
3120 ExpectedToken::ArrowInCaseAlternative,
3121 "expected '->' in case alternative",
3122 );
3123 return None;
3124 }
3125 let branch_pos = self.pos();
3126 let branch_start = self.i;
3127 if !self.eat_op("->") {
3128 self.diag_expected(
3129 ExpectedToken::ArrowInCaseAlternative,
3130 "expected '->' in case alternative",
3131 );
3132 return None;
3133 }
3134 let body = self.expr();
3135 branches.push(AltBranch {
3136 guards: Vec::new(),
3137 body,
3138 pos: branch_pos,
3139 span: self.node_span(branch_start),
3140 });
3141 }
3142 let body = branches.first()?.body.clone();
3143 Some(Alt {
3144 pat,
3145 body,
3146 branches,
3147 where_bindings: Vec::new(),
3148 pos,
3149 span: self.node_span(start_i),
3150 })
3151 }
3152
3153 fn do_expr(&mut self) -> Option<Expr> {
3154 let pos = self.pos();
3155 let start_i = self.i;
3156 self.bump(); let mut stmts = Vec::new();
3158 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
3159 loop {
3160 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
3161 match self.peek() {
3162 None => break,
3163 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
3164 self.bump();
3165 break;
3166 }
3167 Some(TokenKind::RParen | TokenKind::RBracket) => {
3169 self.bump();
3170 continue;
3171 }
3172 _ => {}
3173 }
3174 stmts.push(self.do_stmt());
3175 }
3176 }
3177 Some(Expr::Do {
3178 stmts,
3179 pos,
3180 span: self.node_span(start_i),
3181 })
3182 }
3183
3184 fn do_stmt(&mut self) -> DoStmt {
3185 let pos = self.pos();
3186 let start_i = self.i;
3187 if self.at_keyword("let") {
3188 self.bump();
3189 let bindings = self.binding_block();
3190 if self.eat_keyword("in") {
3192 let body = self.expr();
3193 return DoStmt::Expr {
3194 expr: Expr::LetIn {
3195 bindings,
3196 body: Box::new(body),
3197 pos,
3198 span: self.node_span(start_i),
3199 },
3200 pos,
3201 span: self.node_span(start_i),
3202 };
3203 }
3204 return DoStmt::Let {
3205 bindings,
3206 pos,
3207 span: self.node_span(start_i),
3208 };
3209 }
3210 let snapshot = self.i;
3212 if let Some(pat) = self.try_bind_pattern() {
3213 if self.at_op("<-") {
3214 self.bump();
3215 let expr = self.expr();
3216 return DoStmt::Bind {
3217 pat,
3218 expr,
3219 pos,
3220 span: self.node_span(start_i),
3221 };
3222 }
3223 }
3224 self.i = snapshot;
3225 let expr = self.expr();
3226 DoStmt::Expr {
3227 expr,
3228 pos,
3229 span: self.node_span(start_i),
3230 }
3231 }
3232
3233 fn try_bind_pattern(&mut self) -> Option<Pat> {
3236 self.pattern()
3237 }
3238
3239 fn let_expr(&mut self) -> Option<Expr> {
3240 let pos = self.pos();
3241 let start_i = self.i;
3242 self.bump(); let bindings = self.binding_block();
3244 if self.eat_keyword("in") {
3245 let body = self.expr();
3246 return Some(Expr::LetIn {
3247 bindings,
3248 body: Box::new(body),
3249 pos,
3250 span: self.node_span(start_i),
3251 });
3252 }
3253 Some(Expr::LetIn {
3255 bindings,
3256 body: Box::new(Expr::Error {
3257 raw: String::new(),
3258 pos,
3259 span: self.node_span(start_i),
3260 }),
3261 pos,
3262 span: self.node_span(start_i),
3263 })
3264 }
3265
3266 fn try_expr(&mut self) -> Option<Expr> {
3267 let pos = self.pos();
3268 let start_i = self.i;
3269 self.bump(); let body = self.expr();
3271 let mut handlers = Vec::new();
3272 self.eat(&TokenKind::VSemi);
3273 if self.eat_keyword("catch") {
3274 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
3275 loop {
3276 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
3277 match self.peek() {
3278 None => break,
3279 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
3280 self.bump();
3281 break;
3282 }
3283 Some(TokenKind::RParen | TokenKind::RBracket) => {
3285 self.bump();
3286 continue;
3287 }
3288 _ => {}
3289 }
3290 let alt_start = self.i;
3291 match self.case_alt() {
3292 Some(mut alt) => {
3293 if self.eat_keyword("where") {
3294 alt.where_bindings = self.binding_block();
3295 }
3296 alt.span = self.node_span(alt_start);
3297 handlers.push(alt);
3298 }
3299 None => self.skip_to_item_end(),
3300 }
3301 }
3302 } else if let Some(a) = self.case_alt() {
3303 handlers.push(a);
3305 }
3306 }
3307 Some(Expr::Try {
3308 body: Box::new(body),
3309 handlers,
3310 pos,
3311 span: self.node_span(start_i),
3312 })
3313 }
3314
3315 fn lambda_expr(&mut self) -> Option<Expr> {
3316 let pos = self.pos();
3317 let start_i = self.i;
3318 self.bump(); if self.eat_keyword("case") {
3321 let mut alts = Vec::new();
3322 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
3323 loop {
3324 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
3325 match self.peek() {
3326 None => break,
3327 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
3328 self.bump();
3329 break;
3330 }
3331 Some(TokenKind::RParen | TokenKind::RBracket) => {
3332 self.bump();
3333 continue;
3334 }
3335 _ => {}
3336 }
3337 let alt_start = self.i;
3338 match self.case_alt() {
3339 Some(mut alt) => {
3340 if self.eat_keyword("where") {
3341 alt.where_bindings = self.binding_block();
3342 }
3343 alt.span = self.node_span(alt_start);
3344 alts.push(alt);
3345 }
3346 None => self.skip_to_item_end(),
3347 }
3348 }
3349 }
3350 return Some(Expr::Lambda {
3351 params: vec![Pat::Var {
3352 name: "_".into(),
3353 pos,
3354 span: Span::from_usize(self.byte_at(start_i), self.byte_at(start_i)),
3355 }],
3356 body: Box::new(Expr::Case {
3357 scrutinee: Box::new(Expr::Var {
3358 qualifier: None,
3359 name: "_".into(),
3360 pos,
3361 span: Span::from_usize(self.byte_at(start_i), self.byte_at(start_i)),
3362 }),
3363 alts,
3364 pos,
3365 span: self.node_span(start_i),
3366 }),
3367 pos,
3368 span: self.node_span(start_i),
3369 });
3370 }
3371 let mut params = Vec::new();
3372 while !self.at_op("->") {
3373 match self.pattern_atom() {
3374 Some(p) => params.push(p),
3375 None => {
3376 self.diag_malformed(
3377 MalformedSyntaxKind::LambdaParameter,
3378 "bad lambda parameter",
3379 );
3380 let start = self.i;
3381 self.skip_to_item_end();
3382 return Some(Expr::Error {
3383 raw: format!("\\{}", self.slice_text(start)),
3384 pos,
3385 span: self.node_span(start_i),
3386 });
3387 }
3388 }
3389 }
3390 self.bump(); let body = self.expr();
3392 Some(Expr::Lambda {
3393 params,
3394 body: Box::new(body),
3395 pos,
3396 span: self.node_span(start_i),
3397 })
3398 }
3399
3400 fn paren_expr(&mut self) -> Option<Expr> {
3401 let pos = self.pos();
3402 let start_i = self.i;
3403 self.bump(); if self.eat(&TokenKind::RParen) {
3405 return Some(Expr::Con {
3406 qualifier: None,
3407 name: "()".into(),
3408 pos,
3409 span: self.node_span(start_i),
3410 });
3411 }
3412 if let Some(TokenKind::Op(o)) = self.peek().cloned() {
3414 if !is_reserved_op(&o) && o != "\\" && o != "-" {
3415 self.bump();
3416 if self.eat(&TokenKind::RParen) {
3417 return Some(Expr::OperatorRef {
3418 op: o,
3419 pos,
3420 span: self.node_span(start_i),
3421 });
3422 }
3423 let operand = self.expr();
3424 self.eat(&TokenKind::RParen);
3425 return Some(Expr::RightSection {
3426 op: o,
3427 operand: Box::new(operand),
3428 pos,
3429 span: self.node_span(start_i),
3430 });
3431 }
3432 }
3433 let first = self.expr();
3434 if self.at(&TokenKind::Comma) {
3435 let mut items = vec![first];
3436 while self.eat(&TokenKind::Comma) {
3437 items.push(self.expr());
3438 }
3439 self.eat(&TokenKind::RParen);
3440 return Some(Expr::Tuple {
3441 items,
3442 pos,
3443 span: self.node_span(start_i),
3444 });
3445 }
3446 if let Some(TokenKind::Op(o)) = self.peek().cloned() {
3448 if !is_reserved_op(&o) && self.peek_at(1) == Some(&TokenKind::RParen) {
3449 self.bump();
3450 self.bump();
3451 return Some(Expr::LeftSection {
3452 op: o,
3453 operand: Box::new(first),
3454 pos,
3455 span: self.node_span(start_i),
3456 });
3457 }
3458 }
3459 self.eat(&TokenKind::RParen);
3460 Some(first)
3461 }
3462
3463 fn list_expr(&mut self) -> Option<Expr> {
3464 let pos = self.pos();
3465 let start_i = self.i;
3466 self.bump(); let mut items = Vec::new();
3468 if self.eat(&TokenKind::RBracket) {
3469 return Some(Expr::List {
3470 items,
3471 pos,
3472 span: self.node_span(start_i),
3473 });
3474 }
3475 loop {
3476 let e = self.expr();
3477 if self.at_op("..") {
3479 self.bump();
3480 let hi = if self.at(&TokenKind::RBracket) {
3481 Expr::Error {
3482 raw: String::new(),
3483 pos,
3484 span: self.node_span(start_i),
3485 }
3486 } else {
3487 self.expr()
3488 };
3489 self.eat(&TokenKind::RBracket);
3490 return Some(Expr::BinOp {
3491 op: "..".into(),
3492 lhs: Box::new(e),
3493 rhs: Box::new(hi),
3494 pos,
3495 span: self.node_span(start_i),
3496 });
3497 }
3498 if self.at_op("|") {
3500 let start = self.i;
3501 let mut brackets = 1usize;
3502 while let Some(t) = self.peek() {
3503 match t {
3504 TokenKind::LBracket => brackets += 1,
3505 TokenKind::RBracket => {
3506 brackets -= 1;
3507 if brackets == 0 {
3508 break;
3509 }
3510 }
3511 TokenKind::VSemi | TokenKind::VRBrace => break,
3512 _ => {}
3513 }
3514 self.i += 1;
3515 }
3516 let raw = self.slice_text(start);
3517 self.eat(&TokenKind::RBracket);
3518 return Some(Expr::App {
3519 func: Box::new(e),
3520 args: vec![Expr::Error {
3521 raw,
3522 pos,
3523 span: self.node_span(start_i),
3524 }],
3525 pos,
3526 span: self.node_span(start_i),
3527 });
3528 }
3529 items.push(e);
3530 if !self.eat(&TokenKind::Comma) {
3531 break;
3532 }
3533 }
3534 self.eat(&TokenKind::RBracket);
3535 Some(Expr::List {
3536 items,
3537 pos,
3538 span: self.node_span(start_i),
3539 })
3540 }
3541 fn lookup_fixity(&self, op: &str) -> (u8, bool) {
3542 self.fixity_env
3543 .get(op)
3544 .copied()
3545 .unwrap_or_else(|| default_fixity(op))
3546 }
3547}
3548
3549fn is_reserved_op(op: &str) -> bool {
3552 matches!(op, "=" | "<-" | "->" | "|" | ":" | "=>" | "@" | "\\" | "..")
3553}
3554
3555const fn fixity_assoc_right(assoc: FixityAssoc) -> bool {
3556 matches!(assoc, FixityAssoc::InfixR)
3557}
3558
3559fn fixity_target_key(target: &FixityTarget) -> String {
3560 match target {
3561 FixityTarget::Operator(op) => op.as_str().to_string(),
3562 FixityTarget::Backtick(name) => format!("`{name}`"),
3563 }
3564}
3565
3566fn apply_fixity_decl(env: &mut HashMap<String, (u8, bool)>, decl: &FixityDecl) {
3567 let right_assoc = fixity_assoc_right(decl.assoc);
3568 for target in &decl.operators {
3569 env.insert(fixity_target_key(target), (decl.precedence, right_assoc));
3570 }
3571}
3572
3573fn skip_to_item_end_at(toks: &[Token], i: &mut usize) {
3574 let mut depth = 0usize;
3575 let mut brackets = 0usize;
3576 while let Some(t) = toks.get(*i).map(|t| &t.kind) {
3577 match t {
3578 TokenKind::VLBrace => depth += 1,
3579 TokenKind::VRBrace => {
3580 if depth == 0 {
3581 return;
3582 }
3583 depth -= 1;
3584 }
3585 TokenKind::VSemi if depth == 0 && brackets == 0 => return,
3586 TokenKind::LParen | TokenKind::LBracket | TokenKind::LBrace => brackets += 1,
3587 TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace => {
3588 if brackets == 0 {
3589 return;
3590 }
3591 brackets -= 1;
3592 }
3593 _ => {}
3594 }
3595 *i += 1;
3596 }
3597}
3598
3599fn try_parse_fixity_at(
3600 toks: &[Token],
3601 i: &mut usize,
3602) -> Option<(FixityAssoc, u8, Vec<FixityTarget>)> {
3603 let assoc = match toks.get(*i).map(|t| &t.kind) {
3604 Some(k) if k.is_keyword("infixr") => FixityAssoc::InfixR,
3605 Some(k) if k.is_keyword("infixl") => FixityAssoc::InfixL,
3606 Some(k) if k.is_keyword("infix") => FixityAssoc::Infix,
3607 _ => return None,
3608 };
3609 *i += 1;
3610 let precedence = match toks.get(*i).map(|t| &t.kind) {
3611 Some(TokenKind::IntLit(n)) => n.parse().ok()?,
3612 _ => return None,
3613 };
3614 *i += 1;
3615 let mut operators = Vec::new();
3616 loop {
3617 match toks.get(*i).map(|t| t.kind.clone()) {
3618 Some(TokenKind::Backtick) => {
3619 *i += 1;
3620 let name = match toks.get(*i).map(|t| &t.kind) {
3621 Some(
3622 TokenKind::LowerId {
3623 qualifier: None,
3624 name,
3625 }
3626 | TokenKind::UpperId {
3627 qualifier: None,
3628 name,
3629 },
3630 ) => name.clone(),
3631 _ => return None,
3632 };
3633 *i += 1;
3634 if toks.get(*i).map(|t| &t.kind) != Some(&TokenKind::Backtick) {
3635 return None;
3636 }
3637 *i += 1;
3638 operators.push(FixityTarget::Backtick(name));
3639 }
3640 Some(TokenKind::Op(op)) if !is_reserved_op(&op) => {
3641 *i += 1;
3642 operators.push(FixityTarget::Operator(op));
3643 }
3644 _ => break,
3645 }
3646 if toks.get(*i).map(|t| &t.kind) != Some(&TokenKind::Comma) {
3647 break;
3648 }
3649 *i += 1;
3650 }
3651 if operators.is_empty() {
3652 return None;
3653 }
3654 Some((assoc, precedence, operators))
3655}
3656
3657fn scan_module_fixity_env(toks: &[Token], start: usize) -> HashMap<String, (u8, bool)> {
3660 let mut env = HashMap::new();
3661 let mut i = start;
3662 loop {
3663 while matches!(
3664 toks.get(i).map(|t| &t.kind),
3665 Some(TokenKind::VSemi | TokenKind::Semi)
3666 ) {
3667 i += 1;
3668 }
3669 match toks.get(i).map(|t| &t.kind) {
3670 None | Some(TokenKind::VRBrace | TokenKind::RBrace) => break,
3671 _ => {}
3672 }
3673 let before = i;
3674 if let Some((assoc, precedence, operators)) = try_parse_fixity_at(toks, &mut i) {
3675 let decl = FixityDecl {
3676 assoc,
3677 precedence,
3678 operators,
3679 pos: toks[before].pos,
3680 span: Span::from_usize(toks[before].start, toks[i.saturating_sub(1)].end),
3681 };
3682 apply_fixity_decl(&mut env, &decl);
3683 } else {
3684 i = before;
3685 }
3686 skip_to_item_end_at(toks, &mut i);
3687 if i == before {
3688 i += 1;
3689 }
3690 }
3691 env
3692}
3693
3694fn default_fixity(op: &str) -> (u8, bool) {
3697 match op {
3698 "$" | "$!" => (1, true),
3699 ">>=" | ">>" | "=<<" | "<&>" => (2, false),
3700 "||" => (3, true),
3701 "&&" => (4, true),
3702 "==" | "/=" | "<" | "<=" | ">" | ">=" => (5, false),
3703 "::" | "++" | "<>" => (6, true),
3704 "+" | "-" => (7, false),
3705 "*" | "/" => (8, false),
3706 "^" | "**" => (9, true),
3707 "." | "!!" => (10, true),
3708 _ => (9, false),
3709 }
3710}
3711
3712fn equations_extent(eqs: &[Equation]) -> Option<Span> {
3717 let mut it = eqs.iter();
3718 let first = it.next()?;
3719 let mut s = first.span;
3720 for e in it {
3721 s.start = s.start.min(e.span.start);
3722 s.end = s.end.max(e.span.end);
3723 }
3724 Some(s)
3725}
3726
3727fn merge_functions(decls: &mut Vec<Decl>) {
3728 let mut out: Vec<Decl> = Vec::with_capacity(decls.len());
3729 let mut function_index_by_name: HashMap<Identifier, usize> = HashMap::new();
3730 for decl in decls.drain(..) {
3731 match decl {
3732 Decl::Function(f) => {
3733 if let Some(existing_index) = function_index_by_name.get(&f.name).copied() {
3734 let Decl::Function(g) = &mut out[existing_index] else {
3735 out.push(Decl::Function(f));
3736 continue;
3737 };
3738 if g.ty.is_absent() {
3739 g.ty = f.ty.clone();
3740 }
3741 if g.sig_span.is_none() {
3742 g.sig_span = f.sig_span;
3743 }
3744 if g.equations.is_empty() && !f.equations.is_empty() {
3747 g.pos = f.pos;
3748 }
3749 g.equations.extend(f.equations);
3750 g.span = equations_extent(&g.equations)
3757 .or(g.sig_span)
3758 .unwrap_or(g.span);
3759 } else {
3760 function_index_by_name.insert(f.name.clone(), out.len());
3761 out.push(Decl::Function(f));
3762 }
3763 }
3764 other => out.push(other),
3765 }
3766 }
3767 *decls = out;
3768}
3769
3770pub(crate) fn parse_type_from_tokens(tokens: &[Token]) -> Option<Type> {
3779 let real_tokens: Vec<&Token> = tokens.iter().filter(|t| !t.is_virtual()).collect();
3782 if real_tokens.is_empty() {
3783 return None;
3784 }
3785 let mut parser = TypeTokenParser {
3786 tokens: &real_tokens,
3787 cursor: 0,
3788 };
3789 let ty = parser.parse_type()?;
3790 if parser.cursor == real_tokens.len() {
3793 Some(ty)
3794 } else {
3795 None
3796 }
3797}
3798
3799struct TypeTokenParser<'a> {
3800 tokens: &'a [&'a Token],
3801 cursor: usize,
3802}
3803
3804#[derive(Debug)]
3805struct FieldBlock {
3806 fields: Vec<FieldDecl>,
3807 dangling: bool,
3808}
3809
3810enum TypeAtom {
3813 ParsedType(Type),
3814 DroppedLiteral(Span),
3815}
3816
3817impl<'a> TypeTokenParser<'a> {
3818 fn peek(&self) -> Option<&'a Token> {
3819 self.tokens.get(self.cursor).copied()
3820 }
3821
3822 fn eat_op(&mut self, op: &str) -> bool {
3823 if self.peek().is_some_and(|t| t.kind.is_op(op)) {
3824 self.cursor += 1;
3825 true
3826 } else {
3827 false
3828 }
3829 }
3830
3831 fn parse_type(&mut self) -> Option<Type> {
3834 let lhs = if self.eat_keyword("forall") {
3835 self.parse_forall_type()?
3836 } else {
3837 self.parse_application_type()?
3838 };
3839 if self.eat_op("=>") {
3840 let body = self.parse_type()?;
3842 let span = Span::from_usize(lhs.span().start_usize(), body.span().end_usize());
3843 return Some(Type::Constrained(Box::new(body), span));
3844 }
3845 if self.eat_op("->") {
3846 let rhs = self.parse_type()?;
3847 let span = Span::from_usize(lhs.span().start_usize(), rhs.span().end_usize());
3848 return Some(Type::Fun(Box::new(lhs), Box::new(rhs), span));
3849 }
3850 Some(lhs)
3851 }
3852
3853 fn parse_application_type(&mut self) -> Option<Type> {
3855 let head = match self.parse_atom()? {
3856 TypeAtom::ParsedType(t) => t,
3857 TypeAtom::DroppedLiteral(_) => return None,
3859 };
3860 let mut args = Vec::new();
3861 let start = head.span().start_usize();
3862 let mut end = head.span().end_usize();
3863 loop {
3864 if !self.is_at_type_atom_start() {
3867 break;
3868 }
3869 match self.parse_atom()? {
3870 TypeAtom::ParsedType(t) => {
3871 end = t.span().end_usize();
3872 args.push(t);
3873 }
3874 TypeAtom::DroppedLiteral(span) => {
3875 end = span.end_usize();
3878 }
3879 }
3880 }
3881 let span = Span::from_usize(start, end);
3882 if args.is_empty() {
3883 Some(head.with_span(span))
3884 } else {
3885 Some(Type::App(Box::new(head), args, span))
3886 }
3887 }
3888
3889 fn is_at_type_atom_start(&self) -> bool {
3892 matches!(
3893 self.peek().map(|t| &t.kind),
3894 Some(
3895 TokenKind::UpperId { .. }
3896 | TokenKind::LowerId { .. }
3897 | TokenKind::IntLit(_)
3898 | TokenKind::DecimalLit(_)
3899 | TokenKind::StringLit(_)
3900 | TokenKind::CharLit(_)
3901 | TokenKind::LBracket
3902 | TokenKind::LParen
3903 )
3904 )
3905 }
3906
3907 fn parse_atom(&mut self) -> Option<TypeAtom> {
3908 let tok = self.peek()?;
3909 match &tok.kind {
3910 TokenKind::UpperId { qualifier, name } => {
3911 let con = Type::Con {
3912 qualifier: qualifier.clone(),
3913 name: name.clone(),
3914 span: Span::from_usize(tok.start, tok.end),
3915 };
3916 self.cursor += 1;
3917 Some(TypeAtom::ParsedType(con))
3918 }
3919 TokenKind::LowerId { name, .. } => {
3920 let var = Type::Var(name.clone(), Span::from_usize(tok.start, tok.end));
3923 self.cursor += 1;
3924 Some(TypeAtom::ParsedType(var))
3925 }
3926 TokenKind::IntLit(_) | TokenKind::DecimalLit(_) => {
3927 self.cursor += 1;
3929 Some(TypeAtom::DroppedLiteral(Span::from_usize(
3930 tok.start, tok.end,
3931 )))
3932 }
3933 TokenKind::StringLit(text) => {
3934 self.cursor += 1;
3935 Some(TypeAtom::ParsedType(Type::Lit {
3936 kind: LitKind::Text,
3937 text: text.clone(),
3938 span: Span::from_usize(tok.start, tok.end),
3939 }))
3940 }
3941 TokenKind::CharLit(text) => {
3942 self.cursor += 1;
3943 Some(TypeAtom::ParsedType(Type::Lit {
3944 kind: LitKind::Char,
3945 text: text.clone(),
3946 span: Span::from_usize(tok.start, tok.end),
3947 }))
3948 }
3949 TokenKind::LBracket => {
3950 let start = tok.start;
3951 self.cursor += 1;
3952 let inner = self.parse_type()?;
3953 self.eat_token(&TokenKind::RBracket).map(|end| {
3954 TypeAtom::ParsedType(Type::List(
3955 Box::new(inner),
3956 Span::from_usize(start, end.end),
3957 ))
3958 })
3959 }
3960 TokenKind::LParen => {
3961 let start = tok.start;
3962 self.cursor += 1;
3963 if let Some(op) = self.eat_token_if_operator() {
3964 let mut name = op.as_str().to_string();
3965 while matches!(
3966 self.tokens.get(self.cursor).map(|t| &t.kind),
3967 Some(TokenKind::Op(_))
3968 ) {
3969 self.cursor += 1;
3970 if let TokenKind::Op(o) = &self.tokens[self.cursor - 1].kind {
3971 name.push_str(o.as_str());
3972 }
3973 }
3974 if self.eat_token(&TokenKind::RParen).is_some()
3975 && self
3976 .tokens
3977 .get(self.cursor)
3978 .is_some_and(|t| Self::is_type_atom_start(&t.kind))
3979 {
3980 let end = self.tokens[self.cursor - 1];
3981 return Some(TypeAtom::ParsedType(Type::Con {
3982 qualifier: None,
3983 name: name.into(),
3984 span: Span::from_usize(start, end.end),
3985 }));
3986 }
3987 return None;
3988 }
3989 if matches!(
3990 self.tokens.get(self.cursor).map(|t| &t.kind),
3991 Some(TokenKind::Comma)
3992 ) {
3993 let mut name = String::from(",");
3994 self.cursor += 1;
3995 while matches!(
3996 self.tokens.get(self.cursor).map(|t| &t.kind),
3997 Some(TokenKind::Comma)
3998 ) {
3999 self.cursor += 1;
4000 name.push(',');
4001 }
4002 if self.eat_token(&TokenKind::RParen).is_some()
4003 && self
4004 .tokens
4005 .get(self.cursor)
4006 .is_some_and(|t| Self::is_type_atom_start(&t.kind))
4007 {
4008 let end = self.tokens[self.cursor - 1];
4009 return Some(TypeAtom::ParsedType(Type::Con {
4010 qualifier: None,
4011 name: name.into(),
4012 span: Span::from_usize(start, end.end),
4013 }));
4014 }
4015 return None;
4016 }
4017 if let Some(end) = self.eat_token(&TokenKind::RParen) {
4018 return Some(TypeAtom::ParsedType(Type::Unit(Span::from_usize(
4020 start, end.end,
4021 ))));
4022 }
4023 let first = self.parse_type()?;
4024 if self.peek().map(|t| &t.kind) == Some(&TokenKind::Comma) {
4025 let mut items = vec![first];
4026 while self.eat_token(&TokenKind::Comma).is_some() {
4027 items.push(self.parse_type()?);
4028 }
4029 self.eat_token(&TokenKind::RParen).map(|end| {
4030 TypeAtom::ParsedType(Type::Tuple(items, Span::from_usize(start, end.end)))
4031 })
4032 } else {
4033 self.eat_token(&TokenKind::RParen).map(|end| {
4034 TypeAtom::ParsedType(first.with_span(Span::from_usize(start, end.end)))
4036 })
4037 }
4038 }
4039 _ => None,
4040 }
4041 }
4042
4043 fn eat_keyword(&mut self, kw: &str) -> bool {
4044 if self.peek().is_some_and(|t| t.kind.is_keyword(kw)) {
4045 self.cursor += 1;
4046 true
4047 } else {
4048 false
4049 }
4050 }
4051
4052 fn parse_forall_type(&mut self) -> Option<Type> {
4053 let start = self
4054 .tokens
4055 .get(self.cursor.wrapping_sub(1))
4056 .map(|t| t.start)
4057 .unwrap_or_default();
4058 while self.cursor < self.tokens.len() {
4059 if self.peek().is_some_and(|t| t.kind.is_op(".")) {
4060 self.cursor += 1;
4061 let body = self.parse_type()?;
4062 let body_span = body.span();
4063 return Some(body.with_span(Span::from_usize(start, body_span.end_usize())));
4064 }
4065 self.cursor += 1;
4066 }
4067 None
4068 }
4069
4070 fn eat_token(&mut self, tok: &TokenKind) -> Option<&'a Token> {
4071 if self.peek().is_some_and(|t| t.kind == *tok) {
4072 let t = self.peek();
4073 self.cursor += 1;
4074 t
4075 } else {
4076 None
4077 }
4078 }
4079
4080 fn eat_token_if_operator(&mut self) -> Option<&'a Operator> {
4081 match self.peek() {
4082 Some(Token {
4083 kind: TokenKind::Op(op),
4084 ..
4085 }) => {
4086 self.cursor += 1;
4087 Some(op)
4088 }
4089 _ => None,
4090 }
4091 }
4092
4093 const fn is_type_atom_start(kind: &TokenKind) -> bool {
4094 matches!(
4095 kind,
4096 TokenKind::UpperId { .. }
4097 | TokenKind::LowerId { .. }
4098 | TokenKind::IntLit(_)
4099 | TokenKind::DecimalLit(_)
4100 | TokenKind::StringLit(_)
4101 | TokenKind::CharLit(_)
4102 | TokenKind::LParen
4103 | TokenKind::LBracket
4104 )
4105 }
4106}
4107
4108fn render_token_slice(tokens: &[Token]) -> String {
4109 let mut s = String::new();
4110 let mut prev_no_space_after = true;
4111 for t in tokens {
4112 let (text, no_space_before, no_space_after): (String, bool, bool) = match &t.kind {
4113 TokenKind::LowerId { qualifier, name } | TokenKind::UpperId { qualifier, name } => (
4114 qualifier
4115 .as_ref()
4116 .map_or_else(|| name.to_string(), |q| format!("{q}.{name}")),
4117 false,
4118 false,
4119 ),
4120 TokenKind::Op(o) => (o.to_string(), false, false),
4121 TokenKind::IntLit(n) | TokenKind::DecimalLit(n) => (n.clone(), false, false),
4122 TokenKind::StringLit(v) => (format!("{v:?}"), false, false),
4123 TokenKind::CharLit(v) => (format!("'{v}'"), false, false),
4124 TokenKind::LParen => ("(".to_string(), false, true),
4125 TokenKind::RParen => (")".to_string(), true, false),
4126 TokenKind::LBracket => ("[".to_string(), false, true),
4127 TokenKind::RBracket => ("]".to_string(), true, false),
4128 TokenKind::LBrace => ("{".to_string(), false, true),
4129 TokenKind::RBrace => ("}".to_string(), true, false),
4130 TokenKind::Comma => (",".to_string(), true, false),
4131 TokenKind::Semi | TokenKind::VSemi => (";".to_string(), true, false),
4132 TokenKind::Backtick => ("`".to_string(), false, false),
4133 TokenKind::VLBrace | TokenKind::VRBrace => continue,
4134 };
4135 if !s.is_empty() && !no_space_before && !prev_no_space_after {
4136 s.push(' ');
4137 }
4138 s.push_str(&text);
4139 prev_no_space_after = no_space_after;
4140 }
4141 s
4142}
4143
4144#[cfg(test)]
4147mod type_tests {
4148 use super::*;
4149 use crate::lexer::lex;
4150
4151 fn ty(s: &str) -> Option<Type> {
4155 let (toks, errs) = lex(s).into_parts();
4156 assert!(errs.is_empty(), "lex errors for {s:?}: {errs:?}");
4157 parse_type_from_tokens(&toks)
4158 }
4159
4160 fn con(name: &str) -> Type {
4161 Type::Con {
4162 qualifier: None,
4163 name: name.into(),
4164 span: Span::default(),
4165 }
4166 }
4167
4168 fn qualified_con(qualifier: &str, name: &str) -> Type {
4169 Type::Con {
4170 qualifier: Some(qualifier.into()),
4171 name: name.into(),
4172 span: Span::default(),
4173 }
4174 }
4175
4176 fn app(head: Type, args: Vec<Type>) -> Type {
4177 Type::App(Box::new(head), args, Span::default())
4178 }
4179
4180 fn list(inner: Type) -> Type {
4181 Type::List(Box::new(inner), Span::default())
4182 }
4183
4184 fn tuple(items: Vec<Type>) -> Type {
4185 Type::Tuple(items, Span::default())
4186 }
4187
4188 fn fun(param: Type, result: Type) -> Type {
4189 Type::Fun(Box::new(param), Box::new(result), Span::default())
4190 }
4191
4192 fn var(name: &str) -> Type {
4193 Type::Var(name.into(), Span::default())
4194 }
4195
4196 fn unit() -> Type {
4197 Type::Unit(Span::default())
4198 }
4199
4200 fn constrained(body: Type) -> Type {
4201 Type::Constrained(Box::new(body), Span::default())
4202 }
4203
4204 fn text_lit(value: &str) -> Type {
4205 Type::Lit {
4206 kind: LitKind::Text,
4207 text: value.to_string(),
4208 span: Span::default(),
4209 }
4210 }
4211
4212 fn char_lit(value: &str) -> Type {
4213 Type::Lit {
4214 kind: LitKind::Char,
4215 text: value.to_string(),
4216 span: Span::default(),
4217 }
4218 }
4219
4220 #[test]
4221 fn atoms() {
4222 assert_eq!(ty("Party"), Some(con("Party")));
4223 assert_eq!(ty("Decimal"), Some(con("Decimal")));
4224 assert_eq!(ty("a"), Some(var("a")));
4225 assert_eq!(ty("()"), Some(unit()));
4226 }
4227
4228 #[test]
4229 fn application_vs_constructor() {
4230 assert_eq!(
4233 ty("ContractId Foo"),
4234 Some(app(con("ContractId"), vec![con("Foo")]))
4235 );
4236 assert_eq!(
4237 ty("Optional (ContractId Foo)"),
4238 Some(app(
4239 con("Optional"),
4240 vec![app(con("ContractId"), vec![con("Foo")])]
4241 ))
4242 );
4243 assert_eq!(
4244 ty("Map Text Int"),
4245 Some(app(con("Map"), vec![con("Text"), con("Int")]))
4246 );
4247 }
4248
4249 #[test]
4250 fn qualified_constructor_keeps_qualifier() {
4251 assert_eq!(
4252 ty("DA.Map.Map Text Int"),
4253 Some(app(
4254 qualified_con("DA.Map", "Map"),
4255 vec![con("Text"), con("Int")]
4256 ))
4257 );
4258 }
4259
4260 #[test]
4261 fn list_and_tuple() {
4262 assert_eq!(ty("[Text]"), Some(list(con("Text"))));
4263 assert_eq!(
4264 ty("(Int, Text)"),
4265 Some(tuple(vec![con("Int"), con("Text")]))
4266 );
4267 assert_eq!(
4269 ty("(a, b, c)"),
4270 Some(tuple(vec![var("a"), var("b"), var("c")]))
4271 );
4272 assert_eq!(ty("(Text)"), Some(con("Text")));
4274 }
4275
4276 #[test]
4277 fn function_types_are_arrows_not_names() {
4278 assert_eq!(ty("Int -> Int"), Some(fun(con("Int"), con("Int"))));
4281 assert_eq!(
4283 ty("Int -> Text -> Bool"),
4284 Some(fun(con("Int"), fun(con("Text"), con("Bool"))))
4285 );
4286 assert_eq!(
4287 ty("Party -> Script ()"),
4288 Some(fun(con("Party"), app(con("Script"), vec![unit()])))
4289 );
4290 }
4291
4292 #[test]
4293 fn script_application() {
4294 assert_eq!(ty("Script ()"), Some(app(con("Script"), vec![unit()])));
4297 }
4298
4299 #[test]
4300 fn numeric_nat_literal_is_dropped() {
4301 assert_eq!(ty("Numeric 10"), Some(con("Numeric")));
4304 assert_eq!(ty("Numeric n"), Some(app(con("Numeric"), vec![var("n")])));
4305 }
4306
4307 #[test]
4308 fn string_and_char_type_literals_are_structured() {
4309 assert_eq!(
4312 ty(r#"HasField "observers""#),
4313 Some(app(con("HasField"), vec![text_lit("observers")]))
4314 );
4315 assert_eq!(
4316 ty(r#"HasField "observers" t PartiesMap"#),
4317 Some(app(
4318 con("HasField"),
4319 vec![text_lit("observers"), var("t"), con("PartiesMap")]
4320 ))
4321 );
4322 assert_eq!(
4323 ty(r"HasField 'x'"),
4324 Some(app(con("HasField"), vec![char_lit("x")]))
4325 );
4326 }
4327
4328 #[test]
4329 fn constraint_context_is_dropped_body_kept() {
4330 assert_eq!(
4333 ty("NumericScale n => Numeric 37 -> Numeric n"),
4334 Some(constrained(fun(
4335 con("Numeric"),
4336 app(con("Numeric"), vec![var("n")])
4337 )))
4338 );
4339 assert_eq!(ty("(Eq a, Show a) => a"), Some(constrained(var("a"))));
4341 }
4342
4343 #[test]
4344 fn unparseable_is_none() {
4345 assert_eq!(ty("Int ->"), None);
4348 assert_eq!(ty("-> Int"), None);
4349 }
4350}