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