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