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