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 depth -= 1;
351 if depth == 0 {
352 self.i += 1;
353 return;
354 }
355 }
356 _ => {}
357 }
358 self.i += 1;
359 }
360 }
361
362 fn try_infix_operator_decl(&mut self) -> bool {
366 let snap = self.i;
367 let saved_diags = self.diags.len();
368 if self.pattern().is_some() && matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o))
369 {
370 self.skip_to_item_end();
371 return true;
372 }
373 self.i = snap;
374 self.diags.truncate(saved_diags);
375 false
376 }
377
378 fn declaration(&mut self, imports: &mut Vec<ImportDecl>, decls: &mut Vec<Decl>) {
379 let pos = self.pos();
380 let start = self.i;
381 if matches!(
382 self.peek(),
383 Some(Tok::UpperId { .. } | Tok::LBracket | Tok::LParen)
384 ) && self.try_infix_operator_decl()
385 {
386 decls.push(Decl::Unknown {
387 raw: self.slice_text(start),
388 pos,
389 span: self.node_span(start),
390 });
391 return;
392 }
393 match self.peek() {
394 Some(t) if t.is_keyword("import") => {
395 let imp = self.import_decl();
396 self.skip_to_item_end();
400 if let Some(mut imp) = imp {
401 imp.span = self.node_span(start);
402 imports.push(imp);
403 }
404 }
405 Some(t) if t.is_keyword("template") => {
406 match self.template_decl() {
409 Some(t) => decls.push(Decl::Template(t)),
410 None => {
411 self.skip_to_item_end();
412 decls.push(Decl::Unknown {
413 raw: self.slice_text(start),
414 span: self.node_span(start),
415 pos,
416 });
417 }
418 }
419 }
420 Some(t) if t.is_keyword("interface") => match self.interface_decl() {
421 Some(i) => decls.push(Decl::Interface(i)),
422 None => {
423 self.skip_to_item_end();
424 decls.push(Decl::Unknown {
425 raw: self.slice_text(start),
426 span: self.node_span(start),
427 pos,
428 });
429 }
430 },
431 Some(t)
432 if matches!(
433 t.keyword(),
434 Some("infix" | "infixl" | "infixr" | "default" | "pattern")
437 ) =>
438 {
439 self.skip_to_item_end();
440 decls.push(Decl::Unknown {
441 raw: self.slice_text(start),
442 pos,
443 span: self.node_span(start),
444 });
445 }
446 Some(t)
447 if matches!(
448 t.keyword(),
449 Some(
450 "data"
451 | "type"
452 | "newtype"
453 | "class"
454 | "instance"
455 | "exception"
456 | "deriving"
457 )
458 ) =>
459 {
460 let keyword = t.keyword().unwrap().to_string();
461 self.bump();
462 let name = match self.peek() {
463 Some(Tok::UpperId { qualifier, name }) => {
464 let n = qualifier
465 .as_ref()
466 .map_or_else(|| name.clone(), |q| format!("{q}.{name}"));
467 self.bump();
468 n
469 }
470 _ => String::new(),
471 };
472 self.skip_to_item_end();
473 decls.push(Decl::TypeDef {
474 keyword,
475 name,
476 pos,
477 span: self.node_span(start),
478 });
479 }
480 Some(Tok::LowerId { .. }) => match self.function_item() {
481 Some(d) => decls.push(d),
482 None => {
483 self.skip_to_item_end();
484 decls.push(Decl::Unknown {
485 raw: self.slice_text(start),
486 span: self.node_span(start),
487 pos,
488 });
489 }
490 },
491 Some(Tok::LParen)
493 if matches!(self.peek_at(1), Some(Tok::Op(_)))
494 && self.peek_at(2) == Some(&Tok::RParen) =>
495 {
496 self.skip_to_item_end();
497 decls.push(Decl::Unknown {
498 raw: self.slice_text(start),
499 span: self.node_span(start),
500 pos,
501 });
502 }
503 Some(Tok::LParen | Tok::LBracket) => {
505 if self.binding().is_none() {
506 self.diag_cat(
507 DiagnosticCategory::SkippedDecl,
508 "unparseable top-level pattern binding",
509 );
510 }
511 self.skip_to_item_end();
512 decls.push(Decl::Unknown {
513 raw: self.slice_text(start),
514 span: self.node_span(start),
515 pos,
516 });
517 }
518 _ => {
519 self.diag_cat(
520 DiagnosticCategory::SkippedDecl,
521 format!("unrecognized declaration: {:?}", self.peek()),
522 );
523 self.skip_to_item_end();
524 decls.push(Decl::Unknown {
525 raw: self.slice_text(start),
526 span: self.node_span(start),
527 pos,
528 });
529 }
530 }
531 }
532
533 fn import_decl(&mut self) -> Option<ImportDecl> {
536 let pos = self.pos();
537 let start_i = self.i;
538 self.bump(); let mut qualified = self.eat_keyword("qualified");
540 if matches!(self.peek(), Some(Tok::StringLit(_))) {
542 self.bump();
543 }
544 let module_name = match self.peek().cloned() {
545 Some(Tok::UpperId { qualifier, name }) => {
546 self.bump();
547 match qualifier {
548 Some(q) => format!("{q}.{name}"),
549 None => name,
550 }
551 }
552 _ => {
553 self.diag("expected module name after 'import'");
554 return None;
555 }
556 };
557 if self.eat_keyword("qualified") {
559 qualified = true;
560 }
561 let mut alias = None;
562 if self.eat_keyword("as") {
563 if let Some(Tok::UpperId { qualifier, name }) = self.peek().cloned() {
564 self.bump();
565 alias = Some(match qualifier {
566 Some(q) => format!("{q}.{name}"),
567 None => name,
568 });
569 }
570 }
571 Some(ImportDecl {
573 module_name,
574 qualified,
575 alias,
576 pos,
577 span: self.node_span(start_i),
578 })
579 }
580
581 fn upper_name(&mut self) -> Option<String> {
584 match self.peek().cloned() {
585 Some(Tok::UpperId { qualifier, name }) => {
586 self.bump();
587 Some(match qualifier {
588 Some(q) => format!("{q}.{name}"),
589 None => name,
590 })
591 }
592 _ => None,
593 }
594 }
595
596 fn template_decl(&mut self) -> Option<TemplateDecl> {
597 let pos = self.pos();
598 let start_i = self.i;
599 self.bump(); if self.at_keyword("instance") {
601 return None; }
603 let name = self.upper_name()?;
604
605 let mut fields = Vec::new();
606 if self.eat_keyword("with") {
607 (fields, _) = self.field_block();
608 }
609 let body = if self.eat_keyword("where") {
610 self.template_body()
611 } else {
612 Vec::new()
613 };
614 Some(TemplateDecl {
615 name,
616 fields,
617 body,
618 pos,
619 span: self.node_span(start_i),
620 })
621 }
622
623 fn field_block(&mut self) -> (Vec<FieldDecl>, bool) {
629 let mut fields = Vec::new();
630 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
631 return (fields, false);
632 }
633 loop {
634 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
635 match self.peek() {
636 None => break,
637 Some(Tok::VRBrace | Tok::RBrace) => {
638 self.bump();
639 break;
640 }
641 Some(Tok::RParen | Tok::RBracket) => {
646 self.bump();
647 continue;
648 }
649 _ => {}
650 }
651 {
656 let mut j = self.i;
657 while let Some(Tok::LowerId {
658 qualifier: None, ..
659 }) = self.toks.get(j).map(|t| &t.tok)
660 {
661 j += 1;
662 match self.toks.get(j).map(|t| &t.tok) {
663 Some(Tok::Comma) => j += 1,
664 _ => break,
665 }
666 }
667 let is_field = j > self.i
668 && self
669 .toks
670 .get(j)
671 .map(|t| &t.tok)
672 .is_some_and(|t| t.is_op(":"));
673 if !is_field {
674 return (fields, true);
675 }
676 }
677 let before = self.i;
678 let mut names: Vec<(String, Pos, Span)> = Vec::new();
680 while let Some(Tok::LowerId {
681 qualifier: None,
682 name,
683 }) = self.peek().cloned()
684 {
685 let p = self.pos();
686 let nspan = Span::new(self.toks[self.i].start, self.toks[self.i].end);
687 self.bump();
688 names.push((name, p, nspan));
689 if !self.eat(&Tok::Comma) {
690 break;
691 }
692 }
693 if names.is_empty() || !self.eat_op(":") {
694 self.diag("expected 'name : Type' field");
695 self.skip_to_item_end();
696 let _ = before;
697 continue;
698 }
699 let ty_start = self.i;
700 self.skip_to_item_end();
701 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
702 let type_end = self.end_byte();
707 let last = names.len() - 1;
708 for (idx, (name, p, nspan)) in names.into_iter().enumerate() {
709 let span = if idx == last {
710 Span::new(nspan.start, type_end.max(nspan.end))
711 } else {
712 nspan
713 };
714 fields.push(FieldDecl {
715 name,
716 ty: ty.clone(),
717 pos: p,
718 span,
719 });
720 }
721 }
722 (fields, false)
723 }
724
725 fn template_body(&mut self) -> Vec<TemplateBodyDecl> {
728 let mut body = Vec::new();
729 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
730 return body;
731 }
732 loop {
733 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
734 match self.peek() {
735 None => break,
736 Some(Tok::VRBrace | Tok::RBrace) => {
737 self.bump();
738 break;
739 }
740 Some(Tok::RParen | Tok::RBracket) => {
745 self.bump();
746 continue;
747 }
748 _ => {}
749 }
750 let pos = self.pos();
751 let start = self.i;
752 let decl = self.template_body_item(pos, start);
753 body.push(decl);
754 }
755 body
756 }
757
758 fn template_body_item(&mut self, pos: Pos, start: usize) -> TemplateBodyDecl {
759 match self.peek().and_then(|t| t.keyword()) {
760 Some("signatory") => {
761 self.bump();
762 let parties = self.expr_comma_list();
763 self.skip_to_item_end();
764 TemplateBodyDecl::Signatory {
765 parties,
766 pos,
767 span: self.node_span(start),
768 }
769 }
770 Some("observer") => {
771 self.bump();
772 let parties = self.expr_comma_list();
773 self.skip_to_item_end();
774 TemplateBodyDecl::Observer {
775 parties,
776 pos,
777 span: self.node_span(start),
778 }
779 }
780 Some("ensure") => {
781 self.bump();
782 let expr = self.expr();
783 self.skip_to_item_end();
784 TemplateBodyDecl::Ensure {
785 expr,
786 pos,
787 span: self.node_span(start),
788 }
789 }
790 Some("key") => {
791 self.bump();
792 let expr_start = self.i;
793 let expr = self.expr();
794 let ty = if self.eat_op(":") {
795 let ty_start = self.i;
796 self.skip_to_item_end();
797 parse_type_from_tokens(&self.toks[ty_start..self.i])
798 } else {
799 let mut depth = 0i32;
802 let mut colon = None;
803 for j in expr_start..self.i {
804 match &self.toks[j].tok {
805 Tok::LParen | Tok::LBracket => depth += 1,
806 Tok::RParen | Tok::RBracket => depth -= 1,
807 Tok::Op(o) if o == ":" && depth == 0 => colon = Some(j),
808 _ => {}
809 }
810 }
811 let ty = colon.and_then(|j| parse_type_from_tokens(&self.toks[j + 1..self.i]));
812 self.skip_to_item_end();
813 ty
814 };
815 TemplateBodyDecl::Key {
816 expr,
817 ty,
818 pos,
819 span: self.node_span(start),
820 }
821 }
822 Some("maintainer") => {
823 self.bump();
824 let expr = self.expr();
825 self.skip_to_item_end();
826 TemplateBodyDecl::Maintainer {
827 expr,
828 pos,
829 span: self.node_span(start),
830 }
831 }
832 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
833 self.choice_decl().map_or_else(
834 || {
835 self.skip_to_item_end();
836 TemplateBodyDecl::Other {
837 raw: self.slice_text(start),
838 span: self.node_span(start),
839 pos,
840 }
841 },
842 TemplateBodyDecl::Choice,
843 )
844 }
845 Some("interface") => self.interface_instance_decl().map_or_else(
846 || {
847 self.skip_to_item_end();
848 TemplateBodyDecl::Other {
849 raw: self.slice_text(start),
850 span: self.node_span(start),
851 pos,
852 }
853 },
854 TemplateBodyDecl::InterfaceInstance,
855 ),
856 Some("controller") => {
857 self.diag_cat(
861 DiagnosticCategory::UnsupportedSyntax,
862 "legacy 'controller ... can' syntax is not supported; \
863 choices inside this block are not analyzed",
864 );
865 self.skip_to_item_end();
866 TemplateBodyDecl::Other {
867 raw: self.slice_text(start),
868 span: self.node_span(start),
869 pos,
870 }
871 }
872 _ => {
873 self.skip_to_item_end();
874 TemplateBodyDecl::Other {
875 raw: self.slice_text(start),
876 span: self.node_span(start),
877 pos,
878 }
879 }
880 }
881 }
882
883 fn choice_decl(&mut self) -> Option<ChoiceDecl> {
884 let pos = self.pos();
885 let start_i = self.i;
886 let consuming = match self.peek().and_then(|t| t.keyword()) {
887 Some("nonconsuming") => {
888 self.bump();
889 Consuming::NonConsuming
890 }
891 Some("preconsuming") => {
892 self.bump();
893 Consuming::PreConsuming
894 }
895 Some("postconsuming") => {
896 self.bump();
897 Consuming::PostConsuming
898 }
899 _ => Consuming::Consuming,
900 };
901 if !self.eat_keyword("choice") {
902 return None;
903 }
904 let name = self.upper_name()?;
905 let return_ty = if self.eat_op(":") {
906 let ty_start = self.i;
907 self.skip_type_tokens();
908 parse_type_from_tokens(&self.toks[ty_start..self.i])
909 } else {
910 None
911 };
912 let mut params = Vec::new();
913 let mut dangling = false;
914 if self.eat_keyword("with") {
915 (params, dangling) = self.field_block();
916 }
917 let mut observers = Vec::new();
918 let mut controllers = Vec::new();
919 loop {
920 if dangling {
924 while self.eat(&Tok::VSemi) {}
925 }
926 if self.eat_keyword("observer") {
927 observers = self.expr_comma_list_no_do();
928 } else if self.eat_keyword("controller") {
929 controllers = self.expr_comma_list_no_do();
930 } else {
931 break;
932 }
933 }
934 if dangling {
935 while self.eat(&Tok::VSemi) {}
936 }
937 let body = if self
938 .peek()
939 .is_some_and(|t| !matches!(t, Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace))
940 {
941 Some(self.expr())
942 } else {
943 None
944 };
945 self.skip_to_item_end();
946 if dangling {
947 self.eat(&Tok::VRBrace);
950 self.skip_to_item_end();
951 }
952 Some(ChoiceDecl {
953 name,
954 consuming,
955 return_ty,
956 params,
957 controllers,
958 observers,
959 body,
960 pos,
961 span: self.node_span(start_i),
962 })
963 }
964
965 fn skip_type_tokens(&mut self) {
968 let mut brackets = 0usize;
969 while let Some(t) = self.peek() {
970 match t {
971 Tok::VSemi | Tok::VRBrace | Tok::VLBrace | Tok::Semi => return,
972 Tok::LParen | Tok::LBracket => brackets += 1,
973 Tok::RParen | Tok::RBracket => {
974 if brackets == 0 {
975 return;
976 }
977 brackets -= 1;
978 }
979 _ if brackets == 0
980 && matches!(
981 t.keyword(),
982 Some("with" | "controller" | "observer" | "do" | "where")
983 ) =>
984 {
985 return
986 }
987 _ => {}
988 }
989 self.i += 1;
990 }
991 }
992
993 fn interface_decl(&mut self) -> Option<InterfaceDecl> {
996 let pos = self.pos();
997 let start_i = self.i;
998 self.bump(); if self.at_keyword("instance") {
1000 return None;
1002 }
1003 let name = self.upper_name()?;
1004 let mut requires = Vec::new();
1005 if self.eat_keyword("requires") {
1006 while let Some(r) = self.upper_name() {
1007 requires.push(r);
1008 if !self.eat(&Tok::Comma) {
1009 break;
1010 }
1011 }
1012 }
1013 if !self.eat_keyword("where") {
1014 return None;
1015 }
1016 let mut viewtype = None;
1017 let mut methods = Vec::new();
1018 let mut choices = Vec::new();
1019 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1020 return Some(InterfaceDecl {
1021 name,
1022 requires,
1023 viewtype,
1024 methods,
1025 choices,
1026 pos,
1027 span: self.node_span(start_i),
1028 });
1029 }
1030 loop {
1031 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1032 match self.peek() {
1033 None => break,
1034 Some(Tok::VRBrace | Tok::RBrace) => {
1035 self.bump();
1036 break;
1037 }
1038 Some(Tok::RParen | Tok::RBracket) => {
1043 self.bump();
1044 continue;
1045 }
1046 _ => {}
1047 }
1048 match self.peek().and_then(|t| t.keyword()) {
1049 Some("viewtype") => {
1050 self.bump();
1051 viewtype = self.upper_name();
1052 self.skip_to_item_end();
1053 }
1054 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1055 if let Some(c) = self.choice_decl() {
1056 choices.push(c);
1057 } else {
1058 self.skip_to_item_end();
1059 }
1060 }
1061 _ => {
1062 let mpos = self.pos();
1065 if let Some(Tok::LowerId {
1066 qualifier: None,
1067 name: mname,
1068 }) = self.peek().cloned()
1069 {
1070 if self.peek_at(1).is_some_and(|t| t.is_op(":")) {
1071 let mstart = self.toks[self.i].start;
1072 self.bump();
1073 self.bump();
1074 let ty_start = self.i;
1075 self.skip_to_item_end();
1076 methods.push(FieldDecl {
1078 name: mname,
1079 ty: parse_type_from_tokens(&self.toks[ty_start..self.i]),
1080 pos: mpos,
1081 span: Span::new(mstart, self.end_byte().max(mstart)),
1082 });
1083 continue;
1084 }
1085 }
1086 self.skip_to_item_end();
1087 }
1088 }
1089 }
1090 Some(InterfaceDecl {
1091 name,
1092 requires,
1093 viewtype,
1094 methods,
1095 choices,
1096 pos,
1097 span: self.node_span(start_i),
1098 })
1099 }
1100
1101 fn interface_instance_decl(&mut self) -> Option<InterfaceInstanceDecl> {
1103 let pos = self.pos();
1104 let start_i = self.i;
1105 self.bump(); if !self.eat_keyword("instance") {
1107 return None;
1108 }
1109 let interface_name = self.upper_name()?;
1110 let for_template = if self.eat_keyword("for") {
1111 self.upper_name().unwrap_or_default()
1112 } else {
1113 String::new()
1114 };
1115 let mut methods = Vec::new();
1116 if self.eat_keyword("where") && (self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1117 loop {
1118 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1119 match self.peek() {
1120 None => break,
1121 Some(Tok::VRBrace | Tok::RBrace) => {
1122 self.bump();
1123 break;
1124 }
1125 Some(Tok::RParen | Tok::RBracket) => {
1127 self.bump();
1128 continue;
1129 }
1130 _ => {}
1131 }
1132 if let Some(b) = self.binding() {
1133 methods.push(b);
1134 } else {
1135 self.skip_to_item_end();
1136 }
1137 }
1138 }
1139 Some(InterfaceInstanceDecl {
1140 interface_name,
1141 for_template,
1142 methods,
1143 pos,
1144 span: self.node_span(start_i),
1145 })
1146 }
1147
1148 fn function_item(&mut self) -> Option<Decl> {
1154 let pos = self.pos();
1155 let start_i = self.i;
1156 let name = match self.peek().cloned() {
1157 Some(Tok::LowerId {
1158 qualifier: None,
1159 name,
1160 }) => name,
1161 _ => return None,
1162 };
1163
1164 let mut j = self.i + 1;
1166 let mut is_sig = false;
1167 loop {
1168 match self.toks.get(j).map(|t| &t.tok) {
1169 Some(Tok::Comma) => {
1170 j += 1;
1171 if matches!(
1172 self.toks.get(j).map(|t| &t.tok),
1173 Some(Tok::LowerId {
1174 qualifier: None,
1175 ..
1176 })
1177 ) {
1178 j += 1;
1179 continue;
1180 }
1181 break;
1182 }
1183 Some(Tok::Op(o)) if o == ":" => {
1184 is_sig = true;
1185 break;
1186 }
1187 _ => break,
1188 }
1189 }
1190 if is_sig {
1191 self.bump(); while self.eat(&Tok::Comma) {
1193 self.bump(); }
1195 self.eat_op(":");
1196 let ty_start = self.i;
1197 self.skip_to_item_end();
1198 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
1199 return Some(Decl::Function(FunctionDecl {
1200 name,
1201 ty,
1202 equations: Vec::new(),
1203 pos,
1204 sig_span: Some(self.node_span(start_i)),
1205 span: self.node_span(start_i),
1206 }));
1207 }
1208
1209 self.bump(); let mut params = Vec::new();
1212 while !self.at_op("=") && !self.at_op("|") {
1213 if self.at_op(":") {
1216 self.bump();
1217 let mut brackets = 0usize;
1218 while let Some(t) = self.peek() {
1219 match t {
1220 Tok::Op(o) if o == "=" && brackets == 0 => break,
1221 Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace => break,
1222 Tok::LParen | Tok::LBracket => brackets += 1,
1223 Tok::RParen | Tok::RBracket => brackets = brackets.saturating_sub(1),
1224 _ => {}
1225 }
1226 self.i += 1;
1227 }
1228 continue;
1229 }
1230 if matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o)) {
1233 self.skip_to_item_end();
1234 return None;
1235 }
1236 match self.peek() {
1237 None | Some(Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace) => {
1238 self.diag(format!("could not parse equation for '{name}'"));
1239 return None;
1240 }
1241 _ => {}
1242 }
1243 match self.pattern_atom() {
1244 Some(p) => params.push(p),
1245 None => {
1246 self.diag(format!("bad parameter pattern in '{name}'"));
1247 return None;
1248 }
1249 }
1250 }
1251 let (body, guards) = self.equation_rhs()?;
1252 let where_bindings = if self.eat_keyword("where") {
1253 self.binding_block()
1254 } else {
1255 Vec::new()
1256 };
1257 self.skip_to_item_end();
1258 Some(Decl::Function(FunctionDecl {
1259 name,
1260 ty: None,
1261 equations: vec![Equation {
1262 params,
1263 body,
1264 guards,
1265 where_bindings,
1266 pos,
1267 span: self.node_span(start_i),
1268 }],
1269 pos,
1270 sig_span: None,
1271 span: self.node_span(start_i),
1272 }))
1273 }
1274
1275 fn equation_rhs(&mut self) -> Option<(Expr, Vec<(Expr, Expr)>)> {
1277 if self.eat_op("=") {
1278 return Some((self.expr(), Vec::new()));
1279 }
1280 let mut guards = Vec::new();
1281 while self.eat_op("|") {
1282 let g = loop {
1285 let g = self.expr();
1286 if self.eat_op("<-") {
1287 let _ = self.expr(); }
1289 if !self.eat(&Tok::Comma) {
1290 break g;
1291 }
1292 };
1293 if !self.eat_op("=") {
1294 self.diag("expected '=' after guard");
1295 return None;
1296 }
1297 let e = self.expr();
1298 guards.push((g, e));
1299 }
1300 let first = guards.first()?.1.clone();
1301 Some((first, guards))
1302 }
1303
1304 fn binding_block(&mut self) -> Vec<Binding> {
1306 let mut bindings = Vec::new();
1307 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1308 return bindings;
1309 }
1310 loop {
1311 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1312 match self.peek() {
1313 None => break,
1314 Some(Tok::VRBrace | Tok::RBrace) => {
1315 self.bump();
1316 break;
1317 }
1318 Some(Tok::RParen | Tok::RBracket) => {
1323 self.bump();
1324 continue;
1325 }
1326 _ => {}
1327 }
1328 match self.binding() {
1329 Some(b) => bindings.push(b),
1330 None => self.skip_to_item_end(),
1331 }
1332 }
1333 bindings
1334 }
1335
1336 fn binding(&mut self) -> Option<Binding> {
1339 let pos = self.pos();
1340 let start_i = self.i;
1341 if self.at(&Tok::LParen)
1344 && matches!(self.peek_at(1), Some(Tok::Op(_)))
1345 && self.peek_at(2) == Some(&Tok::RParen)
1346 {
1347 self.skip_to_item_end();
1348 return None;
1349 }
1350 let pat = self.pattern_atom()?;
1351 let mut params = Vec::new();
1352 loop {
1353 if self.at_op("=") {
1354 self.bump();
1355 let expr = self.expr();
1356 if self.eat_keyword("where") {
1358 let _ = self.binding_block();
1359 }
1360 return Some(Binding {
1361 pat,
1362 params,
1363 expr,
1364 pos,
1365 span: self.node_span(start_i),
1366 });
1367 }
1368 if self.at_op("|") {
1369 let (body, _) = self.equation_rhs()?;
1370 if self.eat_keyword("where") {
1371 let _ = self.binding_block();
1372 }
1373 return Some(Binding {
1374 pat,
1375 params,
1376 expr: body,
1377 pos,
1378 span: self.node_span(start_i),
1379 });
1380 }
1381 if self.at_op(":") {
1382 if params.is_empty() {
1383 self.skip_to_item_end();
1385 return None;
1386 }
1387 self.bump();
1390 let mut brackets = 0usize;
1391 while let Some(t) = self.peek() {
1392 match t {
1393 Tok::Op(o) if o == "=" && brackets == 0 => break,
1394 Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace => break,
1395 Tok::LParen | Tok::LBracket => brackets += 1,
1396 Tok::RParen | Tok::RBracket => brackets = brackets.saturating_sub(1),
1397 _ => {}
1398 }
1399 self.i += 1;
1400 }
1401 continue;
1402 }
1403 if matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o)) {
1406 self.skip_to_item_end();
1407 return None;
1408 }
1409 match self.peek() {
1410 None | Some(Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace) => return None,
1411 _ => {}
1412 }
1413 params.push(self.pattern_atom()?);
1414 }
1415 }
1416
1417 fn pattern_atom(&mut self) -> Option<Pat> {
1420 if self.depth >= MAX_DEPTH {
1421 return None;
1422 }
1423 self.depth += 1;
1424 let result = self.pattern_atom_inner();
1425 self.depth -= 1;
1426 result
1427 }
1428
1429 fn pattern_atom_inner(&mut self) -> Option<Pat> {
1430 let pos = self.pos();
1431 let start_i = self.i;
1432 if self.at_op("~") || self.at_op("!") {
1434 self.bump();
1435 return self.pattern_atom();
1436 }
1437 match self.peek().cloned() {
1438 Some(Tok::LowerId {
1439 qualifier: None,
1440 name,
1441 }) => {
1442 self.bump();
1443 if name == "_" {
1444 return Some(Pat::Wild {
1445 pos,
1446 span: self.node_span(start_i),
1447 });
1448 }
1449 if self.at_op("@") {
1450 self.bump();
1451 let inner = self.pattern_atom()?;
1452 return Some(Pat::As {
1453 name,
1454 pat: Box::new(inner),
1455 pos,
1456 span: self.node_span(start_i),
1457 });
1458 }
1459 Some(Pat::Var {
1460 name,
1461 pos,
1462 span: self.node_span(start_i),
1463 })
1464 }
1465 Some(Tok::Op(o)) if o == "_" => {
1466 self.bump();
1467 Some(Pat::Wild {
1468 pos,
1469 span: self.node_span(start_i),
1470 })
1471 }
1472 Some(Tok::UpperId { qualifier, name }) => {
1473 self.bump();
1474 if self.at(&Tok::LBrace) {
1477 self.skip_balanced_braces();
1478 } else if self.eat_keyword("with") {
1479 let _ = self.record_fields();
1480 }
1481 Some(Pat::Con {
1482 qualifier,
1483 name,
1484 args: Vec::new(),
1485 pos,
1486 span: self.node_span(start_i),
1487 })
1488 }
1489 Some(Tok::IntLit(text)) => {
1490 self.bump();
1491 Some(Pat::Lit {
1492 kind: LitKind::Int,
1493 text,
1494 pos,
1495 span: self.node_span(start_i),
1496 })
1497 }
1498 Some(Tok::DecimalLit(text)) => {
1499 self.bump();
1500 Some(Pat::Lit {
1501 kind: LitKind::Decimal,
1502 text,
1503 pos,
1504 span: self.node_span(start_i),
1505 })
1506 }
1507 Some(Tok::StringLit(text)) => {
1508 self.bump();
1509 Some(Pat::Lit {
1510 kind: LitKind::Text,
1511 text,
1512 pos,
1513 span: self.node_span(start_i),
1514 })
1515 }
1516 Some(Tok::CharLit(text)) => {
1517 self.bump();
1518 Some(Pat::Lit {
1519 kind: LitKind::Char,
1520 text,
1521 pos,
1522 span: self.node_span(start_i),
1523 })
1524 }
1525 Some(Tok::LParen) => {
1526 self.bump();
1527 if self.eat(&Tok::RParen) {
1528 return Some(Pat::Con {
1529 qualifier: None,
1530 name: "()".to_string(),
1531 args: Vec::new(),
1532 pos,
1533 span: self.node_span(start_i),
1534 });
1535 }
1536 {
1542 let mut depth = 0usize;
1543 let mut j = self.i;
1544 let mut arrow = None;
1545 while let Some(t) = self.toks.get(j).map(|t| &t.tok) {
1546 match t {
1547 Tok::LParen | Tok::LBracket => depth += 1,
1548 Tok::RParen | Tok::RBracket => {
1549 if depth == 0 {
1550 break;
1551 }
1552 depth -= 1;
1553 }
1554 Tok::Op(o) if o == ":" && depth == 0 => break,
1555 Tok::Op(o) if o == "->" && depth == 0 => {
1556 arrow = Some(j);
1557 break;
1558 }
1559 Tok::VSemi | Tok::VRBrace => break,
1560 Tok::Op(o) if o == "\\" => break,
1562 _ => {}
1563 }
1564 j += 1;
1565 }
1566 if let Some(j) = arrow {
1567 self.i = j + 1; let inner = self.pattern()?;
1569 self.eat(&Tok::RParen);
1570 return Some(inner);
1571 }
1572 }
1573 let first = self.pattern()?;
1574 if self.at_op(":") {
1576 let mut depth = 0usize;
1577 while let Some(t) = self.peek() {
1578 match t {
1579 Tok::LParen | Tok::LBracket => depth += 1,
1580 Tok::RParen if depth == 0 => break,
1581 Tok::RParen | Tok::RBracket => depth -= 1,
1582 Tok::VSemi | Tok::VRBrace => break,
1583 _ => {}
1584 }
1585 self.i += 1;
1586 }
1587 }
1588 if self.at(&Tok::Comma) {
1589 let mut items = vec![first];
1590 while self.eat(&Tok::Comma) {
1591 items.push(self.pattern()?);
1592 }
1593 self.eat(&Tok::RParen);
1594 return Some(Pat::Tuple {
1595 items,
1596 pos,
1597 span: self.node_span(start_i),
1598 });
1599 }
1600 self.eat(&Tok::RParen);
1601 Some(first)
1602 }
1603 Some(Tok::LBracket) => {
1604 self.bump();
1605 let mut items = Vec::new();
1606 if !self.eat(&Tok::RBracket) {
1607 loop {
1608 items.push(self.pattern()?);
1609 if !self.eat(&Tok::Comma) {
1610 break;
1611 }
1612 }
1613 self.eat(&Tok::RBracket);
1614 }
1615 Some(Pat::List {
1616 items,
1617 pos,
1618 span: self.node_span(start_i),
1619 })
1620 }
1621 _ => None,
1622 }
1623 }
1624
1625 fn pattern(&mut self) -> Option<Pat> {
1627 if self.depth >= MAX_DEPTH {
1628 return None;
1629 }
1630 self.depth += 1;
1631 let result = self.pattern_inner();
1632 self.depth -= 1;
1633 result
1634 }
1635
1636 fn pattern_inner(&mut self) -> Option<Pat> {
1637 let pos = self.pos();
1638 let start_i = self.i;
1639 let first = match self.peek().cloned() {
1640 Some(Tok::UpperId { qualifier, name }) => {
1641 self.bump();
1642 if self.at(&Tok::LBrace) || self.at_keyword("with") {
1643 if self.eat_keyword("with") {
1644 let _ = self.record_fields();
1645 } else {
1646 self.skip_balanced_braces();
1647 }
1648 Pat::Con {
1649 qualifier,
1650 name,
1651 args: Vec::new(),
1652 pos,
1653 span: self.node_span(start_i),
1654 }
1655 } else {
1656 let mut args = Vec::new();
1657 while let Some(a) = self.try_pattern_atom() {
1658 args.push(a);
1659 }
1660 Pat::Con {
1661 qualifier,
1662 name,
1663 args,
1664 pos,
1665 span: self.node_span(start_i),
1666 }
1667 }
1668 }
1669 _ => self.pattern_atom()?,
1670 };
1671 if self.at_op("::") {
1672 self.bump();
1673 let rest = self.pattern()?;
1674 return Some(Pat::Con {
1675 qualifier: None,
1676 name: "::".to_string(),
1677 args: vec![first, rest],
1678 pos,
1679 span: self.node_span(start_i),
1680 });
1681 }
1682 Some(first)
1683 }
1684
1685 fn try_pattern_atom(&mut self) -> Option<Pat> {
1686 match self.peek() {
1687 Some(
1688 Tok::LowerId {
1689 qualifier: None, ..
1690 }
1691 | Tok::UpperId { .. }
1692 | Tok::IntLit(_)
1693 | Tok::DecimalLit(_)
1694 | Tok::StringLit(_)
1695 | Tok::CharLit(_)
1696 | Tok::LParen
1697 | Tok::LBracket,
1698 ) => self.pattern_atom(),
1699 _ => None,
1700 }
1701 }
1702
1703 fn skip_balanced_braces(&mut self) {
1704 let mut depth = 0usize;
1705 while let Some(t) = self.peek() {
1706 match t {
1707 Tok::LBrace => depth += 1,
1708 Tok::RBrace => {
1709 depth -= 1;
1710 if depth == 0 {
1711 self.i += 1;
1712 return;
1713 }
1714 }
1715 _ => {}
1716 }
1717 self.i += 1;
1718 }
1719 }
1720
1721 fn expr(&mut self) -> Expr {
1724 self.expr_prec(0, true)
1725 }
1726
1727 fn expr_no_do(&mut self) -> Expr {
1728 self.expr_prec(0, false)
1729 }
1730
1731 fn expr_comma_list(&mut self) -> Vec<Expr> {
1733 let mut out = vec![self.expr()];
1734 while self.eat(&Tok::Comma) {
1735 out.push(self.expr());
1736 }
1737 out
1738 }
1739
1740 fn expr_comma_list_no_do(&mut self) -> Vec<Expr> {
1741 let mut out = vec![self.expr_no_do()];
1742 while self.eat(&Tok::Comma) {
1743 out.push(self.expr_no_do());
1744 }
1745 out
1746 }
1747
1748 fn expr_prec(&mut self, min_prec: u8, allow_do: bool) -> Expr {
1749 let pos = self.pos();
1750 let start_i = self.i;
1751 if self.depth >= MAX_DEPTH {
1752 self.diag_cat(
1757 DiagnosticCategory::RecursionLimit,
1758 "expression nesting too deep; truncated to raw text",
1759 );
1760 let start = self.i;
1761 self.skip_to_item_end();
1762 if self.i == start {
1763 self.bump();
1764 }
1765 return Expr::Error {
1766 raw: self.slice_text(start),
1767 span: self.node_span(start),
1768 pos,
1769 };
1770 }
1771 self.depth += 1;
1772 let result = self.expr_prec_inner(min_prec, allow_do, pos, start_i);
1773 self.depth -= 1;
1774 result
1775 }
1776
1777 fn expr_prec_inner(&mut self, min_prec: u8, allow_do: bool, pos: Pos, start_i: usize) -> Expr {
1778 let mut lhs = match self.unary(allow_do) {
1779 Some(e) => e,
1780 None => {
1781 let start = self.i;
1783 self.skip_to_item_end();
1784 if self.i == start {
1785 self.bump();
1786 }
1787 return Expr::Error {
1788 raw: self.slice_text(start),
1789 span: self.node_span(start),
1790 pos,
1791 };
1792 }
1793 };
1794 loop {
1795 let (op, prec, right_assoc) = match self.peek() {
1796 Some(Tok::Op(o)) => {
1797 let o = o.clone();
1798 if is_reserved_op(&o) {
1799 if o == ":" {
1801 self.bump();
1802 self.skip_type_tokens();
1803 continue;
1804 }
1805 break;
1806 }
1807 let (p, r) = fixity(&o);
1808 (o, p, r)
1809 }
1810 Some(Tok::Backtick) => {
1811 let name = match self.peek_at(1) {
1813 Some(
1814 Tok::LowerId { qualifier, name } | Tok::UpperId { qualifier, name },
1815 ) => qualifier
1816 .as_ref()
1817 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
1818 _ => break,
1819 };
1820 if self.peek_at(2) != Some(&Tok::Backtick) {
1821 break;
1822 }
1823 (format!("`{name}`"), 9, false)
1824 }
1825 _ => break,
1826 };
1827 if prec < min_prec {
1828 break;
1829 }
1830 self.bump();
1831 if op.starts_with('`') {
1832 self.bump();
1833 self.bump();
1834 }
1835 let next_min = if right_assoc { prec } else { prec + 1 };
1836 let rhs = self.expr_prec(next_min, allow_do);
1837 lhs = Expr::BinOp {
1838 op,
1839 lhs: Box::new(lhs),
1840 rhs: Box::new(rhs),
1841 pos,
1842 span: self.node_span(start_i),
1843 };
1844 }
1845 lhs
1846 }
1847
1848 fn unary(&mut self, allow_do: bool) -> Option<Expr> {
1849 let pos = self.pos();
1850 let start_i = self.i;
1851 if self.at_op("-") {
1852 self.bump();
1853 let e = self.unary(allow_do)?;
1854 return Some(Expr::Neg {
1855 expr: Box::new(e),
1856 pos,
1857 span: self.node_span(start_i),
1858 });
1859 }
1860 self.application(allow_do)
1861 }
1862
1863 fn application(&mut self, allow_do: bool) -> Option<Expr> {
1864 let pos = self.pos();
1865 let start_i = self.i;
1866 let head0 = self.atom(allow_do)?;
1867 let mut head = self.projection_tail(head0);
1868 let mut args = Vec::new();
1869 loop {
1870 if self.at_keyword("with") {
1873 let target = args.pop().unwrap_or_else(|| {
1874 std::mem::replace(
1875 &mut head,
1876 Expr::Error {
1877 raw: String::new(),
1878 pos,
1879 span: Span::default(),
1880 },
1881 )
1882 });
1883 self.bump(); let fields = self.record_fields();
1885 let tpos = target.pos();
1886 let sp = Span::new(target.span().start, self.end_byte());
1887 let rec = Expr::Record {
1888 base: Box::new(target),
1889 fields,
1890 pos: tpos,
1891 span: sp,
1892 };
1893 if matches!(head, Expr::Error { ref raw, .. } if raw.is_empty()) {
1894 head = rec;
1895 } else {
1896 args.push(rec);
1897 }
1898 continue;
1899 }
1900 if !allow_do && self.at_keyword("do") {
1901 break;
1902 }
1903 if self.at_op("@") {
1905 self.bump();
1906 match self.peek() {
1907 Some(Tok::UpperId { .. } | Tok::LowerId { .. }) => {
1908 self.bump();
1909 }
1910 Some(Tok::LParen) => self.skip_balanced_parens(),
1911 Some(Tok::LBracket) => {
1912 let mut depth = 0usize;
1913 while let Some(t) = self.peek() {
1914 match t {
1915 Tok::LBracket => depth += 1,
1916 Tok::RBracket => {
1917 depth -= 1;
1918 if depth == 0 {
1919 self.i += 1;
1920 break;
1921 }
1922 }
1923 _ => {}
1924 }
1925 self.i += 1;
1926 }
1927 }
1928 _ => {}
1929 }
1930 continue;
1931 }
1932 match self.try_atom(allow_do) {
1933 Some(a) => args.push(self.projection_tail(a)),
1934 None => break,
1935 }
1936 }
1937 if args.is_empty() {
1938 Some(head)
1939 } else {
1940 Some(Expr::App {
1941 func: Box::new(head),
1942 args,
1943 pos,
1944 span: self.node_span(start_i),
1945 })
1946 }
1947 }
1948
1949 fn record_fields(&mut self) -> Vec<FieldAssign> {
1951 let mut fields = Vec::new();
1952 let explicit = self.at(&Tok::LBrace);
1953 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1954 return fields;
1955 }
1956 loop {
1957 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) || self.eat(&Tok::Comma) {}
1958 match self.peek() {
1959 None => break,
1960 Some(Tok::VRBrace) if !explicit => {
1961 self.bump();
1962 break;
1963 }
1964 Some(Tok::RBrace) => {
1965 self.bump();
1966 break;
1967 }
1968 Some(Tok::RParen | Tok::RBracket) => {
1970 self.bump();
1971 continue;
1972 }
1973 _ => {}
1974 }
1975 let pos = self.pos();
1976 let start_i = self.i;
1977 if self.at_op("..") {
1978 self.bump();
1979 fields.push(FieldAssign {
1980 name: "..".to_string(),
1981 value: None,
1982 pos,
1983 span: self.node_span(start_i),
1984 });
1985 continue;
1986 }
1987 let name = match self.peek().cloned() {
1988 Some(Tok::LowerId {
1989 qualifier: None,
1990 name,
1991 }) => {
1992 self.bump();
1993 name
1994 }
1995 _ => {
1996 self.skip_to_item_end();
1997 continue;
1998 }
1999 };
2000 if self.eat_op("=") {
2001 let value = self.expr_prec(1, true);
2002 fields.push(FieldAssign {
2003 name,
2004 value: Some(value),
2005 pos,
2006 span: self.node_span(start_i),
2007 });
2008 } else {
2009 fields.push(FieldAssign {
2011 name,
2012 value: None,
2013 pos,
2014 span: self.node_span(start_i),
2015 });
2016 }
2017 }
2018 fields
2019 }
2020
2021 fn try_atom(&mut self, allow_do: bool) -> Option<Expr> {
2022 match self.peek() {
2023 Some(Tok::LowerId { .. }) => {
2024 let kw = self.peek().and_then(|t| t.keyword());
2025 match kw {
2026 Some("do") if allow_do => self.atom(allow_do),
2028 Some(
2031 "if" | "case" | "do" | "let" | "try" | "where" | "then" | "else" | "of"
2032 | "in" | "controller" | "with" | "catch",
2033 ) => None,
2034 _ => self.atom(allow_do),
2035 }
2036 }
2037 Some(
2038 Tok::UpperId { .. }
2039 | Tok::IntLit(_)
2040 | Tok::DecimalLit(_)
2041 | Tok::StringLit(_)
2042 | Tok::CharLit(_)
2043 | Tok::LParen
2044 | Tok::LBracket,
2045 ) => self.atom(allow_do),
2046 Some(Tok::Op(o)) if o == "\\" => self.atom(allow_do),
2048 _ => None,
2049 }
2050 }
2051
2052 fn projection_tail(&mut self, mut base: Expr) -> Expr {
2059 while self.at_tight_projection() {
2060 let start = base.span().start;
2061 let pos = base.pos();
2062 self.bump(); let field_tok = self.bump().expect("tight projection guarantees a field");
2064 let (qualifier, name) = match field_tok.tok {
2065 Tok::LowerId { qualifier, name } => (qualifier, name),
2066 other => unreachable!("at_tight_projection guarantees LowerId, got {other:?}"),
2067 };
2068 let field = Expr::Var {
2069 qualifier,
2070 name,
2071 pos: field_tok.pos,
2072 span: Span::new(field_tok.start, field_tok.end),
2073 };
2074 base = Expr::BinOp {
2075 op: ".".to_string(),
2076 lhs: Box::new(base),
2077 rhs: Box::new(field),
2078 pos,
2079 span: Span::new(start, self.end_byte()),
2080 };
2081 }
2082 base
2083 }
2084
2085 fn at_tight_projection(&self) -> bool {
2089 if self.i == 0 {
2090 return false;
2091 }
2092 let dot = match self.toks.get(self.i) {
2093 Some(t) => t,
2094 None => return false,
2095 };
2096 if !matches!(&dot.tok, Tok::Op(o) if o == ".") {
2097 return false;
2098 }
2099 let prev = &self.toks[self.i - 1];
2103 if prev.is_virtual() || prev.end != dot.start {
2104 return false;
2105 }
2106 self.toks.get(self.i + 1).is_some_and(|t| {
2108 matches!(
2109 &t.tok,
2110 Tok::LowerId {
2111 qualifier: None,
2112 ..
2113 }
2114 ) && t.start == dot.end
2115 })
2116 }
2117
2118 fn atom(&mut self, allow_do: bool) -> Option<Expr> {
2119 let pos = self.pos();
2120 let start_i = self.i;
2121 match self.peek().cloned() {
2122 Some(Tok::LowerId { qualifier, name }) => {
2123 match name.as_str() {
2124 "if" if qualifier.is_none() => return self.if_expr(),
2125 "case" if qualifier.is_none() => return self.case_expr(),
2126 "do" if qualifier.is_none() => {
2127 if !allow_do {
2128 return None;
2129 }
2130 return self.do_expr();
2131 }
2132 "let" if qualifier.is_none() => return self.let_expr(),
2133 "try" if qualifier.is_none() => return self.try_expr(),
2134 _ => {}
2135 }
2136 self.bump();
2137 Some(Expr::Var {
2138 qualifier,
2139 name,
2140 pos,
2141 span: self.node_span(start_i),
2142 })
2143 }
2144 Some(Tok::UpperId { qualifier, name }) => {
2145 self.bump();
2146 let base = Expr::Con {
2147 qualifier,
2148 name,
2149 pos,
2150 span: self.node_span(start_i),
2151 };
2152 if self.at(&Tok::LBrace) {
2154 let fields = self.record_fields();
2155 return Some(Expr::Record {
2156 base: Box::new(base),
2157 fields,
2158 pos,
2159 span: self.node_span(start_i),
2160 });
2161 }
2162 Some(base)
2163 }
2164 Some(Tok::IntLit(text)) => {
2165 self.bump();
2166 Some(Expr::Lit {
2167 kind: LitKind::Int,
2168 text,
2169 pos,
2170 span: self.node_span(start_i),
2171 })
2172 }
2173 Some(Tok::DecimalLit(text)) => {
2174 self.bump();
2175 Some(Expr::Lit {
2176 kind: LitKind::Decimal,
2177 text,
2178 pos,
2179 span: self.node_span(start_i),
2180 })
2181 }
2182 Some(Tok::StringLit(text)) => {
2183 self.bump();
2184 Some(Expr::Lit {
2185 kind: LitKind::Text,
2186 text,
2187 pos,
2188 span: self.node_span(start_i),
2189 })
2190 }
2191 Some(Tok::CharLit(text)) => {
2192 self.bump();
2193 Some(Expr::Lit {
2194 kind: LitKind::Char,
2195 text,
2196 pos,
2197 span: self.node_span(start_i),
2198 })
2199 }
2200 Some(Tok::Op(o)) if o == "\\" => self.lambda_expr(),
2201 Some(Tok::LParen) => self.paren_expr(),
2202 Some(Tok::LBracket) => self.list_expr(),
2203 _ => None,
2204 }
2205 }
2206
2207 fn if_expr(&mut self) -> Option<Expr> {
2208 let pos = self.pos();
2209 let start_i = self.i;
2210 self.bump(); let cond = self.expr();
2212 self.eat(&Tok::VSemi); if !self.eat_keyword("then") {
2214 self.diag("expected 'then'");
2215 return Some(Expr::Error {
2216 raw: format!("if {}", cond.render()),
2217 pos,
2218 span: self.node_span(start_i),
2219 });
2220 }
2221 let then_branch = self.expr();
2222 self.eat(&Tok::VSemi);
2223 if !self.eat_keyword("else") {
2224 self.diag("expected 'else'");
2225 return Some(Expr::Error {
2226 raw: format!("if {} then {}", cond.render(), then_branch.render()),
2227 pos,
2228 span: self.node_span(start_i),
2229 });
2230 }
2231 let else_branch = self.expr();
2232 Some(Expr::If {
2233 cond: Box::new(cond),
2234 then_branch: Box::new(then_branch),
2235 else_branch: Box::new(else_branch),
2236 pos,
2237 span: self.node_span(start_i),
2238 })
2239 }
2240
2241 fn case_expr(&mut self) -> Option<Expr> {
2242 let pos = self.pos();
2243 let start_i = self.i;
2244 self.bump(); let scrutinee = self.expr_no_do();
2246 if !self.eat_keyword("of") {
2247 self.diag("expected 'of' in case expression");
2248 return Some(Expr::Error {
2249 raw: format!("case {}", scrutinee.render()),
2250 pos,
2251 span: self.node_span(start_i),
2252 });
2253 }
2254 let mut alts = Vec::new();
2255 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2256 loop {
2257 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2258 match self.peek() {
2259 None => break,
2260 Some(Tok::VRBrace | Tok::RBrace) => {
2261 self.bump();
2262 break;
2263 }
2264 Some(Tok::RParen | Tok::RBracket) => {
2266 self.bump();
2267 continue;
2268 }
2269 _ => {}
2270 }
2271 if self.eat_keyword("where") {
2273 let _ = self.binding_block();
2274 continue;
2275 }
2276 match self.case_alt() {
2277 Some(a) => alts.push(a),
2278 None => self.skip_to_item_end(),
2279 }
2280 }
2281 }
2282 Some(Expr::Case {
2283 scrutinee: Box::new(scrutinee),
2284 alts,
2285 pos,
2286 span: self.node_span(start_i),
2287 })
2288 }
2289
2290 fn case_alt(&mut self) -> Option<Alt> {
2291 let pos = self.pos();
2292 let start_i = self.i;
2293 let pat = self.pattern()?;
2294 if self.at_op("|") {
2295 let mut first: Option<Expr> = None;
2299 while self.eat_op("|") {
2300 loop {
2301 let _guard = self.expr();
2302 if self.eat_op("<-") {
2303 let _ = self.expr();
2304 }
2305 if !self.eat(&Tok::Comma) {
2306 break;
2307 }
2308 }
2309 if !self.eat_op("->") {
2310 self.diag("expected '->' in guarded case alternative");
2311 return None;
2312 }
2313 let body = self.expr();
2314 if first.is_none() {
2315 first = Some(body);
2316 }
2317 }
2318 return Some(Alt {
2319 pat,
2320 body: first?,
2321 pos,
2322 span: self.node_span(start_i),
2323 });
2324 }
2325 if !self.eat_op("->") {
2326 self.diag("expected '->' in case alternative");
2327 return None;
2328 }
2329 let body = self.expr();
2330 Some(Alt {
2331 pat,
2332 body,
2333 pos,
2334 span: self.node_span(start_i),
2335 })
2336 }
2337
2338 fn do_expr(&mut self) -> Option<Expr> {
2339 let pos = self.pos();
2340 let start_i = self.i;
2341 self.bump(); let mut stmts = Vec::new();
2343 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2344 loop {
2345 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2346 match self.peek() {
2347 None => break,
2348 Some(Tok::VRBrace | Tok::RBrace) => {
2349 self.bump();
2350 break;
2351 }
2352 Some(Tok::RParen | Tok::RBracket) => {
2354 self.bump();
2355 continue;
2356 }
2357 _ => {}
2358 }
2359 stmts.push(self.do_stmt());
2360 }
2361 }
2362 Some(Expr::Do {
2363 stmts,
2364 pos,
2365 span: self.node_span(start_i),
2366 })
2367 }
2368
2369 fn do_stmt(&mut self) -> DoStmt {
2370 let pos = self.pos();
2371 let start_i = self.i;
2372 if self.at_keyword("let") {
2373 self.bump();
2374 let bindings = self.binding_block();
2375 if self.eat_keyword("in") {
2377 let body = self.expr();
2378 return DoStmt::Expr {
2379 expr: Expr::LetIn {
2380 bindings,
2381 body: Box::new(body),
2382 pos,
2383 span: self.node_span(start_i),
2384 },
2385 pos,
2386 span: self.node_span(start_i),
2387 };
2388 }
2389 return DoStmt::Let {
2390 bindings,
2391 pos,
2392 span: self.node_span(start_i),
2393 };
2394 }
2395 let snapshot = self.i;
2397 if let Some(pat) = self.try_bind_pattern() {
2398 if self.at_op("<-") {
2399 self.bump();
2400 let expr = self.expr();
2401 return DoStmt::Bind {
2402 pat,
2403 expr,
2404 pos,
2405 span: self.node_span(start_i),
2406 };
2407 }
2408 }
2409 self.i = snapshot;
2410 let expr = self.expr();
2411 DoStmt::Expr {
2412 expr,
2413 pos,
2414 span: self.node_span(start_i),
2415 }
2416 }
2417
2418 fn try_bind_pattern(&mut self) -> Option<Pat> {
2421 self.pattern()
2422 }
2423
2424 fn let_expr(&mut self) -> Option<Expr> {
2425 let pos = self.pos();
2426 let start_i = self.i;
2427 self.bump(); let bindings = self.binding_block();
2429 if self.eat_keyword("in") {
2430 let body = self.expr();
2431 return Some(Expr::LetIn {
2432 bindings,
2433 body: Box::new(body),
2434 pos,
2435 span: self.node_span(start_i),
2436 });
2437 }
2438 Some(Expr::LetIn {
2440 bindings,
2441 body: Box::new(Expr::Error {
2442 raw: String::new(),
2443 pos,
2444 span: self.node_span(start_i),
2445 }),
2446 pos,
2447 span: self.node_span(start_i),
2448 })
2449 }
2450
2451 fn try_expr(&mut self) -> Option<Expr> {
2452 let pos = self.pos();
2453 let start_i = self.i;
2454 self.bump(); let body = self.expr();
2456 let mut handlers = Vec::new();
2457 self.eat(&Tok::VSemi);
2458 if self.eat_keyword("catch") {
2459 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2460 loop {
2461 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2462 match self.peek() {
2463 None => break,
2464 Some(Tok::VRBrace | Tok::RBrace) => {
2465 self.bump();
2466 break;
2467 }
2468 Some(Tok::RParen | Tok::RBracket) => {
2470 self.bump();
2471 continue;
2472 }
2473 _ => {}
2474 }
2475 match self.case_alt() {
2476 Some(a) => handlers.push(a),
2477 None => self.skip_to_item_end(),
2478 }
2479 }
2480 } else if let Some(a) = self.case_alt() {
2481 handlers.push(a);
2483 }
2484 }
2485 Some(Expr::Try {
2486 body: Box::new(body),
2487 handlers,
2488 pos,
2489 span: self.node_span(start_i),
2490 })
2491 }
2492
2493 fn lambda_expr(&mut self) -> Option<Expr> {
2494 let pos = self.pos();
2495 let start_i = self.i;
2496 self.bump(); if self.eat_keyword("case") {
2499 let mut alts = Vec::new();
2500 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2501 loop {
2502 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2503 match self.peek() {
2504 None => break,
2505 Some(Tok::VRBrace | Tok::RBrace) => {
2506 self.bump();
2507 break;
2508 }
2509 Some(Tok::RParen | Tok::RBracket) => {
2510 self.bump();
2511 continue;
2512 }
2513 _ => {}
2514 }
2515 match self.case_alt() {
2516 Some(a) => alts.push(a),
2517 None => self.skip_to_item_end(),
2518 }
2519 }
2520 }
2521 return Some(Expr::Lambda {
2522 params: vec![Pat::Var {
2523 name: "_".to_string(),
2524 pos,
2525 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2526 }],
2527 body: Box::new(Expr::Case {
2528 scrutinee: Box::new(Expr::Var {
2529 qualifier: None,
2530 name: "_".to_string(),
2531 pos,
2532 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2533 }),
2534 alts,
2535 pos,
2536 span: self.node_span(start_i),
2537 }),
2538 pos,
2539 span: self.node_span(start_i),
2540 });
2541 }
2542 let mut params = Vec::new();
2543 while !self.at_op("->") {
2544 match self.pattern_atom() {
2545 Some(p) => params.push(p),
2546 None => {
2547 self.diag("bad lambda parameter");
2548 let start = self.i;
2549 self.skip_to_item_end();
2550 return Some(Expr::Error {
2551 raw: format!("\\{}", self.slice_text(start)),
2552 pos,
2553 span: self.node_span(start_i),
2554 });
2555 }
2556 }
2557 }
2558 self.bump(); let body = self.expr();
2560 Some(Expr::Lambda {
2561 params,
2562 body: Box::new(body),
2563 pos,
2564 span: self.node_span(start_i),
2565 })
2566 }
2567
2568 fn paren_expr(&mut self) -> Option<Expr> {
2569 let pos = self.pos();
2570 let start_i = self.i;
2571 self.bump(); if self.eat(&Tok::RParen) {
2573 return Some(Expr::Con {
2574 qualifier: None,
2575 name: "()".to_string(),
2576 pos,
2577 span: self.node_span(start_i),
2578 });
2579 }
2580 if let Some(Tok::Op(o)) = self.peek().cloned() {
2582 if !is_reserved_op(&o) && o != "\\" && o != "-" {
2583 self.bump();
2584 if self.eat(&Tok::RParen) {
2585 return Some(Expr::Section {
2586 op: o,
2587 operand: None,
2588 left: false,
2589 pos,
2590 span: self.node_span(start_i),
2591 });
2592 }
2593 let operand = self.expr();
2594 self.eat(&Tok::RParen);
2595 return Some(Expr::Section {
2596 op: o,
2597 operand: Some(Box::new(operand)),
2598 left: false,
2599 pos,
2600 span: self.node_span(start_i),
2601 });
2602 }
2603 }
2604 let first = self.expr();
2605 if self.at(&Tok::Comma) {
2606 let mut items = vec![first];
2607 while self.eat(&Tok::Comma) {
2608 items.push(self.expr());
2609 }
2610 self.eat(&Tok::RParen);
2611 return Some(Expr::Tuple {
2612 items,
2613 pos,
2614 span: self.node_span(start_i),
2615 });
2616 }
2617 if let Some(Tok::Op(o)) = self.peek().cloned() {
2619 if !is_reserved_op(&o) && self.peek_at(1) == Some(&Tok::RParen) {
2620 self.bump();
2621 self.bump();
2622 return Some(Expr::Section {
2623 op: o,
2624 operand: Some(Box::new(first)),
2625 left: true,
2626 pos,
2627 span: self.node_span(start_i),
2628 });
2629 }
2630 }
2631 self.eat(&Tok::RParen);
2632 Some(first)
2633 }
2634
2635 fn list_expr(&mut self) -> Option<Expr> {
2636 let pos = self.pos();
2637 let start_i = self.i;
2638 self.bump(); let mut items = Vec::new();
2640 if self.eat(&Tok::RBracket) {
2641 return Some(Expr::List {
2642 items,
2643 pos,
2644 span: self.node_span(start_i),
2645 });
2646 }
2647 loop {
2648 let e = self.expr();
2649 if self.at_op("..") {
2651 self.bump();
2652 let hi = if self.at(&Tok::RBracket) {
2653 Expr::Error {
2654 raw: String::new(),
2655 pos,
2656 span: self.node_span(start_i),
2657 }
2658 } else {
2659 self.expr()
2660 };
2661 self.eat(&Tok::RBracket);
2662 return Some(Expr::BinOp {
2663 op: "..".to_string(),
2664 lhs: Box::new(e),
2665 rhs: Box::new(hi),
2666 pos,
2667 span: self.node_span(start_i),
2668 });
2669 }
2670 if self.at_op("|") {
2672 let start = self.i;
2673 let mut brackets = 1usize;
2674 while let Some(t) = self.peek() {
2675 match t {
2676 Tok::LBracket => brackets += 1,
2677 Tok::RBracket => {
2678 brackets -= 1;
2679 if brackets == 0 {
2680 break;
2681 }
2682 }
2683 Tok::VSemi | Tok::VRBrace => break,
2684 _ => {}
2685 }
2686 self.i += 1;
2687 }
2688 let raw = self.slice_text(start);
2689 self.eat(&Tok::RBracket);
2690 return Some(Expr::App {
2691 func: Box::new(e),
2692 args: vec![Expr::Error {
2693 raw,
2694 pos,
2695 span: self.node_span(start_i),
2696 }],
2697 pos,
2698 span: self.node_span(start_i),
2699 });
2700 }
2701 items.push(e);
2702 if !self.eat(&Tok::Comma) {
2703 break;
2704 }
2705 }
2706 self.eat(&Tok::RBracket);
2707 Some(Expr::List {
2708 items,
2709 pos,
2710 span: self.node_span(start_i),
2711 })
2712 }
2713}
2714
2715fn is_reserved_op(op: &str) -> bool {
2718 matches!(op, "=" | "<-" | "->" | "|" | ":" | "=>" | "@" | "\\" | "..")
2719}
2720
2721fn fixity(op: &str) -> (u8, bool) {
2724 match op {
2725 "$" | "$!" => (1, true),
2726 ">>=" | ">>" | "=<<" | "<&>" => (2, false),
2727 "||" => (3, true),
2728 "&&" => (4, true),
2729 "==" | "/=" | "<" | "<=" | ">" | ">=" => (5, false),
2730 "::" | "++" | "<>" => (6, true),
2731 "+" | "-" => (7, false),
2732 "*" | "/" => (8, false),
2733 "^" | "**" => (9, true),
2734 "." | "!!" => (10, true),
2735 _ => (9, false),
2736 }
2737}
2738
2739fn equations_extent(eqs: &[Equation]) -> Option<Span> {
2744 let mut it = eqs.iter();
2745 let first = it.next()?;
2746 let mut s = first.span;
2747 for e in it {
2748 s.start = s.start.min(e.span.start);
2749 s.end = s.end.max(e.span.end);
2750 }
2751 Some(s)
2752}
2753
2754fn merge_functions(decls: &mut Vec<Decl>) {
2755 let mut out: Vec<Decl> = Vec::with_capacity(decls.len());
2756 for decl in decls.drain(..) {
2757 match decl {
2758 Decl::Function(f) => {
2759 let existing = out.iter_mut().find_map(|d| match d {
2760 Decl::Function(g) if g.name == f.name => Some(g),
2761 _ => None,
2762 });
2763 match existing {
2764 Some(g) => {
2765 if g.ty.is_none() {
2766 g.ty = f.ty.clone();
2767 }
2768 if g.sig_span.is_none() {
2769 g.sig_span = f.sig_span;
2770 }
2771 if g.equations.is_empty() && !f.equations.is_empty() {
2774 g.pos = f.pos;
2775 }
2776 g.equations.extend(f.equations);
2777 g.span = equations_extent(&g.equations)
2784 .or(g.sig_span)
2785 .unwrap_or(g.span);
2786 }
2787 None => out.push(Decl::Function(f)),
2788 }
2789 }
2790 other => out.push(other),
2791 }
2792 }
2793 *decls = out;
2794}
2795
2796pub(crate) fn parse_type_from_tokens(tokens: &[Token]) -> Option<Type> {
2805 let real_tokens: Vec<&Token> = tokens.iter().filter(|t| !t.is_virtual()).collect();
2808 if real_tokens.is_empty() {
2809 return None;
2810 }
2811 let mut parser = TypeTokenParser {
2812 tokens: &real_tokens,
2813 cursor: 0,
2814 };
2815 let ty = parser.parse_type()?;
2816 if parser.cursor == real_tokens.len() {
2819 Some(ty)
2820 } else {
2821 None
2822 }
2823}
2824
2825struct TypeTokenParser<'a> {
2826 tokens: &'a [&'a Token],
2827 cursor: usize,
2828}
2829
2830enum TypeAtom {
2833 ParsedType(Type),
2834 DroppedLiteral(Span),
2835}
2836
2837impl<'a> TypeTokenParser<'a> {
2838 fn peek(&self) -> Option<&'a Token> {
2839 self.tokens.get(self.cursor).copied()
2840 }
2841
2842 fn eat_op(&mut self, op: &str) -> bool {
2843 if self.peek().is_some_and(|t| t.tok.is_op(op)) {
2844 self.cursor += 1;
2845 true
2846 } else {
2847 false
2848 }
2849 }
2850
2851 fn parse_type(&mut self) -> Option<Type> {
2854 let lhs = self.parse_application_type()?;
2855 if self.eat_op("=>") {
2856 let body = self.parse_type()?;
2858 let span = Span::new(lhs.span().start, body.span().end);
2859 return Some(Type::Constrained(Box::new(body), span));
2860 }
2861 if self.eat_op("->") {
2862 let rhs = self.parse_type()?;
2863 let span = Span::new(lhs.span().start, rhs.span().end);
2864 return Some(Type::Fun(Box::new(lhs), Box::new(rhs), span));
2865 }
2866 Some(lhs)
2867 }
2868
2869 fn parse_application_type(&mut self) -> Option<Type> {
2871 let head = match self.parse_atom()? {
2872 TypeAtom::ParsedType(t) => t,
2873 TypeAtom::DroppedLiteral(_) => return None,
2875 };
2876 let mut args = Vec::new();
2877 let start = head.span().start;
2878 let mut end = head.span().end;
2879 loop {
2880 if !self.is_at_type_atom_start() {
2883 break;
2884 }
2885 match self.parse_atom()? {
2886 TypeAtom::ParsedType(t) => {
2887 end = t.span().end;
2888 args.push(t);
2889 }
2890 TypeAtom::DroppedLiteral(span) => {
2891 end = span.end;
2894 }
2895 }
2896 }
2897 let span = Span::new(start, end);
2898 if args.is_empty() {
2899 Some(head.with_span(span))
2900 } else {
2901 Some(Type::App(Box::new(head), args, span))
2902 }
2903 }
2904
2905 fn is_at_type_atom_start(&self) -> bool {
2908 matches!(
2909 self.peek().map(|t| &t.tok),
2910 Some(
2911 Tok::UpperId { .. }
2912 | Tok::LowerId { .. }
2913 | Tok::IntLit(_)
2914 | Tok::DecimalLit(_)
2915 | Tok::LBracket
2916 | Tok::LParen
2917 )
2918 )
2919 }
2920
2921 fn parse_atom(&mut self) -> Option<TypeAtom> {
2922 let tok = self.peek()?;
2923 match &tok.tok {
2924 Tok::UpperId { qualifier, name } => {
2925 let con = Type::Con {
2926 qualifier: qualifier.clone(),
2927 name: name.clone(),
2928 span: Span::new(tok.start, tok.end),
2929 };
2930 self.cursor += 1;
2931 Some(TypeAtom::ParsedType(con))
2932 }
2933 Tok::LowerId { name, .. } => {
2934 let var = Type::Var(name.clone(), Span::new(tok.start, tok.end));
2937 self.cursor += 1;
2938 Some(TypeAtom::ParsedType(var))
2939 }
2940 Tok::IntLit(_) | Tok::DecimalLit(_) => {
2941 self.cursor += 1;
2943 Some(TypeAtom::DroppedLiteral(Span::new(tok.start, tok.end)))
2944 }
2945 Tok::LBracket => {
2946 let start = tok.start;
2947 self.cursor += 1;
2948 let inner = self.parse_type()?;
2949 self.eat_token(&Tok::RBracket).map(|end| {
2950 TypeAtom::ParsedType(Type::List(Box::new(inner), Span::new(start, end.end)))
2951 })
2952 }
2953 Tok::LParen => {
2954 let start = tok.start;
2955 self.cursor += 1;
2956 if let Some(end) = self.eat_token(&Tok::RParen) {
2957 return Some(TypeAtom::ParsedType(Type::Unit(Span::new(start, end.end))));
2959 }
2960 let first = self.parse_type()?;
2961 if self.peek().map(|t| &t.tok) == Some(&Tok::Comma) {
2962 let mut items = vec![first];
2963 while self.eat_token(&Tok::Comma).is_some() {
2964 items.push(self.parse_type()?);
2965 }
2966 self.eat_token(&Tok::RParen).map(|end| {
2967 TypeAtom::ParsedType(Type::Tuple(items, Span::new(start, end.end)))
2968 })
2969 } else {
2970 self.eat_token(&Tok::RParen).map(|end| {
2971 TypeAtom::ParsedType(first.with_span(Span::new(start, end.end)))
2973 })
2974 }
2975 }
2976 _ => None,
2977 }
2978 }
2979
2980 fn eat_token(&mut self, tok: &Tok) -> Option<&'a Token> {
2981 if self.peek().is_some_and(|t| t.tok == *tok) {
2982 let t = self.peek();
2983 self.cursor += 1;
2984 t
2985 } else {
2986 None
2987 }
2988 }
2989}
2990
2991fn render_token_slice(tokens: &[Token]) -> String {
2992 let mut s = String::new();
2993 let mut prev_no_space_after = true;
2994 for t in tokens {
2995 let (text, no_space_before, no_space_after): (String, bool, bool) = match &t.tok {
2996 Tok::LowerId { qualifier, name } | Tok::UpperId { qualifier, name } => (
2997 qualifier
2998 .as_ref()
2999 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
3000 false,
3001 false,
3002 ),
3003 Tok::Op(o) => (o.clone(), false, false),
3004 Tok::IntLit(n) | Tok::DecimalLit(n) => (n.clone(), false, false),
3005 Tok::StringLit(v) => (format!("{v:?}"), false, false),
3006 Tok::CharLit(v) => (format!("'{v}'"), false, false),
3007 Tok::LParen => ("(".to_string(), false, true),
3008 Tok::RParen => (")".to_string(), true, false),
3009 Tok::LBracket => ("[".to_string(), false, true),
3010 Tok::RBracket => ("]".to_string(), true, false),
3011 Tok::LBrace => ("{".to_string(), false, true),
3012 Tok::RBrace => ("}".to_string(), true, false),
3013 Tok::Comma => (",".to_string(), true, false),
3014 Tok::Semi | Tok::VSemi => (";".to_string(), true, false),
3015 Tok::Backtick => ("`".to_string(), false, false),
3016 Tok::VLBrace | Tok::VRBrace => continue,
3017 };
3018 if !s.is_empty() && !no_space_before && !prev_no_space_after {
3019 s.push(' ');
3020 }
3021 s.push_str(&text);
3022 prev_no_space_after = no_space_after;
3023 }
3024 s
3025}
3026
3027#[cfg(test)]
3028mod type_tests {
3029 use super::*;
3030 use crate::lexer::lex;
3031
3032 fn ty(s: &str) -> Option<Type> {
3036 let (toks, errs) = lex(s);
3037 assert!(errs.is_empty(), "lex errors for {s:?}: {errs:?}");
3038 parse_type_from_tokens(&toks)
3039 }
3040
3041 fn con(name: &str) -> Type {
3042 Type::Con {
3043 qualifier: None,
3044 name: name.to_string(),
3045 span: Span::default(),
3046 }
3047 }
3048
3049 fn qualified_con(qualifier: &str, name: &str) -> Type {
3050 Type::Con {
3051 qualifier: Some(qualifier.to_string()),
3052 name: name.to_string(),
3053 span: Span::default(),
3054 }
3055 }
3056
3057 fn app(head: Type, args: Vec<Type>) -> Type {
3058 Type::App(Box::new(head), args, Span::default())
3059 }
3060
3061 fn list(inner: Type) -> Type {
3062 Type::List(Box::new(inner), Span::default())
3063 }
3064
3065 fn tuple(items: Vec<Type>) -> Type {
3066 Type::Tuple(items, Span::default())
3067 }
3068
3069 fn fun(param: Type, result: Type) -> Type {
3070 Type::Fun(Box::new(param), Box::new(result), Span::default())
3071 }
3072
3073 fn var(name: &str) -> Type {
3074 Type::Var(name.to_string(), Span::default())
3075 }
3076
3077 fn unit() -> Type {
3078 Type::Unit(Span::default())
3079 }
3080
3081 fn constrained(body: Type) -> Type {
3082 Type::Constrained(Box::new(body), Span::default())
3083 }
3084
3085 #[test]
3086 fn atoms() {
3087 assert_eq!(ty("Party"), Some(con("Party")));
3088 assert_eq!(ty("Decimal"), Some(con("Decimal")));
3089 assert_eq!(ty("a"), Some(var("a")));
3090 assert_eq!(ty("()"), Some(unit()));
3091 }
3092
3093 #[test]
3094 fn application_vs_constructor() {
3095 assert_eq!(
3098 ty("ContractId Foo"),
3099 Some(app(con("ContractId"), vec![con("Foo")]))
3100 );
3101 assert_eq!(
3102 ty("Optional (ContractId Foo)"),
3103 Some(app(
3104 con("Optional"),
3105 vec![app(con("ContractId"), vec![con("Foo")])]
3106 ))
3107 );
3108 assert_eq!(
3109 ty("Map Text Int"),
3110 Some(app(con("Map"), vec![con("Text"), con("Int")]))
3111 );
3112 }
3113
3114 #[test]
3115 fn qualified_constructor_keeps_qualifier() {
3116 assert_eq!(
3117 ty("DA.Map.Map Text Int"),
3118 Some(app(
3119 qualified_con("DA.Map", "Map"),
3120 vec![con("Text"), con("Int")]
3121 ))
3122 );
3123 }
3124
3125 #[test]
3126 fn list_and_tuple() {
3127 assert_eq!(ty("[Text]"), Some(list(con("Text"))));
3128 assert_eq!(
3129 ty("(Int, Text)"),
3130 Some(tuple(vec![con("Int"), con("Text")]))
3131 );
3132 assert_eq!(
3134 ty("(a, b, c)"),
3135 Some(tuple(vec![var("a"), var("b"), var("c")]))
3136 );
3137 assert_eq!(ty("(Text)"), Some(con("Text")));
3139 }
3140
3141 #[test]
3142 fn function_types_are_arrows_not_names() {
3143 assert_eq!(ty("Int -> Int"), Some(fun(con("Int"), con("Int"))));
3146 assert_eq!(
3148 ty("Int -> Text -> Bool"),
3149 Some(fun(con("Int"), fun(con("Text"), con("Bool"))))
3150 );
3151 assert_eq!(
3152 ty("Party -> Script ()"),
3153 Some(fun(con("Party"), app(con("Script"), vec![unit()])))
3154 );
3155 }
3156
3157 #[test]
3158 fn script_application() {
3159 assert_eq!(ty("Script ()"), Some(app(con("Script"), vec![unit()])));
3162 }
3163
3164 #[test]
3165 fn numeric_nat_literal_is_dropped() {
3166 assert_eq!(ty("Numeric 10"), Some(con("Numeric")));
3169 assert_eq!(ty("Numeric n"), Some(app(con("Numeric"), vec![var("n")])));
3170 }
3171
3172 #[test]
3173 fn constraint_context_is_dropped_body_kept() {
3174 assert_eq!(
3177 ty("NumericScale n => Numeric 37 -> Numeric n"),
3178 Some(constrained(fun(
3179 con("Numeric"),
3180 app(con("Numeric"), vec![var("n")])
3181 )))
3182 );
3183 assert_eq!(ty("(Eq a, Show a) => a"), Some(constrained(var("a"))));
3185 }
3186
3187 #[test]
3188 fn unparseable_is_none() {
3189 assert_eq!(ty("Int ->"), None);
3192 assert_eq!(ty("-> Int"), None);
3193 }
3194
3195 #[test]
3196 fn ty_is_populated_through_real_parse() {
3197 let src = r#"module M where
3200template T
3201 with
3202 owner : Party
3203 held : ContractId Asset
3204 where
3205 signatory owner
3206 choice Go : Optional (ContractId Asset)
3207 controller owner
3208 do
3209 pure None
3210"#;
3211 let (m, _) = parse_module(src);
3212 let t = match &m.decls[0] {
3213 Decl::Template(t) => t,
3214 other => panic!("expected template, got {other:?}"),
3215 };
3216 assert_eq!(t.fields[0].ty, Some(con("Party")));
3217 assert_eq!(
3218 t.fields[1].ty,
3219 Some(app(con("ContractId"), vec![con("Asset")]))
3220 );
3221 let choice = match &t
3222 .body
3223 .iter()
3224 .find(|d| matches!(d, TemplateBodyDecl::Choice(_)))
3225 {
3226 Some(TemplateBodyDecl::Choice(c)) => (*c).clone(),
3227 _ => panic!("expected choice"),
3228 };
3229 assert_eq!(
3230 choice.return_ty,
3231 Some(app(
3232 con("Optional"),
3233 vec![app(con("ContractId"), vec![con("Asset")])]
3234 ))
3235 );
3236 }
3237
3238 #[test]
3239 fn ty_is_populated_on_key_and_interface_method() {
3240 let src = r#"module M where
3243template T
3244 with
3245 owner : Party
3246 where
3247 signatory owner
3248 key owner : Party
3249 maintainer owner
3250
3251interface I where
3252 getAmount : Numeric 10
3253"#;
3254 let (m, _) = parse_module(src);
3255 let t = match &m.decls[0] {
3256 Decl::Template(t) => t,
3257 other => panic!("expected template, got {other:?}"),
3258 };
3259 let key_ty = t.body.iter().find_map(|d| match d {
3260 TemplateBodyDecl::Key { ty, .. } => Some(ty.clone()),
3261 _ => None,
3262 });
3263 assert_eq!(key_ty, Some(Some(con("Party"))));
3264
3265 let iface = match &m.decls[1] {
3266 Decl::Interface(i) => i,
3267 other => panic!("expected interface, got {other:?}"),
3268 };
3269 assert_eq!(iface.methods[0].ty, Some(con("Numeric")));
3271 }
3272}