1use crate::ast::*;
8use crate::layout::resolve_layout;
9use crate::lexer::{lex, Pos, Tok, Token};
10use std::collections::HashMap;
11
12pub fn parse_module(source: &str) -> (Module, Vec<ParseDiagnostic>) {
27 let (tokens, lex_errors) = lex(source);
28 let tokens = resolve_layout(tokens);
29 let mut p = Parser {
30 toks: tokens,
31 src_len: source.len(),
32 i: 0,
33 depth: 0,
34 diags: lex_errors
35 .into_iter()
36 .map(|e| {
37 let b = byte_of_pos(source, e.pos);
38 ParseDiagnostic {
39 message: e.message,
40 pos: e.pos,
41 span: crate::ast::Span::new(b, b),
42 category: DiagnosticCategory::Lex,
43 }
44 })
45 .collect(),
46 };
47 let mut module = p.module();
48 module.span = crate::ast::Span::new(0, source.len());
49 (module, p.diags)
50}
51
52fn byte_of_pos(source: &str, pos: Pos) -> usize {
57 let mut line = 1usize;
58 let mut col = 1usize;
59 for (idx, ch) in source.char_indices() {
60 if line == pos.line && col == pos.column {
61 return idx;
62 }
63 match ch {
64 '\n' => {
65 line += 1;
66 col = 1;
67 }
68 '\t' => col = ((col - 1) / crate::lexer::TAB_STOP + 1) * crate::lexer::TAB_STOP + 1,
69 _ => col += 1,
70 }
71 }
72 source.len()
73}
74
75struct Parser {
76 toks: Vec<Token>,
77 src_len: usize,
79 i: usize,
80 diags: Vec<ParseDiagnostic>,
81 depth: u32,
84}
85
86const MAX_DEPTH: u32 = 128;
87
88impl Parser {
89 fn node_span(&self, from: usize) -> crate::ast::Span {
95 let mut a = from;
96 while a < self.i && self.toks[a].is_virtual() {
97 a += 1;
98 }
99 let mut b = self.i;
100 while b > a && self.toks[b - 1].is_virtual() {
101 b -= 1;
102 }
103 if a >= b {
104 let p = self.byte_at(a);
109 return crate::ast::Span::new(p, p);
110 }
111 crate::ast::Span::new(self.toks[a].start, self.toks[b - 1].end)
112 }
113
114 fn byte_at(&self, i: usize) -> usize {
116 self.toks.get(i).map(|t| t.start).unwrap_or(self.src_len)
117 }
118
119 fn end_byte(&self) -> usize {
123 let mut b = self.i;
124 while b > 0 && self.toks[b - 1].is_virtual() {
125 b -= 1;
126 }
127 if b == 0 {
128 0
129 } else {
130 self.toks[b - 1].end
131 }
132 }
133}
134
135impl Parser {
136 fn peek(&self) -> Option<&Tok> {
139 self.toks.get(self.i).map(|t| &t.tok)
140 }
141
142 fn peek_at(&self, n: usize) -> Option<&Tok> {
143 self.toks.get(self.i + n).map(|t| &t.tok)
144 }
145
146 fn pos(&self) -> Pos {
147 self.toks
148 .get(self.i)
149 .or_else(|| self.toks.last())
150 .map_or(Pos { line: 1, column: 1 }, |t| t.pos)
151 }
152
153 fn bump(&mut self) -> Option<Token> {
154 let t = self.toks.get(self.i).cloned();
155 if t.is_some() {
156 self.i += 1;
157 }
158 t
159 }
160
161 fn at_keyword(&self, kw: &str) -> bool {
162 self.peek().is_some_and(|t| t.is_keyword(kw))
163 }
164
165 fn eat_keyword(&mut self, kw: &str) -> bool {
166 if self.at_keyword(kw) {
167 self.i += 1;
168 true
169 } else {
170 false
171 }
172 }
173
174 fn at_op(&self, op: &str) -> bool {
175 self.peek().is_some_and(|t| t.is_op(op))
176 }
177
178 fn eat_op(&mut self, op: &str) -> bool {
179 if self.at_op(op) {
180 self.i += 1;
181 true
182 } else {
183 false
184 }
185 }
186
187 fn at(&self, tok: &Tok) -> bool {
188 self.peek() == Some(tok)
189 }
190
191 fn eat(&mut self, tok: &Tok) -> bool {
192 if self.at(tok) {
193 self.i += 1;
194 true
195 } else {
196 false
197 }
198 }
199
200 fn diag(&mut self, message: impl Into<String>) {
202 self.diag_cat(DiagnosticCategory::Malformed, message);
203 }
204
205 fn diag_cat(&mut self, category: DiagnosticCategory, message: impl Into<String>) {
209 let pos = self.pos();
210 let span = self.cur_span();
211 self.diags.push(ParseDiagnostic {
212 message: message.into(),
213 pos,
214 span,
215 category,
216 });
217 }
218
219 fn cur_span(&self) -> crate::ast::Span {
222 let mut j = self.i;
223 while self.toks.get(j).is_some_and(|t| t.is_virtual()) {
224 j += 1;
225 }
226 self.toks.get(j).map_or_else(
227 || crate::ast::Span::new(self.src_len, self.src_len),
228 |t| crate::ast::Span::new(t.start, t.end),
229 )
230 }
231
232 fn skip_to_item_end(&mut self) {
235 let mut depth = 0usize;
236 let mut brackets = 0usize;
237 while let Some(t) = self.peek() {
238 match t {
239 Tok::VLBrace => depth += 1,
240 Tok::VRBrace => {
241 if depth == 0 {
242 return;
243 }
244 depth -= 1;
245 }
246 Tok::VSemi if depth == 0 && brackets == 0 => return,
247 Tok::LParen | Tok::LBracket | Tok::LBrace => brackets += 1,
248 Tok::RParen | Tok::RBracket | Tok::RBrace => {
249 if brackets == 0 {
250 return;
253 }
254 brackets -= 1;
255 }
256 _ => {}
257 }
258 self.i += 1;
259 }
260 }
261
262 fn slice_text(&self, start: usize) -> String {
264 render_token_slice(&self.toks[start..self.i])
265 }
266
267 fn module(&mut self) -> Module {
270 let pos = self.pos();
271 let header_start = self.i;
272 let mut header = crate::ast::Span::new(0, 0);
273 let mut name = "Unknown".to_string();
274
275 if self.eat_keyword("module") {
276 if let Some(Tok::UpperId { qualifier, name: n }) = self.peek().cloned() {
277 self.bump();
278 name = match qualifier {
279 Some(q) => format!("{q}.{n}"),
280 None => n,
281 };
282 }
283 if self.at(&Tok::LParen) {
285 self.skip_balanced_parens();
286 }
287 if !self.eat_keyword("where") {
288 self.diag("expected 'where' after module header");
289 }
290 header = self.node_span(header_start);
291 }
292
293 let mut imports = Vec::new();
294 let mut decls: Vec<Decl> = Vec::new();
295
296 let _ = self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace);
300 loop {
301 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
302 match self.peek() {
303 None => break,
304 Some(Tok::VRBrace | Tok::RBrace) => {
305 self.bump();
306 break;
307 }
308 Some(Tok::RParen | Tok::RBracket) => {
313 let cpos = self.pos();
314 let cstart = self.i;
315 self.bump();
316 decls.push(Decl::Unknown {
317 raw: self.slice_text(cstart),
318 pos: cpos,
319 span: self.node_span(cstart),
320 });
321 continue;
322 }
323 _ => {}
324 }
325 let before = self.i;
326 self.declaration(&mut imports, &mut decls);
327 if self.i == before {
328 self.bump();
330 }
331 }
332
333 merge_functions(&mut decls);
334
335 Module {
336 name,
337 pos,
338 header,
339 imports,
340 decls,
341 span: crate::ast::Span::new(0, self.src_len),
342 }
343 }
344
345 fn skip_balanced_parens(&mut self) {
346 let mut depth = 0usize;
347 while let Some(t) = self.peek() {
348 match t {
349 Tok::LParen => depth += 1,
350 Tok::RParen => {
351 if depth == 0 {
352 return;
353 }
354 depth -= 1;
355 if depth == 0 {
356 self.i += 1;
357 return;
358 }
359 }
360 _ => {}
361 }
362 self.i += 1;
363 }
364 }
365
366 fn try_infix_operator_decl(&mut self) -> bool {
370 let snap = self.i;
371 let saved_diags = self.diags.len();
372 if self.pattern().is_some() && matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o))
373 {
374 self.skip_to_item_end();
375 return true;
376 }
377 self.i = snap;
378 self.diags.truncate(saved_diags);
379 false
380 }
381
382 fn declaration(&mut self, imports: &mut Vec<ImportDecl>, decls: &mut Vec<Decl>) {
383 let pos = self.pos();
384 let start = self.i;
385 if matches!(
386 self.peek(),
387 Some(Tok::UpperId { .. } | Tok::LBracket | Tok::LParen)
388 ) && self.try_infix_operator_decl()
389 {
390 decls.push(Decl::Unknown {
391 raw: self.slice_text(start),
392 pos,
393 span: self.node_span(start),
394 });
395 return;
396 }
397 match self.peek() {
398 Some(t) if t.is_keyword("import") => {
399 let imp = self.import_decl();
400 self.skip_to_item_end();
404 if let Some(mut imp) = imp {
405 imp.span = self.node_span(start);
406 imports.push(imp);
407 }
408 }
409 Some(t) if t.is_keyword("template") => {
410 match self.template_decl() {
413 Some(t) => decls.push(Decl::Template(t)),
414 None => {
415 self.skip_to_item_end();
416 decls.push(Decl::Unknown {
417 raw: self.slice_text(start),
418 span: self.node_span(start),
419 pos,
420 });
421 }
422 }
423 }
424 Some(t) if t.is_keyword("interface") => match self.interface_decl() {
425 Some(i) => decls.push(Decl::Interface(i)),
426 None => {
427 self.skip_to_item_end();
428 decls.push(Decl::Unknown {
429 raw: self.slice_text(start),
430 span: self.node_span(start),
431 pos,
432 });
433 }
434 },
435 Some(t)
436 if matches!(
437 t.keyword(),
438 Some("infix" | "infixl" | "infixr" | "default" | "pattern")
441 ) =>
442 {
443 self.skip_to_item_end();
444 decls.push(Decl::Unknown {
445 raw: self.slice_text(start),
446 pos,
447 span: self.node_span(start),
448 });
449 }
450 Some(t)
451 if matches!(
452 t.keyword(),
453 Some(
454 "data"
455 | "type"
456 | "newtype"
457 | "class"
458 | "instance"
459 | "exception"
460 | "deriving"
461 )
462 ) =>
463 {
464 let keyword = t.keyword().unwrap().to_string();
465 self.bump();
466 let name = match self.peek() {
467 Some(Tok::UpperId { qualifier, name }) => {
468 let n = qualifier
469 .as_ref()
470 .map_or_else(|| name.clone(), |q| format!("{q}.{name}"));
471 self.bump();
472 n
473 }
474 _ => String::new(),
475 };
476 self.skip_to_item_end();
477 decls.push(Decl::TypeDef {
478 keyword,
479 name,
480 pos,
481 span: self.node_span(start),
482 });
483 }
484 Some(Tok::LowerId { .. }) => match self.function_item() {
485 Some(d) => decls.push(d),
486 None => {
487 self.skip_to_item_end();
488 decls.push(Decl::Unknown {
489 raw: self.slice_text(start),
490 span: self.node_span(start),
491 pos,
492 });
493 }
494 },
495 Some(Tok::LParen)
497 if matches!(self.peek_at(1), Some(Tok::Op(_)))
498 && self.peek_at(2) == Some(&Tok::RParen) =>
499 {
500 self.skip_to_item_end();
501 decls.push(Decl::Unknown {
502 raw: self.slice_text(start),
503 span: self.node_span(start),
504 pos,
505 });
506 }
507 Some(Tok::LParen | Tok::LBracket) => {
509 if self.binding().is_none() {
510 self.diag_cat(
511 DiagnosticCategory::SkippedDecl,
512 "unparseable top-level pattern binding",
513 );
514 }
515 self.skip_to_item_end();
516 decls.push(Decl::Unknown {
517 raw: self.slice_text(start),
518 span: self.node_span(start),
519 pos,
520 });
521 }
522 _ => {
523 self.diag_cat(
524 DiagnosticCategory::SkippedDecl,
525 format!("unrecognized declaration: {:?}", self.peek()),
526 );
527 self.skip_to_item_end();
528 decls.push(Decl::Unknown {
529 raw: self.slice_text(start),
530 span: self.node_span(start),
531 pos,
532 });
533 }
534 }
535 }
536
537 fn import_decl(&mut self) -> Option<ImportDecl> {
540 let pos = self.pos();
541 let start_i = self.i;
542 self.bump(); let mut qualified = self.eat_keyword("qualified");
544 if matches!(self.peek(), Some(Tok::StringLit(_))) {
546 self.bump();
547 }
548 let module_name = match self.peek().cloned() {
549 Some(Tok::UpperId { qualifier, name }) => {
550 self.bump();
551 match qualifier {
552 Some(q) => format!("{q}.{name}"),
553 None => name,
554 }
555 }
556 _ => {
557 self.diag("expected module name after 'import'");
558 return None;
559 }
560 };
561 if self.eat_keyword("qualified") {
563 qualified = true;
564 }
565 let mut alias = None;
566 if self.eat_keyword("as") {
567 if let Some(Tok::UpperId { qualifier, name }) = self.peek().cloned() {
568 self.bump();
569 alias = Some(match qualifier {
570 Some(q) => format!("{q}.{name}"),
571 None => name,
572 });
573 }
574 }
575 Some(ImportDecl {
577 module_name,
578 qualified,
579 alias,
580 pos,
581 span: self.node_span(start_i),
582 })
583 }
584
585 fn upper_name(&mut self) -> Option<String> {
588 match self.peek().cloned() {
589 Some(Tok::UpperId { qualifier, name }) => {
590 self.bump();
591 Some(match qualifier {
592 Some(q) => format!("{q}.{name}"),
593 None => name,
594 })
595 }
596 _ => None,
597 }
598 }
599
600 fn template_decl(&mut self) -> Option<TemplateDecl> {
601 let pos = self.pos();
602 let start_i = self.i;
603 self.bump(); if self.at_keyword("instance") {
605 return None; }
607 let name = self.upper_name()?;
608
609 let mut fields = Vec::new();
610 if self.eat_keyword("with") {
611 (fields, _) = self.field_block();
612 }
613 let body = if self.eat_keyword("where") {
614 self.template_body()
615 } else {
616 Vec::new()
617 };
618 Some(TemplateDecl {
619 name,
620 fields,
621 body,
622 pos,
623 span: self.node_span(start_i),
624 })
625 }
626
627 fn field_block(&mut self) -> (Vec<FieldDecl>, bool) {
633 let mut fields = Vec::new();
634 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
635 return (fields, false);
636 }
637 loop {
638 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
639 match self.peek() {
640 None => break,
641 Some(Tok::VRBrace | Tok::RBrace) => {
642 self.bump();
643 break;
644 }
645 Some(Tok::RParen | Tok::RBracket) => {
650 self.bump();
651 continue;
652 }
653 _ => {}
654 }
655 {
660 let mut j = self.i;
661 while let Some(Tok::LowerId {
662 qualifier: None, ..
663 }) = self.toks.get(j).map(|t| &t.tok)
664 {
665 j += 1;
666 match self.toks.get(j).map(|t| &t.tok) {
667 Some(Tok::Comma) => j += 1,
668 _ => break,
669 }
670 }
671 let is_field = j > self.i
672 && self
673 .toks
674 .get(j)
675 .map(|t| &t.tok)
676 .is_some_and(|t| t.is_op(":"));
677 if !is_field {
678 return (fields, true);
679 }
680 }
681 let mut names: Vec<(String, Pos, Span)> = Vec::new();
683 while let Some(Tok::LowerId {
684 qualifier: None,
685 name,
686 }) = self.peek().cloned()
687 {
688 let p = self.pos();
689 let nspan = Span::new(self.toks[self.i].start, self.toks[self.i].end);
690 self.bump();
691 names.push((name, p, nspan));
692 if !self.eat(&Tok::Comma) {
693 break;
694 }
695 }
696 if names.is_empty() || !self.eat_op(":") {
697 self.diag("expected 'name : Type' field");
698 self.skip_to_item_end();
699 continue;
700 }
701 let ty_start = self.i;
702 self.skip_to_item_end();
703 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
704 let type_end = self.end_byte();
709 let last = names.len() - 1;
710 for (idx, (name, p, nspan)) in names.into_iter().enumerate() {
711 let span = if idx == last {
712 Span::new(nspan.start, type_end.max(nspan.end))
713 } else {
714 nspan
715 };
716 fields.push(FieldDecl {
717 name,
718 ty: ty.clone(),
719 pos: p,
720 span,
721 });
722 }
723 }
724 (fields, false)
725 }
726
727 fn template_body(&mut self) -> Vec<TemplateBodyDecl> {
730 let mut body = Vec::new();
731 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
732 return body;
733 }
734 loop {
735 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
736 match self.peek() {
737 None => break,
738 Some(Tok::VRBrace | Tok::RBrace) => {
739 self.bump();
740 break;
741 }
742 Some(Tok::RParen | Tok::RBracket) => {
747 self.bump();
748 continue;
749 }
750 _ => {}
751 }
752 let pos = self.pos();
753 let start = self.i;
754 let decl = self.template_body_item(pos, start);
755 body.push(decl);
756 }
757 body
758 }
759
760 fn template_body_item(&mut self, pos: Pos, start: usize) -> TemplateBodyDecl {
761 match self.peek().and_then(|t| t.keyword()) {
762 Some("signatory") => {
763 self.bump();
764 let parties = self.expr_comma_list();
765 self.skip_to_item_end();
766 TemplateBodyDecl::Signatory {
767 parties,
768 pos,
769 span: self.node_span(start),
770 }
771 }
772 Some("observer") => {
773 self.bump();
774 let parties = self.expr_comma_list();
775 self.skip_to_item_end();
776 TemplateBodyDecl::Observer {
777 parties,
778 pos,
779 span: self.node_span(start),
780 }
781 }
782 Some("ensure") => {
783 self.bump();
784 let expr = self.expr();
785 self.skip_to_item_end();
786 TemplateBodyDecl::Ensure {
787 expr,
788 pos,
789 span: self.node_span(start),
790 }
791 }
792 Some("key") => {
793 self.bump();
794 let expr_start = self.i;
795 let expr = self.expr();
796 let ty = if self.eat_op(":") {
797 let ty_start = self.i;
798 self.skip_to_item_end();
799 parse_type_from_tokens(&self.toks[ty_start..self.i])
800 } else {
801 let mut depth = 0i32;
804 let mut colon = None;
805 for j in expr_start..self.i {
806 match &self.toks[j].tok {
807 Tok::LParen | Tok::LBracket => depth += 1,
808 Tok::RParen | Tok::RBracket if depth > 0 => depth -= 1,
809 Tok::Op(o) if o == ":" && depth == 0 => colon = Some(j),
810 _ => {}
811 }
812 }
813 let ty = colon.and_then(|j| parse_type_from_tokens(&self.toks[j + 1..self.i]));
814 self.skip_to_item_end();
815 ty
816 };
817 TemplateBodyDecl::Key {
818 expr,
819 ty,
820 pos,
821 span: self.node_span(start),
822 }
823 }
824 Some("maintainer") => {
825 self.bump();
826 let expr = self.expr();
827 self.skip_to_item_end();
828 TemplateBodyDecl::Maintainer {
829 expr,
830 pos,
831 span: self.node_span(start),
832 }
833 }
834 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
835 self.choice_decl().map_or_else(
836 || {
837 self.skip_to_item_end();
838 TemplateBodyDecl::Other {
839 raw: self.slice_text(start),
840 span: self.node_span(start),
841 pos,
842 }
843 },
844 TemplateBodyDecl::Choice,
845 )
846 }
847 Some("interface") => self.interface_instance_decl().map_or_else(
848 || {
849 self.skip_to_item_end();
850 TemplateBodyDecl::Other {
851 raw: self.slice_text(start),
852 span: self.node_span(start),
853 pos,
854 }
855 },
856 TemplateBodyDecl::InterfaceInstance,
857 ),
858 Some("controller") => {
859 self.diag_cat(
863 DiagnosticCategory::UnsupportedSyntax,
864 "legacy 'controller ... can' syntax is not supported; \
865 choices inside this block are not analyzed",
866 );
867 self.skip_to_item_end();
868 TemplateBodyDecl::Other {
869 raw: self.slice_text(start),
870 span: self.node_span(start),
871 pos,
872 }
873 }
874 _ => {
875 self.skip_to_item_end();
876 TemplateBodyDecl::Other {
877 raw: self.slice_text(start),
878 span: self.node_span(start),
879 pos,
880 }
881 }
882 }
883 }
884
885 fn choice_decl(&mut self) -> Option<ChoiceDecl> {
886 let pos = self.pos();
887 let start_i = self.i;
888 let consuming = match self.peek().and_then(|t| t.keyword()) {
889 Some("nonconsuming") => {
890 self.bump();
891 Consuming::NonConsuming
892 }
893 Some("preconsuming") => {
894 self.bump();
895 Consuming::PreConsuming
896 }
897 Some("postconsuming") => {
898 self.bump();
899 Consuming::PostConsuming
900 }
901 _ => Consuming::Consuming,
902 };
903 if !self.eat_keyword("choice") {
904 return None;
905 }
906 let name = self.upper_name()?;
907 let return_ty = if self.eat_op(":") {
908 let ty_start = self.i;
909 self.skip_type_tokens();
910 parse_type_from_tokens(&self.toks[ty_start..self.i])
911 } else {
912 None
913 };
914 let mut params = Vec::new();
915 let mut dangling = false;
916 if self.eat_keyword("with") {
917 (params, dangling) = self.field_block();
918 }
919 let mut observers = Vec::new();
920 let mut controllers = Vec::new();
921 loop {
922 if dangling {
926 while self.eat(&Tok::VSemi) {}
927 }
928 if self.eat_keyword("observer") {
929 observers = self.expr_comma_list_no_do();
930 } else if self.eat_keyword("controller") {
931 controllers = self.expr_comma_list_no_do();
932 } else {
933 break;
934 }
935 }
936 if dangling {
937 while self.eat(&Tok::VSemi) {}
938 }
939 let body = if self
940 .peek()
941 .is_some_and(|t| !matches!(t, Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace))
942 {
943 Some(self.expr())
944 } else {
945 None
946 };
947 self.skip_to_item_end();
948 if dangling {
949 self.eat(&Tok::VRBrace);
952 self.skip_to_item_end();
953 }
954 Some(ChoiceDecl {
955 name,
956 consuming,
957 return_ty,
958 params,
959 controllers,
960 observers,
961 body,
962 pos,
963 span: self.node_span(start_i),
964 })
965 }
966
967 fn skip_type_tokens(&mut self) {
970 let mut brackets = 0usize;
971 while let Some(t) = self.peek() {
972 match t {
973 Tok::VSemi | Tok::VRBrace | Tok::VLBrace | Tok::Semi => return,
974 Tok::LParen | Tok::LBracket => brackets += 1,
975 Tok::RParen | Tok::RBracket => {
976 if brackets == 0 {
977 return;
978 }
979 brackets -= 1;
980 }
981 _ if brackets == 0
982 && matches!(
983 t.keyword(),
984 Some("with" | "controller" | "observer" | "do" | "where")
985 ) =>
986 {
987 return
988 }
989 _ => {}
990 }
991 self.i += 1;
992 }
993 }
994
995 fn interface_decl(&mut self) -> Option<InterfaceDecl> {
998 let pos = self.pos();
999 let start_i = self.i;
1000 self.bump(); if self.at_keyword("instance") {
1002 return None;
1004 }
1005 let name = self.upper_name()?;
1006 let mut requires = Vec::new();
1007 if self.eat_keyword("requires") {
1008 while let Some(r) = self.upper_name() {
1009 requires.push(r);
1010 if !self.eat(&Tok::Comma) {
1011 break;
1012 }
1013 }
1014 }
1015 if !self.eat_keyword("where") {
1016 return None;
1017 }
1018 let mut viewtype = None;
1019 let mut methods = Vec::new();
1020 let mut choices = Vec::new();
1021 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1022 return Some(InterfaceDecl {
1023 name,
1024 requires,
1025 viewtype,
1026 methods,
1027 choices,
1028 pos,
1029 span: self.node_span(start_i),
1030 });
1031 }
1032 loop {
1033 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1034 match self.peek() {
1035 None => break,
1036 Some(Tok::VRBrace | Tok::RBrace) => {
1037 self.bump();
1038 break;
1039 }
1040 Some(Tok::RParen | Tok::RBracket) => {
1045 self.bump();
1046 continue;
1047 }
1048 _ => {}
1049 }
1050 match self.peek().and_then(|t| t.keyword()) {
1051 Some("viewtype") => {
1052 self.bump();
1053 viewtype = self.upper_name();
1054 self.skip_to_item_end();
1055 }
1056 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1057 if let Some(c) = self.choice_decl() {
1058 choices.push(c);
1059 } else {
1060 self.skip_to_item_end();
1061 }
1062 }
1063 _ => {
1064 let mpos = self.pos();
1067 if let Some(Tok::LowerId {
1068 qualifier: None,
1069 name: mname,
1070 }) = self.peek().cloned()
1071 {
1072 if self.peek_at(1).is_some_and(|t| t.is_op(":")) {
1073 let mstart = self.toks[self.i].start;
1074 self.bump();
1075 self.bump();
1076 let ty_start = self.i;
1077 self.skip_to_item_end();
1078 methods.push(FieldDecl {
1080 name: mname,
1081 ty: parse_type_from_tokens(&self.toks[ty_start..self.i]),
1082 pos: mpos,
1083 span: Span::new(mstart, self.end_byte().max(mstart)),
1084 });
1085 continue;
1086 }
1087 }
1088 self.skip_to_item_end();
1089 }
1090 }
1091 }
1092 Some(InterfaceDecl {
1093 name,
1094 requires,
1095 viewtype,
1096 methods,
1097 choices,
1098 pos,
1099 span: self.node_span(start_i),
1100 })
1101 }
1102
1103 fn interface_instance_decl(&mut self) -> Option<InterfaceInstanceDecl> {
1105 let pos = self.pos();
1106 let start_i = self.i;
1107 self.bump(); if !self.eat_keyword("instance") {
1109 return None;
1110 }
1111 let interface_name = self.upper_name()?;
1112 let for_template = if self.eat_keyword("for") {
1113 self.upper_name().unwrap_or_default()
1114 } else {
1115 String::new()
1116 };
1117 let mut methods = Vec::new();
1118 if self.eat_keyword("where") && (self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1119 loop {
1120 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1121 match self.peek() {
1122 None => break,
1123 Some(Tok::VRBrace | Tok::RBrace) => {
1124 self.bump();
1125 break;
1126 }
1127 Some(Tok::RParen | Tok::RBracket) => {
1129 self.bump();
1130 continue;
1131 }
1132 _ => {}
1133 }
1134 if let Some(b) = self.binding() {
1135 methods.push(b);
1136 } else {
1137 self.skip_to_item_end();
1138 }
1139 }
1140 }
1141 Some(InterfaceInstanceDecl {
1142 interface_name,
1143 for_template,
1144 methods,
1145 pos,
1146 span: self.node_span(start_i),
1147 })
1148 }
1149
1150 fn function_item(&mut self) -> Option<Decl> {
1156 let pos = self.pos();
1157 let start_i = self.i;
1158 let name = match self.peek().cloned() {
1159 Some(Tok::LowerId {
1160 qualifier: None,
1161 name,
1162 }) => name,
1163 _ => return None,
1164 };
1165
1166 let mut j = self.i + 1;
1168 let mut is_sig = false;
1169 loop {
1170 match self.toks.get(j).map(|t| &t.tok) {
1171 Some(Tok::Comma) => {
1172 j += 1;
1173 if matches!(
1174 self.toks.get(j).map(|t| &t.tok),
1175 Some(Tok::LowerId {
1176 qualifier: None,
1177 ..
1178 })
1179 ) {
1180 j += 1;
1181 continue;
1182 }
1183 break;
1184 }
1185 Some(Tok::Op(o)) if o == ":" => {
1186 is_sig = true;
1187 break;
1188 }
1189 _ => break,
1190 }
1191 }
1192 if is_sig {
1193 self.bump(); while self.eat(&Tok::Comma) {
1195 self.bump(); }
1197 self.eat_op(":");
1198 let ty_start = self.i;
1199 self.skip_to_item_end();
1200 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
1201 return Some(Decl::Function(FunctionDecl {
1202 name,
1203 ty,
1204 equations: Vec::new(),
1205 pos,
1206 sig_span: Some(self.node_span(start_i)),
1207 span: self.node_span(start_i),
1208 }));
1209 }
1210
1211 self.bump(); let mut params = Vec::new();
1214 while !self.at_op("=") && !self.at_op("|") {
1215 if self.at_op(":") {
1218 self.bump();
1219 let mut brackets = 0usize;
1220 while let Some(t) = self.peek() {
1221 match t {
1222 Tok::Op(o) if o == "=" && brackets == 0 => break,
1223 Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace => break,
1224 Tok::LParen | Tok::LBracket => brackets += 1,
1225 Tok::RParen | Tok::RBracket => brackets = brackets.saturating_sub(1),
1226 _ => {}
1227 }
1228 self.i += 1;
1229 }
1230 continue;
1231 }
1232 if matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o)) {
1235 self.skip_to_item_end();
1236 return None;
1237 }
1238 match self.peek() {
1239 None | Some(Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace) => {
1240 self.diag(format!("could not parse equation for '{name}'"));
1241 return None;
1242 }
1243 _ => {}
1244 }
1245 match self.pattern_atom() {
1246 Some(p) => params.push(p),
1247 None => {
1248 self.diag(format!("bad parameter pattern in '{name}'"));
1249 return None;
1250 }
1251 }
1252 }
1253 let (body, guards) = self.equation_rhs()?;
1254 let where_bindings = if self.eat_keyword("where") {
1255 self.binding_block()
1256 } else {
1257 Vec::new()
1258 };
1259 self.skip_to_item_end();
1260 Some(Decl::Function(FunctionDecl {
1261 name,
1262 ty: None,
1263 equations: vec![Equation {
1264 params,
1265 body,
1266 guards,
1267 where_bindings,
1268 pos,
1269 span: self.node_span(start_i),
1270 }],
1271 pos,
1272 sig_span: None,
1273 span: self.node_span(start_i),
1274 }))
1275 }
1276
1277 fn equation_rhs(&mut self) -> Option<(Expr, Vec<(Expr, Expr)>)> {
1279 if self.eat_op("=") {
1280 return Some((self.expr(), Vec::new()));
1281 }
1282 let mut guards = Vec::new();
1283 while self.eat_op("|") {
1284 let g = loop {
1287 let g = self.expr();
1288 if self.eat_op("<-") {
1289 let _ = self.expr(); }
1291 if !self.eat(&Tok::Comma) {
1292 break g;
1293 }
1294 };
1295 if !self.eat_op("=") {
1296 self.diag("expected '=' after guard");
1297 return None;
1298 }
1299 let e = self.expr();
1300 guards.push((g, e));
1301 }
1302 if guards.is_empty() {
1303 self.diag("expected '=' or guarded right-hand side in equation");
1304 None
1305 } else {
1306 let first = guards[0].1.clone();
1307 Some((first, guards))
1308 }
1309 }
1310
1311 fn binding_block(&mut self) -> Vec<Binding> {
1313 let mut bindings = Vec::new();
1314 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1315 return bindings;
1316 }
1317 loop {
1318 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1319 match self.peek() {
1320 None => break,
1321 Some(Tok::VRBrace | Tok::RBrace) => {
1322 self.bump();
1323 break;
1324 }
1325 Some(Tok::RParen | Tok::RBracket) => {
1330 self.bump();
1331 continue;
1332 }
1333 _ => {}
1334 }
1335 match self.binding() {
1336 Some(b) => bindings.push(b),
1337 None => self.skip_to_item_end(),
1338 }
1339 }
1340 bindings
1341 }
1342
1343 fn binding(&mut self) -> Option<Binding> {
1346 let pos = self.pos();
1347 let start_i = self.i;
1348 if self.at(&Tok::LParen)
1351 && matches!(self.peek_at(1), Some(Tok::Op(_)))
1352 && self.peek_at(2) == Some(&Tok::RParen)
1353 {
1354 self.skip_to_item_end();
1355 return None;
1356 }
1357 let pat = self.pattern_atom()?;
1358 let mut params = Vec::new();
1359 loop {
1360 if self.at_op("=") {
1361 self.bump();
1362 let expr = self.expr();
1363 if self.eat_keyword("where") {
1365 let _ = self.binding_block();
1366 }
1367 return Some(Binding {
1368 pat,
1369 params,
1370 expr,
1371 pos,
1372 span: self.node_span(start_i),
1373 });
1374 }
1375 if self.at_op("|") {
1376 let (body, _) = self.equation_rhs()?;
1377 if self.eat_keyword("where") {
1378 let _ = self.binding_block();
1379 }
1380 return Some(Binding {
1381 pat,
1382 params,
1383 expr: body,
1384 pos,
1385 span: self.node_span(start_i),
1386 });
1387 }
1388 if self.at_op(":") {
1389 if params.is_empty() {
1390 self.skip_to_item_end();
1392 return None;
1393 }
1394 self.bump();
1397 let mut brackets = 0usize;
1398 while let Some(t) = self.peek() {
1399 match t {
1400 Tok::Op(o) if o == "=" && brackets == 0 => break,
1401 Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace => break,
1402 Tok::LParen | Tok::LBracket => brackets += 1,
1403 Tok::RParen | Tok::RBracket => brackets = brackets.saturating_sub(1),
1404 _ => {}
1405 }
1406 self.i += 1;
1407 }
1408 continue;
1409 }
1410 if matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o)) {
1413 self.skip_to_item_end();
1414 return None;
1415 }
1416 match self.peek() {
1417 None | Some(Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace) => return None,
1418 _ => {}
1419 }
1420 params.push(self.pattern_atom()?);
1421 }
1422 }
1423
1424 fn pattern_atom(&mut self) -> Option<Pat> {
1427 if self.depth >= MAX_DEPTH {
1428 return None;
1429 }
1430 self.depth += 1;
1431 let result = self.pattern_atom_inner();
1432 self.depth -= 1;
1433 result
1434 }
1435
1436 fn pattern_atom_inner(&mut self) -> Option<Pat> {
1437 let pos = self.pos();
1438 let start_i = self.i;
1439 if self.at_op("~") || self.at_op("!") {
1441 self.bump();
1442 return self.pattern_atom();
1443 }
1444 match self.peek().cloned() {
1445 Some(Tok::LowerId {
1446 qualifier: None,
1447 name,
1448 }) => {
1449 self.bump();
1450 if name == "_" {
1451 return Some(Pat::Wild {
1452 pos,
1453 span: self.node_span(start_i),
1454 });
1455 }
1456 if self.at_op("@") {
1457 self.bump();
1458 let inner = self.pattern_atom()?;
1459 return Some(Pat::As {
1460 name,
1461 pat: Box::new(inner),
1462 pos,
1463 span: self.node_span(start_i),
1464 });
1465 }
1466 Some(Pat::Var {
1467 name,
1468 pos,
1469 span: self.node_span(start_i),
1470 })
1471 }
1472 Some(Tok::Op(o)) if o == "_" => {
1473 self.bump();
1474 Some(Pat::Wild {
1475 pos,
1476 span: self.node_span(start_i),
1477 })
1478 }
1479 Some(Tok::UpperId { qualifier, name }) => {
1480 self.bump();
1481 if self.at(&Tok::LBrace) {
1484 self.skip_balanced_braces();
1485 } else if self.eat_keyword("with") {
1486 let _ = self.record_fields();
1487 }
1488 Some(Pat::Con {
1489 qualifier,
1490 name,
1491 args: Vec::new(),
1492 pos,
1493 span: self.node_span(start_i),
1494 })
1495 }
1496 Some(Tok::IntLit(text)) => {
1497 self.bump();
1498 Some(Pat::Lit {
1499 kind: LitKind::Int,
1500 text,
1501 pos,
1502 span: self.node_span(start_i),
1503 })
1504 }
1505 Some(Tok::DecimalLit(text)) => {
1506 self.bump();
1507 Some(Pat::Lit {
1508 kind: LitKind::Decimal,
1509 text,
1510 pos,
1511 span: self.node_span(start_i),
1512 })
1513 }
1514 Some(Tok::StringLit(text)) => {
1515 self.bump();
1516 Some(Pat::Lit {
1517 kind: LitKind::Text,
1518 text,
1519 pos,
1520 span: self.node_span(start_i),
1521 })
1522 }
1523 Some(Tok::CharLit(text)) => {
1524 self.bump();
1525 Some(Pat::Lit {
1526 kind: LitKind::Char,
1527 text,
1528 pos,
1529 span: self.node_span(start_i),
1530 })
1531 }
1532 Some(Tok::LParen) => {
1533 self.bump();
1534 if self.eat(&Tok::RParen) {
1535 return Some(Pat::Con {
1536 qualifier: None,
1537 name: "()".to_string(),
1538 args: Vec::new(),
1539 pos,
1540 span: self.node_span(start_i),
1541 });
1542 }
1543 {
1549 let mut depth = 0usize;
1550 let mut j = self.i;
1551 let mut arrow = None;
1552 while let Some(t) = self.toks.get(j).map(|t| &t.tok) {
1553 match t {
1554 Tok::LParen | Tok::LBracket => depth += 1,
1555 Tok::RParen | Tok::RBracket => {
1556 if depth == 0 {
1557 break;
1558 }
1559 depth -= 1;
1560 }
1561 Tok::Op(o) if o == ":" && depth == 0 => break,
1562 Tok::Op(o) if o == "->" && depth == 0 => {
1563 arrow = Some(j);
1564 break;
1565 }
1566 Tok::VSemi | Tok::VRBrace => break,
1567 Tok::Op(o) if o == "\\" => break,
1569 _ => {}
1570 }
1571 j += 1;
1572 }
1573 if let Some(j) = arrow {
1574 self.i = j + 1; let inner = self.pattern()?;
1576 self.eat(&Tok::RParen);
1577 return Some(inner);
1578 }
1579 }
1580 let first = self.pattern()?;
1581 if self.at_op(":") {
1583 let mut depth = 0usize;
1584 while let Some(t) = self.peek() {
1585 match t {
1586 Tok::LParen | Tok::LBracket => depth += 1,
1587 Tok::RParen if depth == 0 => break,
1588 Tok::RParen | Tok::RBracket => depth = depth.saturating_sub(1),
1589 Tok::VSemi | Tok::VRBrace => break,
1590 _ => {}
1591 }
1592 self.i += 1;
1593 }
1594 }
1595 if self.at(&Tok::Comma) {
1596 let mut items = vec![first];
1597 while self.eat(&Tok::Comma) {
1598 items.push(self.pattern()?);
1599 }
1600 self.eat(&Tok::RParen);
1601 return Some(Pat::Tuple {
1602 items,
1603 pos,
1604 span: self.node_span(start_i),
1605 });
1606 }
1607 self.eat(&Tok::RParen);
1608 Some(first)
1609 }
1610 Some(Tok::LBracket) => {
1611 self.bump();
1612 let mut items = Vec::new();
1613 if !self.eat(&Tok::RBracket) {
1614 loop {
1615 items.push(self.pattern()?);
1616 if !self.eat(&Tok::Comma) {
1617 break;
1618 }
1619 }
1620 self.eat(&Tok::RBracket);
1621 }
1622 Some(Pat::List {
1623 items,
1624 pos,
1625 span: self.node_span(start_i),
1626 })
1627 }
1628 _ => None,
1629 }
1630 }
1631
1632 fn pattern(&mut self) -> Option<Pat> {
1634 if self.depth >= MAX_DEPTH {
1635 return None;
1636 }
1637 self.depth += 1;
1638 let result = self.pattern_inner();
1639 self.depth -= 1;
1640 result
1641 }
1642
1643 fn pattern_inner(&mut self) -> Option<Pat> {
1644 let pos = self.pos();
1645 let start_i = self.i;
1646 let first = match self.peek().cloned() {
1647 Some(Tok::UpperId { qualifier, name }) => {
1648 self.bump();
1649 if self.at(&Tok::LBrace) || self.at_keyword("with") {
1650 if self.eat_keyword("with") {
1651 let _ = self.record_fields();
1652 } else {
1653 self.skip_balanced_braces();
1654 }
1655 Pat::Con {
1656 qualifier,
1657 name,
1658 args: Vec::new(),
1659 pos,
1660 span: self.node_span(start_i),
1661 }
1662 } else {
1663 let mut args = Vec::new();
1664 while let Some(a) = self.try_pattern_atom() {
1665 args.push(a);
1666 }
1667 Pat::Con {
1668 qualifier,
1669 name,
1670 args,
1671 pos,
1672 span: self.node_span(start_i),
1673 }
1674 }
1675 }
1676 _ => self.pattern_atom()?,
1677 };
1678 if self.at_op("::") {
1679 self.bump();
1680 let rest = self.pattern()?;
1681 return Some(Pat::Con {
1682 qualifier: None,
1683 name: "::".to_string(),
1684 args: vec![first, rest],
1685 pos,
1686 span: self.node_span(start_i),
1687 });
1688 }
1689 Some(first)
1690 }
1691
1692 fn try_pattern_atom(&mut self) -> Option<Pat> {
1693 match self.peek() {
1694 Some(
1695 Tok::LowerId {
1696 qualifier: None, ..
1697 }
1698 | Tok::UpperId { .. }
1699 | Tok::IntLit(_)
1700 | Tok::DecimalLit(_)
1701 | Tok::StringLit(_)
1702 | Tok::CharLit(_)
1703 | Tok::LParen
1704 | Tok::LBracket,
1705 ) => self.pattern_atom(),
1706 _ => None,
1707 }
1708 }
1709
1710 fn skip_balanced_braces(&mut self) {
1711 let mut depth = 0usize;
1712 while let Some(t) = self.peek() {
1713 match t {
1714 Tok::LBrace => depth += 1,
1715 Tok::RBrace => {
1716 if depth == 0 {
1717 return;
1718 }
1719 depth -= 1;
1720 if depth == 0 {
1721 self.i += 1;
1722 return;
1723 }
1724 }
1725 _ => {}
1726 }
1727 self.i += 1;
1728 }
1729 }
1730
1731 fn expr(&mut self) -> Expr {
1734 self.expr_prec(0, true)
1735 }
1736
1737 fn expr_no_do(&mut self) -> Expr {
1738 self.expr_prec(0, false)
1739 }
1740
1741 fn expr_comma_list(&mut self) -> Vec<Expr> {
1743 let mut out = vec![self.expr()];
1744 while self.eat(&Tok::Comma) {
1745 out.push(self.expr());
1746 }
1747 out
1748 }
1749
1750 fn expr_comma_list_no_do(&mut self) -> Vec<Expr> {
1751 let mut out = vec![self.expr_no_do()];
1752 while self.eat(&Tok::Comma) {
1753 out.push(self.expr_no_do());
1754 }
1755 out
1756 }
1757
1758 fn expr_prec(&mut self, min_prec: u8, allow_do: bool) -> Expr {
1759 let pos = self.pos();
1760 let start_i = self.i;
1761 if self.depth >= MAX_DEPTH {
1762 self.diag_cat(
1767 DiagnosticCategory::RecursionLimit,
1768 "expression nesting too deep; truncated to raw text",
1769 );
1770 let start = self.i;
1771 self.skip_to_item_end();
1772 if self.i == start {
1773 self.bump();
1774 }
1775 return Expr::Error {
1776 raw: self.slice_text(start),
1777 span: self.node_span(start),
1778 pos,
1779 };
1780 }
1781 self.depth += 1;
1782 let result = self.expr_prec_inner(min_prec, allow_do, pos, start_i);
1783 self.depth -= 1;
1784 result
1785 }
1786
1787 fn expr_prec_inner(&mut self, min_prec: u8, allow_do: bool, pos: Pos, start_i: usize) -> Expr {
1788 let mut lhs = match self.unary(allow_do) {
1789 Some(e) => e,
1790 None => {
1791 let start = self.i;
1793 self.skip_to_item_end();
1794 if self.i == start {
1795 self.bump();
1796 }
1797 return Expr::Error {
1798 raw: self.slice_text(start),
1799 span: self.node_span(start),
1800 pos,
1801 };
1802 }
1803 };
1804 loop {
1805 let (op, prec, right_assoc) = match self.peek() {
1806 Some(Tok::Op(o)) => {
1807 let o = o.clone();
1808 if is_reserved_op(&o) {
1809 if o == ":" {
1811 self.bump();
1812 self.skip_type_tokens();
1813 continue;
1814 }
1815 break;
1816 }
1817 let (p, r) = fixity(&o);
1818 (o, p, r)
1819 }
1820 Some(Tok::Backtick) => {
1821 let name = match self.peek_at(1) {
1823 Some(
1824 Tok::LowerId { qualifier, name } | Tok::UpperId { qualifier, name },
1825 ) => qualifier
1826 .as_ref()
1827 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
1828 _ => break,
1829 };
1830 if self.peek_at(2) != Some(&Tok::Backtick) {
1831 break;
1832 }
1833 (format!("`{name}`"), 9, false)
1834 }
1835 _ => break,
1836 };
1837 if prec < min_prec {
1838 break;
1839 }
1840 self.bump();
1841 if op.starts_with('`') {
1842 self.bump();
1843 self.bump();
1844 }
1845 let next_min = if right_assoc { prec } else { prec + 1 };
1846 let rhs = self.expr_prec(next_min, allow_do);
1847 lhs = Expr::BinOp {
1848 op,
1849 lhs: Box::new(lhs),
1850 rhs: Box::new(rhs),
1851 pos,
1852 span: self.node_span(start_i),
1853 };
1854 }
1855 lhs
1856 }
1857
1858 fn unary(&mut self, allow_do: bool) -> Option<Expr> {
1859 let pos = self.pos();
1860 let start_i = self.i;
1861 if self.at_op("-") {
1862 self.bump();
1863 let e = self.unary(allow_do)?;
1864 return Some(Expr::Neg {
1865 expr: Box::new(e),
1866 pos,
1867 span: self.node_span(start_i),
1868 });
1869 }
1870 self.application(allow_do)
1871 }
1872
1873 fn application(&mut self, allow_do: bool) -> Option<Expr> {
1874 let pos = self.pos();
1875 let start_i = self.i;
1876 let head0 = self.atom(allow_do)?;
1877 let mut head = self.projection_tail(head0);
1878 let mut args = Vec::new();
1879 loop {
1880 if self.at_keyword("with") {
1883 let target = args.pop().unwrap_or_else(|| {
1884 std::mem::replace(
1885 &mut head,
1886 Expr::Error {
1887 raw: String::new(),
1888 pos,
1889 span: Span::default(),
1890 },
1891 )
1892 });
1893 self.bump(); let fields = self.record_fields();
1895 let tpos = target.pos();
1896 let sp = Span::new(target.span().start, self.end_byte());
1897 let rec = Expr::Record {
1898 base: Box::new(target),
1899 fields,
1900 pos: tpos,
1901 span: sp,
1902 };
1903 if matches!(head, Expr::Error { ref raw, .. } if raw.is_empty()) {
1904 head = rec;
1905 } else {
1906 args.push(rec);
1907 }
1908 continue;
1909 }
1910 if !allow_do && self.at_keyword("do") {
1911 break;
1912 }
1913 if self.at_op("@") {
1915 self.bump();
1916 match self.peek() {
1917 Some(Tok::UpperId { .. } | Tok::LowerId { .. }) => {
1918 self.bump();
1919 }
1920 Some(Tok::LParen) => self.skip_balanced_parens(),
1921 Some(Tok::LBracket) => {
1922 let mut depth = 0usize;
1923 while let Some(t) = self.peek() {
1924 match t {
1925 Tok::LBracket => depth += 1,
1926 Tok::RBracket => {
1927 if depth == 0 {
1928 break;
1929 }
1930 depth -= 1;
1931 if depth == 0 {
1932 self.i += 1;
1933 break;
1934 }
1935 }
1936 _ => {}
1937 }
1938 self.i += 1;
1939 }
1940 }
1941 _ => {}
1942 }
1943 continue;
1944 }
1945 match self.try_atom(allow_do) {
1946 Some(a) => args.push(self.projection_tail(a)),
1947 None => break,
1948 }
1949 }
1950 if args.is_empty() {
1951 Some(head)
1952 } else {
1953 Some(Expr::App {
1954 func: Box::new(head),
1955 args,
1956 pos,
1957 span: self.node_span(start_i),
1958 })
1959 }
1960 }
1961
1962 fn record_fields(&mut self) -> Vec<FieldAssign> {
1964 let mut fields = Vec::new();
1965 let explicit = self.at(&Tok::LBrace);
1966 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1967 return fields;
1968 }
1969 loop {
1970 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) || self.eat(&Tok::Comma) {}
1971 match self.peek() {
1972 None => break,
1973 Some(Tok::VRBrace) if !explicit => {
1974 self.bump();
1975 break;
1976 }
1977 Some(Tok::RBrace) => {
1978 self.bump();
1979 break;
1980 }
1981 Some(Tok::RParen | Tok::RBracket) => {
1983 self.bump();
1984 continue;
1985 }
1986 _ => {}
1987 }
1988 let pos = self.pos();
1989 let start_i = self.i;
1990 if self.at_op("..") {
1991 self.bump();
1992 fields.push(FieldAssign {
1993 name: "..".to_string(),
1994 value: None,
1995 pos,
1996 span: self.node_span(start_i),
1997 });
1998 continue;
1999 }
2000 let name = match self.peek().cloned() {
2001 Some(Tok::LowerId {
2002 qualifier: None,
2003 name,
2004 }) => {
2005 self.bump();
2006 name
2007 }
2008 _ => {
2009 self.skip_to_item_end();
2010 continue;
2011 }
2012 };
2013 if self.eat_op("=") {
2014 let value = self.expr_prec(1, true);
2015 fields.push(FieldAssign {
2016 name,
2017 value: Some(value),
2018 pos,
2019 span: self.node_span(start_i),
2020 });
2021 } else {
2022 fields.push(FieldAssign {
2024 name,
2025 value: None,
2026 pos,
2027 span: self.node_span(start_i),
2028 });
2029 }
2030 }
2031 fields
2032 }
2033
2034 fn try_atom(&mut self, allow_do: bool) -> Option<Expr> {
2035 match self.peek() {
2036 Some(Tok::LowerId { .. }) => {
2037 let kw = self.peek().and_then(|t| t.keyword());
2038 match kw {
2039 Some("do") if allow_do => self.atom(allow_do),
2041 Some(
2044 "if" | "case" | "do" | "let" | "try" | "where" | "then" | "else" | "of"
2045 | "in" | "controller" | "with" | "catch",
2046 ) => None,
2047 _ => self.atom(allow_do),
2048 }
2049 }
2050 Some(
2051 Tok::UpperId { .. }
2052 | Tok::IntLit(_)
2053 | Tok::DecimalLit(_)
2054 | Tok::StringLit(_)
2055 | Tok::CharLit(_)
2056 | Tok::LParen
2057 | Tok::LBracket,
2058 ) => self.atom(allow_do),
2059 Some(Tok::Op(o)) if o == "\\" => self.atom(allow_do),
2061 _ => None,
2062 }
2063 }
2064
2065 fn projection_tail(&mut self, mut base: Expr) -> Expr {
2072 while self.at_tight_projection() {
2073 let start = base.span().start;
2074 let pos = base.pos();
2075 self.bump(); let Some(field_tok) = self.bump() else {
2077 self.diag("expected projection field after '.'");
2078 return base;
2079 };
2080 let Tok::LowerId { qualifier, name } = field_tok.tok else {
2081 self.diag("expected projection field after '.'");
2082 return base;
2083 };
2084 let field = Expr::Var {
2085 qualifier,
2086 name,
2087 pos: field_tok.pos,
2088 span: Span::new(field_tok.start, field_tok.end),
2089 };
2090 base = Expr::BinOp {
2091 op: ".".to_string(),
2092 lhs: Box::new(base),
2093 rhs: Box::new(field),
2094 pos,
2095 span: Span::new(start, self.end_byte()),
2096 };
2097 }
2098 base
2099 }
2100
2101 fn at_tight_projection(&self) -> bool {
2105 if self.i == 0 {
2106 return false;
2107 }
2108 let dot = match self.toks.get(self.i) {
2109 Some(t) => t,
2110 None => return false,
2111 };
2112 if !matches!(&dot.tok, Tok::Op(o) if o == ".") {
2113 return false;
2114 }
2115 let prev = &self.toks[self.i - 1];
2119 if prev.is_virtual() || prev.end != dot.start {
2120 return false;
2121 }
2122 self.toks.get(self.i + 1).is_some_and(|t| {
2124 matches!(
2125 &t.tok,
2126 Tok::LowerId {
2127 qualifier: None,
2128 ..
2129 }
2130 ) && t.start == dot.end
2131 })
2132 }
2133
2134 fn atom(&mut self, allow_do: bool) -> Option<Expr> {
2135 let pos = self.pos();
2136 let start_i = self.i;
2137 match self.peek().cloned() {
2138 Some(Tok::LowerId { qualifier, name }) => {
2139 match name.as_str() {
2140 "if" if qualifier.is_none() => return self.if_expr(),
2141 "case" if qualifier.is_none() => return self.case_expr(),
2142 "do" if qualifier.is_none() => {
2143 if !allow_do {
2144 return None;
2145 }
2146 return self.do_expr();
2147 }
2148 "let" if qualifier.is_none() => return self.let_expr(),
2149 "try" if qualifier.is_none() => return self.try_expr(),
2150 _ => {}
2151 }
2152 self.bump();
2153 Some(Expr::Var {
2154 qualifier,
2155 name,
2156 pos,
2157 span: self.node_span(start_i),
2158 })
2159 }
2160 Some(Tok::UpperId { qualifier, name }) => {
2161 self.bump();
2162 let base = Expr::Con {
2163 qualifier,
2164 name,
2165 pos,
2166 span: self.node_span(start_i),
2167 };
2168 if self.at(&Tok::LBrace) {
2170 let fields = self.record_fields();
2171 return Some(Expr::Record {
2172 base: Box::new(base),
2173 fields,
2174 pos,
2175 span: self.node_span(start_i),
2176 });
2177 }
2178 Some(base)
2179 }
2180 Some(Tok::IntLit(text)) => {
2181 self.bump();
2182 Some(Expr::Lit {
2183 kind: LitKind::Int,
2184 text,
2185 pos,
2186 span: self.node_span(start_i),
2187 })
2188 }
2189 Some(Tok::DecimalLit(text)) => {
2190 self.bump();
2191 Some(Expr::Lit {
2192 kind: LitKind::Decimal,
2193 text,
2194 pos,
2195 span: self.node_span(start_i),
2196 })
2197 }
2198 Some(Tok::StringLit(text)) => {
2199 self.bump();
2200 Some(Expr::Lit {
2201 kind: LitKind::Text,
2202 text,
2203 pos,
2204 span: self.node_span(start_i),
2205 })
2206 }
2207 Some(Tok::CharLit(text)) => {
2208 self.bump();
2209 Some(Expr::Lit {
2210 kind: LitKind::Char,
2211 text,
2212 pos,
2213 span: self.node_span(start_i),
2214 })
2215 }
2216 Some(Tok::Op(o)) if o == "\\" => self.lambda_expr(),
2217 Some(Tok::LParen) => self.paren_expr(),
2218 Some(Tok::LBracket) => self.list_expr(),
2219 _ => None,
2220 }
2221 }
2222
2223 fn if_expr(&mut self) -> Option<Expr> {
2224 let pos = self.pos();
2225 let start_i = self.i;
2226 self.bump(); let cond = self.expr();
2228 self.eat(&Tok::VSemi); if !self.eat_keyword("then") {
2230 self.diag("expected 'then'");
2231 return Some(Expr::Error {
2232 raw: format!("if {}", cond.render()),
2233 pos,
2234 span: self.node_span(start_i),
2235 });
2236 }
2237 let then_branch = self.expr();
2238 self.eat(&Tok::VSemi);
2239 if !self.eat_keyword("else") {
2240 self.diag("expected 'else'");
2241 return Some(Expr::Error {
2242 raw: format!("if {} then {}", cond.render(), then_branch.render()),
2243 pos,
2244 span: self.node_span(start_i),
2245 });
2246 }
2247 let else_branch = self.expr();
2248 Some(Expr::If {
2249 cond: Box::new(cond),
2250 then_branch: Box::new(then_branch),
2251 else_branch: Box::new(else_branch),
2252 pos,
2253 span: self.node_span(start_i),
2254 })
2255 }
2256
2257 fn case_expr(&mut self) -> Option<Expr> {
2258 let pos = self.pos();
2259 let start_i = self.i;
2260 self.bump(); let scrutinee = self.expr_no_do();
2262 if !self.eat_keyword("of") {
2263 self.diag("expected 'of' in case expression");
2264 return Some(Expr::Error {
2265 raw: format!("case {}", scrutinee.render()),
2266 pos,
2267 span: self.node_span(start_i),
2268 });
2269 }
2270 let mut alts = Vec::new();
2271 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2272 loop {
2273 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2274 match self.peek() {
2275 None => break,
2276 Some(Tok::VRBrace | Tok::RBrace) => {
2277 self.bump();
2278 break;
2279 }
2280 Some(Tok::RParen | Tok::RBracket) => {
2282 self.bump();
2283 continue;
2284 }
2285 _ => {}
2286 }
2287 if self.eat_keyword("where") {
2289 let _ = self.binding_block();
2290 continue;
2291 }
2292 match self.case_alt() {
2293 Some(a) => alts.push(a),
2294 None => self.skip_to_item_end(),
2295 }
2296 }
2297 }
2298 Some(Expr::Case {
2299 scrutinee: Box::new(scrutinee),
2300 alts,
2301 pos,
2302 span: self.node_span(start_i),
2303 })
2304 }
2305
2306 fn case_alt(&mut self) -> Option<Alt> {
2307 let pos = self.pos();
2308 let start_i = self.i;
2309 let pat = self.pattern()?;
2310 if self.at_op("|") {
2311 let mut first: Option<Expr> = None;
2315 while self.eat_op("|") {
2316 loop {
2317 let _guard = self.expr();
2318 if self.eat_op("<-") {
2319 let _ = self.expr();
2320 }
2321 if !self.eat(&Tok::Comma) {
2322 break;
2323 }
2324 }
2325 if !self.eat_op("->") {
2326 self.diag("expected '->' in guarded case alternative");
2327 return None;
2328 }
2329 let body = self.expr();
2330 if first.is_none() {
2331 first = Some(body);
2332 }
2333 }
2334 return Some(Alt {
2335 pat,
2336 body: first?,
2337 pos,
2338 span: self.node_span(start_i),
2339 });
2340 }
2341 if !self.eat_op("->") {
2342 self.diag("expected '->' in case alternative");
2343 return None;
2344 }
2345 let body = self.expr();
2346 Some(Alt {
2347 pat,
2348 body,
2349 pos,
2350 span: self.node_span(start_i),
2351 })
2352 }
2353
2354 fn do_expr(&mut self) -> Option<Expr> {
2355 let pos = self.pos();
2356 let start_i = self.i;
2357 self.bump(); let mut stmts = Vec::new();
2359 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2360 loop {
2361 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2362 match self.peek() {
2363 None => break,
2364 Some(Tok::VRBrace | Tok::RBrace) => {
2365 self.bump();
2366 break;
2367 }
2368 Some(Tok::RParen | Tok::RBracket) => {
2370 self.bump();
2371 continue;
2372 }
2373 _ => {}
2374 }
2375 stmts.push(self.do_stmt());
2376 }
2377 }
2378 Some(Expr::Do {
2379 stmts,
2380 pos,
2381 span: self.node_span(start_i),
2382 })
2383 }
2384
2385 fn do_stmt(&mut self) -> DoStmt {
2386 let pos = self.pos();
2387 let start_i = self.i;
2388 if self.at_keyword("let") {
2389 self.bump();
2390 let bindings = self.binding_block();
2391 if self.eat_keyword("in") {
2393 let body = self.expr();
2394 return DoStmt::Expr {
2395 expr: Expr::LetIn {
2396 bindings,
2397 body: Box::new(body),
2398 pos,
2399 span: self.node_span(start_i),
2400 },
2401 pos,
2402 span: self.node_span(start_i),
2403 };
2404 }
2405 return DoStmt::Let {
2406 bindings,
2407 pos,
2408 span: self.node_span(start_i),
2409 };
2410 }
2411 let snapshot = self.i;
2413 if let Some(pat) = self.try_bind_pattern() {
2414 if self.at_op("<-") {
2415 self.bump();
2416 let expr = self.expr();
2417 return DoStmt::Bind {
2418 pat,
2419 expr,
2420 pos,
2421 span: self.node_span(start_i),
2422 };
2423 }
2424 }
2425 self.i = snapshot;
2426 let expr = self.expr();
2427 DoStmt::Expr {
2428 expr,
2429 pos,
2430 span: self.node_span(start_i),
2431 }
2432 }
2433
2434 fn try_bind_pattern(&mut self) -> Option<Pat> {
2437 self.pattern()
2438 }
2439
2440 fn let_expr(&mut self) -> Option<Expr> {
2441 let pos = self.pos();
2442 let start_i = self.i;
2443 self.bump(); let bindings = self.binding_block();
2445 if self.eat_keyword("in") {
2446 let body = self.expr();
2447 return Some(Expr::LetIn {
2448 bindings,
2449 body: Box::new(body),
2450 pos,
2451 span: self.node_span(start_i),
2452 });
2453 }
2454 Some(Expr::LetIn {
2456 bindings,
2457 body: Box::new(Expr::Error {
2458 raw: String::new(),
2459 pos,
2460 span: self.node_span(start_i),
2461 }),
2462 pos,
2463 span: self.node_span(start_i),
2464 })
2465 }
2466
2467 fn try_expr(&mut self) -> Option<Expr> {
2468 let pos = self.pos();
2469 let start_i = self.i;
2470 self.bump(); let body = self.expr();
2472 let mut handlers = Vec::new();
2473 self.eat(&Tok::VSemi);
2474 if self.eat_keyword("catch") {
2475 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2476 loop {
2477 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2478 match self.peek() {
2479 None => break,
2480 Some(Tok::VRBrace | Tok::RBrace) => {
2481 self.bump();
2482 break;
2483 }
2484 Some(Tok::RParen | Tok::RBracket) => {
2486 self.bump();
2487 continue;
2488 }
2489 _ => {}
2490 }
2491 match self.case_alt() {
2492 Some(a) => handlers.push(a),
2493 None => self.skip_to_item_end(),
2494 }
2495 }
2496 } else if let Some(a) = self.case_alt() {
2497 handlers.push(a);
2499 }
2500 }
2501 Some(Expr::Try {
2502 body: Box::new(body),
2503 handlers,
2504 pos,
2505 span: self.node_span(start_i),
2506 })
2507 }
2508
2509 fn lambda_expr(&mut self) -> Option<Expr> {
2510 let pos = self.pos();
2511 let start_i = self.i;
2512 self.bump(); if self.eat_keyword("case") {
2515 let mut alts = Vec::new();
2516 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2517 loop {
2518 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2519 match self.peek() {
2520 None => break,
2521 Some(Tok::VRBrace | Tok::RBrace) => {
2522 self.bump();
2523 break;
2524 }
2525 Some(Tok::RParen | Tok::RBracket) => {
2526 self.bump();
2527 continue;
2528 }
2529 _ => {}
2530 }
2531 match self.case_alt() {
2532 Some(a) => alts.push(a),
2533 None => self.skip_to_item_end(),
2534 }
2535 }
2536 }
2537 return Some(Expr::Lambda {
2538 params: vec![Pat::Var {
2539 name: "_".to_string(),
2540 pos,
2541 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2542 }],
2543 body: Box::new(Expr::Case {
2544 scrutinee: Box::new(Expr::Var {
2545 qualifier: None,
2546 name: "_".to_string(),
2547 pos,
2548 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2549 }),
2550 alts,
2551 pos,
2552 span: self.node_span(start_i),
2553 }),
2554 pos,
2555 span: self.node_span(start_i),
2556 });
2557 }
2558 let mut params = Vec::new();
2559 while !self.at_op("->") {
2560 match self.pattern_atom() {
2561 Some(p) => params.push(p),
2562 None => {
2563 self.diag("bad lambda parameter");
2564 let start = self.i;
2565 self.skip_to_item_end();
2566 return Some(Expr::Error {
2567 raw: format!("\\{}", self.slice_text(start)),
2568 pos,
2569 span: self.node_span(start_i),
2570 });
2571 }
2572 }
2573 }
2574 self.bump(); let body = self.expr();
2576 Some(Expr::Lambda {
2577 params,
2578 body: Box::new(body),
2579 pos,
2580 span: self.node_span(start_i),
2581 })
2582 }
2583
2584 fn paren_expr(&mut self) -> Option<Expr> {
2585 let pos = self.pos();
2586 let start_i = self.i;
2587 self.bump(); if self.eat(&Tok::RParen) {
2589 return Some(Expr::Con {
2590 qualifier: None,
2591 name: "()".to_string(),
2592 pos,
2593 span: self.node_span(start_i),
2594 });
2595 }
2596 if let Some(Tok::Op(o)) = self.peek().cloned() {
2598 if !is_reserved_op(&o) && o != "\\" && o != "-" {
2599 self.bump();
2600 if self.eat(&Tok::RParen) {
2601 return Some(Expr::Section {
2602 op: o,
2603 operand: None,
2604 left: false,
2605 pos,
2606 span: self.node_span(start_i),
2607 });
2608 }
2609 let operand = self.expr();
2610 self.eat(&Tok::RParen);
2611 return Some(Expr::Section {
2612 op: o,
2613 operand: Some(Box::new(operand)),
2614 left: false,
2615 pos,
2616 span: self.node_span(start_i),
2617 });
2618 }
2619 }
2620 let first = self.expr();
2621 if self.at(&Tok::Comma) {
2622 let mut items = vec![first];
2623 while self.eat(&Tok::Comma) {
2624 items.push(self.expr());
2625 }
2626 self.eat(&Tok::RParen);
2627 return Some(Expr::Tuple {
2628 items,
2629 pos,
2630 span: self.node_span(start_i),
2631 });
2632 }
2633 if let Some(Tok::Op(o)) = self.peek().cloned() {
2635 if !is_reserved_op(&o) && self.peek_at(1) == Some(&Tok::RParen) {
2636 self.bump();
2637 self.bump();
2638 return Some(Expr::Section {
2639 op: o,
2640 operand: Some(Box::new(first)),
2641 left: true,
2642 pos,
2643 span: self.node_span(start_i),
2644 });
2645 }
2646 }
2647 self.eat(&Tok::RParen);
2648 Some(first)
2649 }
2650
2651 fn list_expr(&mut self) -> Option<Expr> {
2652 let pos = self.pos();
2653 let start_i = self.i;
2654 self.bump(); let mut items = Vec::new();
2656 if self.eat(&Tok::RBracket) {
2657 return Some(Expr::List {
2658 items,
2659 pos,
2660 span: self.node_span(start_i),
2661 });
2662 }
2663 loop {
2664 let e = self.expr();
2665 if self.at_op("..") {
2667 self.bump();
2668 let hi = if self.at(&Tok::RBracket) {
2669 Expr::Error {
2670 raw: String::new(),
2671 pos,
2672 span: self.node_span(start_i),
2673 }
2674 } else {
2675 self.expr()
2676 };
2677 self.eat(&Tok::RBracket);
2678 return Some(Expr::BinOp {
2679 op: "..".to_string(),
2680 lhs: Box::new(e),
2681 rhs: Box::new(hi),
2682 pos,
2683 span: self.node_span(start_i),
2684 });
2685 }
2686 if self.at_op("|") {
2688 let start = self.i;
2689 let mut brackets = 1usize;
2690 while let Some(t) = self.peek() {
2691 match t {
2692 Tok::LBracket => brackets += 1,
2693 Tok::RBracket => {
2694 brackets -= 1;
2695 if brackets == 0 {
2696 break;
2697 }
2698 }
2699 Tok::VSemi | Tok::VRBrace => break,
2700 _ => {}
2701 }
2702 self.i += 1;
2703 }
2704 let raw = self.slice_text(start);
2705 self.eat(&Tok::RBracket);
2706 return Some(Expr::App {
2707 func: Box::new(e),
2708 args: vec![Expr::Error {
2709 raw,
2710 pos,
2711 span: self.node_span(start_i),
2712 }],
2713 pos,
2714 span: self.node_span(start_i),
2715 });
2716 }
2717 items.push(e);
2718 if !self.eat(&Tok::Comma) {
2719 break;
2720 }
2721 }
2722 self.eat(&Tok::RBracket);
2723 Some(Expr::List {
2724 items,
2725 pos,
2726 span: self.node_span(start_i),
2727 })
2728 }
2729}
2730
2731fn is_reserved_op(op: &str) -> bool {
2734 matches!(op, "=" | "<-" | "->" | "|" | ":" | "=>" | "@" | "\\" | "..")
2735}
2736
2737fn fixity(op: &str) -> (u8, bool) {
2740 match op {
2741 "$" | "$!" => (1, true),
2742 ">>=" | ">>" | "=<<" | "<&>" => (2, false),
2743 "||" => (3, true),
2744 "&&" => (4, true),
2745 "==" | "/=" | "<" | "<=" | ">" | ">=" => (5, false),
2746 "::" | "++" | "<>" => (6, true),
2747 "+" | "-" => (7, false),
2748 "*" | "/" => (8, false),
2749 "^" | "**" => (9, true),
2750 "." | "!!" => (10, true),
2751 _ => (9, false),
2752 }
2753}
2754
2755fn equations_extent(eqs: &[Equation]) -> Option<Span> {
2760 let mut it = eqs.iter();
2761 let first = it.next()?;
2762 let mut s = first.span;
2763 for e in it {
2764 s.start = s.start.min(e.span.start);
2765 s.end = s.end.max(e.span.end);
2766 }
2767 Some(s)
2768}
2769
2770fn merge_functions(decls: &mut Vec<Decl>) {
2771 let mut out: Vec<Decl> = Vec::with_capacity(decls.len());
2772 let mut function_index_by_name: HashMap<String, usize> = HashMap::new();
2773 for decl in decls.drain(..) {
2774 match decl {
2775 Decl::Function(f) => {
2776 if let Some(existing_index) = function_index_by_name.get(&f.name).copied() {
2777 let Decl::Function(g) = &mut out[existing_index] else {
2778 unreachable!("function index must point at a function declaration");
2779 };
2780 if g.ty.is_none() {
2781 g.ty = f.ty.clone();
2782 }
2783 if g.sig_span.is_none() {
2784 g.sig_span = f.sig_span;
2785 }
2786 if g.equations.is_empty() && !f.equations.is_empty() {
2789 g.pos = f.pos;
2790 }
2791 g.equations.extend(f.equations);
2792 g.span = equations_extent(&g.equations)
2799 .or(g.sig_span)
2800 .unwrap_or(g.span);
2801 } else {
2802 function_index_by_name.insert(f.name.clone(), out.len());
2803 out.push(Decl::Function(f));
2804 }
2805 }
2806 other => out.push(other),
2807 }
2808 }
2809 *decls = out;
2810}
2811
2812pub(crate) fn parse_type_from_tokens(tokens: &[Token]) -> Option<Type> {
2821 let real_tokens: Vec<&Token> = tokens.iter().filter(|t| !t.is_virtual()).collect();
2824 if real_tokens.is_empty() {
2825 return None;
2826 }
2827 let mut parser = TypeTokenParser {
2828 tokens: &real_tokens,
2829 cursor: 0,
2830 };
2831 let ty = parser.parse_type()?;
2832 if parser.cursor == real_tokens.len() {
2835 Some(ty)
2836 } else {
2837 None
2838 }
2839}
2840
2841struct TypeTokenParser<'a> {
2842 tokens: &'a [&'a Token],
2843 cursor: usize,
2844}
2845
2846enum TypeAtom {
2849 ParsedType(Type),
2850 DroppedLiteral(Span),
2851}
2852
2853impl<'a> TypeTokenParser<'a> {
2854 fn peek(&self) -> Option<&'a Token> {
2855 self.tokens.get(self.cursor).copied()
2856 }
2857
2858 fn eat_op(&mut self, op: &str) -> bool {
2859 if self.peek().is_some_and(|t| t.tok.is_op(op)) {
2860 self.cursor += 1;
2861 true
2862 } else {
2863 false
2864 }
2865 }
2866
2867 fn parse_type(&mut self) -> Option<Type> {
2870 let lhs = self.parse_application_type()?;
2871 if self.eat_op("=>") {
2872 let body = self.parse_type()?;
2874 let span = Span::new(lhs.span().start, body.span().end);
2875 return Some(Type::Constrained(Box::new(body), span));
2876 }
2877 if self.eat_op("->") {
2878 let rhs = self.parse_type()?;
2879 let span = Span::new(lhs.span().start, rhs.span().end);
2880 return Some(Type::Fun(Box::new(lhs), Box::new(rhs), span));
2881 }
2882 Some(lhs)
2883 }
2884
2885 fn parse_application_type(&mut self) -> Option<Type> {
2887 let head = match self.parse_atom()? {
2888 TypeAtom::ParsedType(t) => t,
2889 TypeAtom::DroppedLiteral(_) => return None,
2891 };
2892 let mut args = Vec::new();
2893 let start = head.span().start;
2894 let mut end = head.span().end;
2895 loop {
2896 if !self.is_at_type_atom_start() {
2899 break;
2900 }
2901 match self.parse_atom()? {
2902 TypeAtom::ParsedType(t) => {
2903 end = t.span().end;
2904 args.push(t);
2905 }
2906 TypeAtom::DroppedLiteral(span) => {
2907 end = span.end;
2910 }
2911 }
2912 }
2913 let span = Span::new(start, end);
2914 if args.is_empty() {
2915 Some(head.with_span(span))
2916 } else {
2917 Some(Type::App(Box::new(head), args, span))
2918 }
2919 }
2920
2921 fn is_at_type_atom_start(&self) -> bool {
2924 matches!(
2925 self.peek().map(|t| &t.tok),
2926 Some(
2927 Tok::UpperId { .. }
2928 | Tok::LowerId { .. }
2929 | Tok::IntLit(_)
2930 | Tok::DecimalLit(_)
2931 | Tok::LBracket
2932 | Tok::LParen
2933 )
2934 )
2935 }
2936
2937 fn parse_atom(&mut self) -> Option<TypeAtom> {
2938 let tok = self.peek()?;
2939 match &tok.tok {
2940 Tok::UpperId { qualifier, name } => {
2941 let con = Type::Con {
2942 qualifier: qualifier.clone(),
2943 name: name.clone(),
2944 span: Span::new(tok.start, tok.end),
2945 };
2946 self.cursor += 1;
2947 Some(TypeAtom::ParsedType(con))
2948 }
2949 Tok::LowerId { name, .. } => {
2950 let var = Type::Var(name.clone(), Span::new(tok.start, tok.end));
2953 self.cursor += 1;
2954 Some(TypeAtom::ParsedType(var))
2955 }
2956 Tok::IntLit(_) | Tok::DecimalLit(_) => {
2957 self.cursor += 1;
2959 Some(TypeAtom::DroppedLiteral(Span::new(tok.start, tok.end)))
2960 }
2961 Tok::LBracket => {
2962 let start = tok.start;
2963 self.cursor += 1;
2964 let inner = self.parse_type()?;
2965 self.eat_token(&Tok::RBracket).map(|end| {
2966 TypeAtom::ParsedType(Type::List(Box::new(inner), Span::new(start, end.end)))
2967 })
2968 }
2969 Tok::LParen => {
2970 let start = tok.start;
2971 self.cursor += 1;
2972 if let Some(end) = self.eat_token(&Tok::RParen) {
2973 return Some(TypeAtom::ParsedType(Type::Unit(Span::new(start, end.end))));
2975 }
2976 let first = self.parse_type()?;
2977 if self.peek().map(|t| &t.tok) == Some(&Tok::Comma) {
2978 let mut items = vec![first];
2979 while self.eat_token(&Tok::Comma).is_some() {
2980 items.push(self.parse_type()?);
2981 }
2982 self.eat_token(&Tok::RParen).map(|end| {
2983 TypeAtom::ParsedType(Type::Tuple(items, Span::new(start, end.end)))
2984 })
2985 } else {
2986 self.eat_token(&Tok::RParen).map(|end| {
2987 TypeAtom::ParsedType(first.with_span(Span::new(start, end.end)))
2989 })
2990 }
2991 }
2992 _ => None,
2993 }
2994 }
2995
2996 fn eat_token(&mut self, tok: &Tok) -> Option<&'a Token> {
2997 if self.peek().is_some_and(|t| t.tok == *tok) {
2998 let t = self.peek();
2999 self.cursor += 1;
3000 t
3001 } else {
3002 None
3003 }
3004 }
3005}
3006
3007fn render_token_slice(tokens: &[Token]) -> String {
3008 let mut s = String::new();
3009 let mut prev_no_space_after = true;
3010 for t in tokens {
3011 let (text, no_space_before, no_space_after): (String, bool, bool) = match &t.tok {
3012 Tok::LowerId { qualifier, name } | Tok::UpperId { qualifier, name } => (
3013 qualifier
3014 .as_ref()
3015 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
3016 false,
3017 false,
3018 ),
3019 Tok::Op(o) => (o.clone(), false, false),
3020 Tok::IntLit(n) | Tok::DecimalLit(n) => (n.clone(), false, false),
3021 Tok::StringLit(v) => (format!("{v:?}"), false, false),
3022 Tok::CharLit(v) => (format!("'{v}'"), false, false),
3023 Tok::LParen => ("(".to_string(), false, true),
3024 Tok::RParen => (")".to_string(), true, false),
3025 Tok::LBracket => ("[".to_string(), false, true),
3026 Tok::RBracket => ("]".to_string(), true, false),
3027 Tok::LBrace => ("{".to_string(), false, true),
3028 Tok::RBrace => ("}".to_string(), true, false),
3029 Tok::Comma => (",".to_string(), true, false),
3030 Tok::Semi | Tok::VSemi => (";".to_string(), true, false),
3031 Tok::Backtick => ("`".to_string(), false, false),
3032 Tok::VLBrace | Tok::VRBrace => continue,
3033 };
3034 if !s.is_empty() && !no_space_before && !prev_no_space_after {
3035 s.push(' ');
3036 }
3037 s.push_str(&text);
3038 prev_no_space_after = no_space_after;
3039 }
3040 s
3041}
3042
3043#[cfg(test)]
3044mod type_tests {
3045 use super::*;
3046 use crate::lexer::lex;
3047
3048 fn ty(s: &str) -> Option<Type> {
3052 let (toks, errs) = lex(s);
3053 assert!(errs.is_empty(), "lex errors for {s:?}: {errs:?}");
3054 parse_type_from_tokens(&toks)
3055 }
3056
3057 fn con(name: &str) -> Type {
3058 Type::Con {
3059 qualifier: None,
3060 name: name.to_string(),
3061 span: Span::default(),
3062 }
3063 }
3064
3065 fn qualified_con(qualifier: &str, name: &str) -> Type {
3066 Type::Con {
3067 qualifier: Some(qualifier.to_string()),
3068 name: name.to_string(),
3069 span: Span::default(),
3070 }
3071 }
3072
3073 fn app(head: Type, args: Vec<Type>) -> Type {
3074 Type::App(Box::new(head), args, Span::default())
3075 }
3076
3077 fn list(inner: Type) -> Type {
3078 Type::List(Box::new(inner), Span::default())
3079 }
3080
3081 fn tuple(items: Vec<Type>) -> Type {
3082 Type::Tuple(items, Span::default())
3083 }
3084
3085 fn fun(param: Type, result: Type) -> Type {
3086 Type::Fun(Box::new(param), Box::new(result), Span::default())
3087 }
3088
3089 fn var(name: &str) -> Type {
3090 Type::Var(name.to_string(), Span::default())
3091 }
3092
3093 fn unit() -> Type {
3094 Type::Unit(Span::default())
3095 }
3096
3097 fn constrained(body: Type) -> Type {
3098 Type::Constrained(Box::new(body), Span::default())
3099 }
3100
3101 #[test]
3102 fn atoms() {
3103 assert_eq!(ty("Party"), Some(con("Party")));
3104 assert_eq!(ty("Decimal"), Some(con("Decimal")));
3105 assert_eq!(ty("a"), Some(var("a")));
3106 assert_eq!(ty("()"), Some(unit()));
3107 }
3108
3109 #[test]
3110 fn application_vs_constructor() {
3111 assert_eq!(
3114 ty("ContractId Foo"),
3115 Some(app(con("ContractId"), vec![con("Foo")]))
3116 );
3117 assert_eq!(
3118 ty("Optional (ContractId Foo)"),
3119 Some(app(
3120 con("Optional"),
3121 vec![app(con("ContractId"), vec![con("Foo")])]
3122 ))
3123 );
3124 assert_eq!(
3125 ty("Map Text Int"),
3126 Some(app(con("Map"), vec![con("Text"), con("Int")]))
3127 );
3128 }
3129
3130 #[test]
3131 fn qualified_constructor_keeps_qualifier() {
3132 assert_eq!(
3133 ty("DA.Map.Map Text Int"),
3134 Some(app(
3135 qualified_con("DA.Map", "Map"),
3136 vec![con("Text"), con("Int")]
3137 ))
3138 );
3139 }
3140
3141 #[test]
3142 fn list_and_tuple() {
3143 assert_eq!(ty("[Text]"), Some(list(con("Text"))));
3144 assert_eq!(
3145 ty("(Int, Text)"),
3146 Some(tuple(vec![con("Int"), con("Text")]))
3147 );
3148 assert_eq!(
3150 ty("(a, b, c)"),
3151 Some(tuple(vec![var("a"), var("b"), var("c")]))
3152 );
3153 assert_eq!(ty("(Text)"), Some(con("Text")));
3155 }
3156
3157 #[test]
3158 fn function_types_are_arrows_not_names() {
3159 assert_eq!(ty("Int -> Int"), Some(fun(con("Int"), con("Int"))));
3162 assert_eq!(
3164 ty("Int -> Text -> Bool"),
3165 Some(fun(con("Int"), fun(con("Text"), con("Bool"))))
3166 );
3167 assert_eq!(
3168 ty("Party -> Script ()"),
3169 Some(fun(con("Party"), app(con("Script"), vec![unit()])))
3170 );
3171 }
3172
3173 #[test]
3174 fn script_application() {
3175 assert_eq!(ty("Script ()"), Some(app(con("Script"), vec![unit()])));
3178 }
3179
3180 #[test]
3181 fn numeric_nat_literal_is_dropped() {
3182 assert_eq!(ty("Numeric 10"), Some(con("Numeric")));
3185 assert_eq!(ty("Numeric n"), Some(app(con("Numeric"), vec![var("n")])));
3186 }
3187
3188 #[test]
3189 fn constraint_context_is_dropped_body_kept() {
3190 assert_eq!(
3193 ty("NumericScale n => Numeric 37 -> Numeric n"),
3194 Some(constrained(fun(
3195 con("Numeric"),
3196 app(con("Numeric"), vec![var("n")])
3197 )))
3198 );
3199 assert_eq!(ty("(Eq a, Show a) => a"), Some(constrained(var("a"))));
3201 }
3202
3203 #[test]
3204 fn unparseable_is_none() {
3205 assert_eq!(ty("Int ->"), None);
3208 assert_eq!(ty("-> Int"), None);
3209 }
3210
3211 #[test]
3212 fn ty_is_populated_through_real_parse() {
3213 let src = r#"module M where
3216template T
3217 with
3218 owner : Party
3219 held : ContractId Asset
3220 where
3221 signatory owner
3222 choice Go : Optional (ContractId Asset)
3223 controller owner
3224 do
3225 pure None
3226"#;
3227 let (m, _) = parse_module(src);
3228 let t = match &m.decls[0] {
3229 Decl::Template(t) => t,
3230 other => panic!("expected template, got {other:?}"),
3231 };
3232 assert_eq!(t.fields[0].ty, Some(con("Party")));
3233 assert_eq!(
3234 t.fields[1].ty,
3235 Some(app(con("ContractId"), vec![con("Asset")]))
3236 );
3237 let choice = match &t
3238 .body
3239 .iter()
3240 .find(|d| matches!(d, TemplateBodyDecl::Choice(_)))
3241 {
3242 Some(TemplateBodyDecl::Choice(c)) => (*c).clone(),
3243 _ => panic!("expected choice"),
3244 };
3245 assert_eq!(
3246 choice.return_ty,
3247 Some(app(
3248 con("Optional"),
3249 vec![app(con("ContractId"), vec![con("Asset")])]
3250 ))
3251 );
3252 }
3253
3254 #[test]
3255 fn ty_is_populated_on_key_and_interface_method() {
3256 let src = r#"module M where
3259template T
3260 with
3261 owner : Party
3262 where
3263 signatory owner
3264 key owner : Party
3265 maintainer owner
3266
3267interface I where
3268 getAmount : Numeric 10
3269"#;
3270 let (m, _) = parse_module(src);
3271 let t = match &m.decls[0] {
3272 Decl::Template(t) => t,
3273 other => panic!("expected template, got {other:?}"),
3274 };
3275 let key_ty = t.body.iter().find_map(|d| match d {
3276 TemplateBodyDecl::Key { ty, .. } => Some(ty.clone()),
3277 _ => None,
3278 });
3279 assert_eq!(key_ty, Some(Some(con("Party"))));
3280
3281 let iface = match &m.decls[1] {
3282 Decl::Interface(i) => i,
3283 other => panic!("expected interface, got {other:?}"),
3284 };
3285 assert_eq!(iface.methods[0].ty, Some(con("Numeric")));
3287 }
3288
3289 #[test]
3290 fn malformed_guarded_equation_reports_missing_equals_and_continues() {
3291 let src = "module M where\nf x | x > 0\ng = 1\n";
3292 let (module, diagnostics) = parse_module(src);
3293
3294 assert!(
3295 diagnostics.iter().any(
3296 |diagnostic| diagnostic.message == "expected '=' after guard"
3297 && diagnostic.category == DiagnosticCategory::Malformed
3298 ),
3299 "expected guard diagnostic, got {diagnostics:?}"
3300 );
3301 assert!(
3302 module
3303 .decls
3304 .iter()
3305 .any(|decl| matches!(decl, Decl::Function(function) if function.name == "g")),
3306 "parser should recover to the following declaration: {:?}",
3307 module.decls
3308 );
3309 }
3310
3311 #[test]
3312 fn malformed_brackets_do_not_underflow_recovery_scans() {
3313 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";
3314 let (module, _diagnostics) = parse_module(src);
3315
3316 assert_eq!(module.name, "M");
3317 assert!(
3318 module
3319 .decls
3320 .iter()
3321 .any(|decl| matches!(decl, Decl::Function(function) if function.name == "g")),
3322 "parser should recover to the following declaration: {:?}",
3323 module.decls
3324 );
3325 }
3326}