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