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) | Some(Tok::RBrace) => {
287 self.bump();
288 break;
289 }
290 Some(Tok::RParen) | Some(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) | Some(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) | Some(Tok::RBrace) => {
622 self.bump();
623 break;
624 }
625 Some(Tok::RParen) | Some(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) | Some(Tok::RBrace) => {
721 self.bump();
722 break;
723 }
724 Some(Tok::RParen) | Some(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")
817 | Some("nonconsuming")
818 | Some("preconsuming")
819 | Some("postconsuming") => self.choice_decl().map_or_else(
820 || {
821 self.skip_to_item_end();
822 TemplateBodyDecl::Other {
823 raw: self.slice_text(start),
824 span: self.node_span(start),
825 pos,
826 }
827 },
828 TemplateBodyDecl::Choice,
829 ),
830 Some("interface") => self.interface_instance_decl().map_or_else(
831 || {
832 self.skip_to_item_end();
833 TemplateBodyDecl::Other {
834 raw: self.slice_text(start),
835 span: self.node_span(start),
836 pos,
837 }
838 },
839 TemplateBodyDecl::InterfaceInstance,
840 ),
841 Some("controller") => {
842 self.diag_cat(
846 DiagnosticCategory::UnsupportedSyntax,
847 "legacy 'controller ... can' syntax is not supported; \
848 choices inside this block are not analyzed",
849 );
850 self.skip_to_item_end();
851 TemplateBodyDecl::Other {
852 raw: self.slice_text(start),
853 span: self.node_span(start),
854 pos,
855 }
856 }
857 _ => {
858 self.skip_to_item_end();
859 TemplateBodyDecl::Other {
860 raw: self.slice_text(start),
861 span: self.node_span(start),
862 pos,
863 }
864 }
865 }
866 }
867
868 fn choice_decl(&mut self) -> Option<ChoiceDecl> {
869 let pos = self.pos();
870 let start_i = self.i;
871 let consuming = match self.peek().and_then(|t| t.keyword()) {
872 Some("nonconsuming") => {
873 self.bump();
874 Consuming::NonConsuming
875 }
876 Some("preconsuming") => {
877 self.bump();
878 Consuming::PreConsuming
879 }
880 Some("postconsuming") => {
881 self.bump();
882 Consuming::PostConsuming
883 }
884 _ => Consuming::Consuming,
885 };
886 if !self.eat_keyword("choice") {
887 return None;
888 }
889 let name = self.upper_name()?;
890 let return_ty = if self.eat_op(":") {
891 let ty_start = self.i;
892 self.skip_type_tokens();
893 parse_type_from_tokens(&self.toks[ty_start..self.i])
894 } else {
895 None
896 };
897 let mut params = Vec::new();
898 let mut dangling = false;
899 if self.eat_keyword("with") {
900 (params, dangling) = self.field_block();
901 }
902 let mut observers = Vec::new();
903 let mut controllers = Vec::new();
904 loop {
905 if dangling {
909 while self.eat(&Tok::VSemi) {}
910 }
911 if self.eat_keyword("observer") {
912 observers = self.expr_comma_list_no_do();
913 } else if self.eat_keyword("controller") {
914 controllers = self.expr_comma_list_no_do();
915 } else {
916 break;
917 }
918 }
919 if dangling {
920 while self.eat(&Tok::VSemi) {}
921 }
922 let body = if self
923 .peek()
924 .is_some_and(|t| !matches!(t, Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace))
925 {
926 Some(self.expr())
927 } else {
928 None
929 };
930 self.skip_to_item_end();
931 if dangling {
932 self.eat(&Tok::VRBrace);
935 self.skip_to_item_end();
936 }
937 Some(ChoiceDecl {
938 name,
939 consuming,
940 return_ty,
941 params,
942 controllers,
943 observers,
944 body,
945 pos,
946 span: self.node_span(start_i),
947 })
948 }
949
950 fn skip_type_tokens(&mut self) {
953 let mut brackets = 0usize;
954 while let Some(t) = self.peek() {
955 match t {
956 Tok::VSemi | Tok::VRBrace | Tok::VLBrace | Tok::Semi => return,
957 Tok::LParen | Tok::LBracket => brackets += 1,
958 Tok::RParen | Tok::RBracket => {
959 if brackets == 0 {
960 return;
961 }
962 brackets -= 1;
963 }
964 _ if brackets == 0
965 && matches!(
966 t.keyword(),
967 Some("with" | "controller" | "observer" | "do" | "where")
968 ) =>
969 {
970 return
971 }
972 _ => {}
973 }
974 self.i += 1;
975 }
976 }
977
978 fn interface_decl(&mut self) -> Option<InterfaceDecl> {
981 let pos = self.pos();
982 let start_i = self.i;
983 self.bump(); if self.at_keyword("instance") {
985 return None;
987 }
988 let name = self.upper_name()?;
989 let mut requires = Vec::new();
990 if self.eat_keyword("requires") {
991 while let Some(r) = self.upper_name() {
992 requires.push(r);
993 if !self.eat(&Tok::Comma) {
994 break;
995 }
996 }
997 }
998 if !self.eat_keyword("where") {
999 return None;
1000 }
1001 let mut viewtype = None;
1002 let mut methods = Vec::new();
1003 let mut choices = Vec::new();
1004 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1005 return Some(InterfaceDecl {
1006 name,
1007 requires,
1008 viewtype,
1009 methods,
1010 choices,
1011 pos,
1012 span: self.node_span(start_i),
1013 });
1014 }
1015 loop {
1016 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1017 match self.peek() {
1018 None => break,
1019 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
1020 self.bump();
1021 break;
1022 }
1023 Some(Tok::RParen) | Some(Tok::RBracket) => {
1028 self.bump();
1029 continue;
1030 }
1031 _ => {}
1032 }
1033 match self.peek().and_then(|t| t.keyword()) {
1034 Some("viewtype") => {
1035 self.bump();
1036 viewtype = self.upper_name();
1037 self.skip_to_item_end();
1038 }
1039 Some("choice")
1040 | Some("nonconsuming")
1041 | Some("preconsuming")
1042 | Some("postconsuming") => {
1043 if let Some(c) = self.choice_decl() {
1044 choices.push(c);
1045 } else {
1046 self.skip_to_item_end();
1047 }
1048 }
1049 _ => {
1050 let mpos = self.pos();
1053 if let Some(Tok::LowerId {
1054 qualifier: None,
1055 name: mname,
1056 }) = self.peek().cloned()
1057 {
1058 if self.peek_at(1).is_some_and(|t| t.is_op(":")) {
1059 let mstart = self.toks[self.i].start;
1060 self.bump();
1061 self.bump();
1062 let ty_start = self.i;
1063 self.skip_to_item_end();
1064 methods.push(FieldDecl {
1066 name: mname,
1067 ty: parse_type_from_tokens(&self.toks[ty_start..self.i]),
1068 pos: mpos,
1069 span: Span::new(mstart, self.end_byte().max(mstart)),
1070 });
1071 continue;
1072 }
1073 }
1074 self.skip_to_item_end();
1075 }
1076 }
1077 }
1078 Some(InterfaceDecl {
1079 name,
1080 requires,
1081 viewtype,
1082 methods,
1083 choices,
1084 pos,
1085 span: self.node_span(start_i),
1086 })
1087 }
1088
1089 fn interface_instance_decl(&mut self) -> Option<InterfaceInstanceDecl> {
1091 let pos = self.pos();
1092 let start_i = self.i;
1093 self.bump(); if !self.eat_keyword("instance") {
1095 return None;
1096 }
1097 let interface_name = self.upper_name()?;
1098 let for_template = if self.eat_keyword("for") {
1099 self.upper_name().unwrap_or_default()
1100 } else {
1101 String::new()
1102 };
1103 let mut methods = Vec::new();
1104 if self.eat_keyword("where") && (self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1105 loop {
1106 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1107 match self.peek() {
1108 None => break,
1109 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
1110 self.bump();
1111 break;
1112 }
1113 Some(Tok::RParen) | Some(Tok::RBracket) => {
1115 self.bump();
1116 continue;
1117 }
1118 _ => {}
1119 }
1120 if let Some(b) = self.binding() {
1121 methods.push(b);
1122 } else {
1123 self.skip_to_item_end();
1124 }
1125 }
1126 }
1127 Some(InterfaceInstanceDecl {
1128 interface_name,
1129 for_template,
1130 methods,
1131 pos,
1132 span: self.node_span(start_i),
1133 })
1134 }
1135
1136 fn function_item(&mut self) -> Option<Decl> {
1142 let pos = self.pos();
1143 let start_i = self.i;
1144 let name = match self.peek().cloned() {
1145 Some(Tok::LowerId {
1146 qualifier: None,
1147 name,
1148 }) => name,
1149 _ => return None,
1150 };
1151
1152 let mut j = self.i + 1;
1154 let mut is_sig = false;
1155 loop {
1156 match self.toks.get(j).map(|t| &t.tok) {
1157 Some(Tok::Comma) => {
1158 j += 1;
1159 if matches!(
1160 self.toks.get(j).map(|t| &t.tok),
1161 Some(Tok::LowerId {
1162 qualifier: None,
1163 ..
1164 })
1165 ) {
1166 j += 1;
1167 continue;
1168 }
1169 break;
1170 }
1171 Some(Tok::Op(o)) if o == ":" => {
1172 is_sig = true;
1173 break;
1174 }
1175 _ => break,
1176 }
1177 }
1178 if is_sig {
1179 self.bump(); while self.eat(&Tok::Comma) {
1181 self.bump(); }
1183 self.eat_op(":");
1184 let ty_start = self.i;
1185 self.skip_to_item_end();
1186 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
1187 return Some(Decl::Function(FunctionDecl {
1188 name,
1189 ty,
1190 equations: Vec::new(),
1191 pos,
1192 sig_span: Some(self.node_span(start_i)),
1193 span: self.node_span(start_i),
1194 }));
1195 }
1196
1197 self.bump(); let mut params = Vec::new();
1200 while !self.at_op("=") && !self.at_op("|") {
1201 if self.at_op(":") {
1204 self.bump();
1205 let mut brackets = 0usize;
1206 while let Some(t) = self.peek() {
1207 match t {
1208 Tok::Op(o) if o == "=" && brackets == 0 => break,
1209 Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace => break,
1210 Tok::LParen | Tok::LBracket => brackets += 1,
1211 Tok::RParen | Tok::RBracket => brackets = brackets.saturating_sub(1),
1212 _ => {}
1213 }
1214 self.i += 1;
1215 }
1216 continue;
1217 }
1218 if matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o)) {
1221 self.skip_to_item_end();
1222 return None;
1223 }
1224 match self.peek() {
1225 None | Some(Tok::VSemi) | Some(Tok::VRBrace) | Some(Tok::Semi)
1226 | Some(Tok::RBrace) => {
1227 self.diag(format!("could not parse equation for '{}'", name));
1228 return None;
1229 }
1230 _ => {}
1231 }
1232 match self.pattern_atom() {
1233 Some(p) => params.push(p),
1234 None => {
1235 self.diag(format!("bad parameter pattern in '{}'", name));
1236 return None;
1237 }
1238 }
1239 }
1240 let (body, guards) = self.equation_rhs()?;
1241 let where_bindings = if self.eat_keyword("where") {
1242 self.binding_block()
1243 } else {
1244 Vec::new()
1245 };
1246 self.skip_to_item_end();
1247 Some(Decl::Function(FunctionDecl {
1248 name,
1249 ty: None,
1250 equations: vec![Equation {
1251 params,
1252 body,
1253 guards,
1254 where_bindings,
1255 pos,
1256 span: self.node_span(start_i),
1257 }],
1258 pos,
1259 sig_span: None,
1260 span: self.node_span(start_i),
1261 }))
1262 }
1263
1264 fn equation_rhs(&mut self) -> Option<(Expr, Vec<(Expr, Expr)>)> {
1266 if self.eat_op("=") {
1267 return Some((self.expr(), Vec::new()));
1268 }
1269 let mut guards = Vec::new();
1270 while self.eat_op("|") {
1271 let g = loop {
1274 let g = self.expr();
1275 if self.eat_op("<-") {
1276 let _ = self.expr(); }
1278 if !self.eat(&Tok::Comma) {
1279 break g;
1280 }
1281 };
1282 if !self.eat_op("=") {
1283 self.diag("expected '=' after guard");
1284 return None;
1285 }
1286 let e = self.expr();
1287 guards.push((g, e));
1288 }
1289 let first = guards.first()?.1.clone();
1290 Some((first, guards))
1291 }
1292
1293 fn binding_block(&mut self) -> Vec<Binding> {
1295 let mut bindings = Vec::new();
1296 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1297 return bindings;
1298 }
1299 loop {
1300 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
1301 match self.peek() {
1302 None => break,
1303 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
1304 self.bump();
1305 break;
1306 }
1307 Some(Tok::RParen) | Some(Tok::RBracket) => {
1312 self.bump();
1313 continue;
1314 }
1315 _ => {}
1316 }
1317 match self.binding() {
1318 Some(b) => bindings.push(b),
1319 None => self.skip_to_item_end(),
1320 }
1321 }
1322 bindings
1323 }
1324
1325 fn binding(&mut self) -> Option<Binding> {
1328 let pos = self.pos();
1329 let start_i = self.i;
1330 if self.at(&Tok::LParen)
1333 && matches!(self.peek_at(1), Some(Tok::Op(_)))
1334 && self.peek_at(2) == Some(&Tok::RParen)
1335 {
1336 self.skip_to_item_end();
1337 return None;
1338 }
1339 let pat = self.pattern_atom()?;
1340 let mut params = Vec::new();
1341 loop {
1342 if self.at_op("=") {
1343 self.bump();
1344 let expr = self.expr();
1345 if self.eat_keyword("where") {
1347 let _ = self.binding_block();
1348 }
1349 return Some(Binding {
1350 pat,
1351 params,
1352 expr,
1353 pos,
1354 span: self.node_span(start_i),
1355 });
1356 }
1357 if self.at_op("|") {
1358 let (body, _) = self.equation_rhs()?;
1359 if self.eat_keyword("where") {
1360 let _ = self.binding_block();
1361 }
1362 return Some(Binding {
1363 pat,
1364 params,
1365 expr: body,
1366 pos,
1367 span: self.node_span(start_i),
1368 });
1369 }
1370 if self.at_op(":") {
1371 if params.is_empty() {
1372 self.skip_to_item_end();
1374 return None;
1375 }
1376 self.bump();
1379 let mut brackets = 0usize;
1380 while let Some(t) = self.peek() {
1381 match t {
1382 Tok::Op(o) if o == "=" && brackets == 0 => break,
1383 Tok::VSemi | Tok::VRBrace | Tok::Semi | Tok::RBrace => break,
1384 Tok::LParen | Tok::LBracket => brackets += 1,
1385 Tok::RParen | Tok::RBracket => brackets = brackets.saturating_sub(1),
1386 _ => {}
1387 }
1388 self.i += 1;
1389 }
1390 continue;
1391 }
1392 if matches!(self.peek(), Some(Tok::Op(o)) if !is_reserved_op(o)) {
1395 self.skip_to_item_end();
1396 return None;
1397 }
1398 match self.peek() {
1399 None | Some(Tok::VSemi) | Some(Tok::VRBrace) | Some(Tok::Semi)
1400 | Some(Tok::RBrace) => return None,
1401 _ => {}
1402 }
1403 params.push(self.pattern_atom()?);
1404 }
1405 }
1406
1407 fn pattern_atom(&mut self) -> Option<Pat> {
1410 if self.depth >= MAX_DEPTH {
1411 return None;
1412 }
1413 self.depth += 1;
1414 let result = self.pattern_atom_inner();
1415 self.depth -= 1;
1416 result
1417 }
1418
1419 fn pattern_atom_inner(&mut self) -> Option<Pat> {
1420 let pos = self.pos();
1421 let start_i = self.i;
1422 if self.at_op("~") || self.at_op("!") {
1424 self.bump();
1425 return self.pattern_atom();
1426 }
1427 match self.peek().cloned() {
1428 Some(Tok::LowerId {
1429 qualifier: None,
1430 name,
1431 }) => {
1432 self.bump();
1433 if name == "_" {
1434 return Some(Pat::Wild {
1435 pos,
1436 span: self.node_span(start_i),
1437 });
1438 }
1439 if self.at_op("@") {
1440 self.bump();
1441 let inner = self.pattern_atom()?;
1442 return Some(Pat::As {
1443 name,
1444 pat: Box::new(inner),
1445 pos,
1446 span: self.node_span(start_i),
1447 });
1448 }
1449 Some(Pat::Var {
1450 name,
1451 pos,
1452 span: self.node_span(start_i),
1453 })
1454 }
1455 Some(Tok::Op(o)) if o == "_" => {
1456 self.bump();
1457 Some(Pat::Wild {
1458 pos,
1459 span: self.node_span(start_i),
1460 })
1461 }
1462 Some(Tok::UpperId { qualifier, name }) => {
1463 self.bump();
1464 if self.at(&Tok::LBrace) {
1467 self.skip_balanced_braces();
1468 } else if self.eat_keyword("with") {
1469 let _ = self.record_fields();
1470 }
1471 Some(Pat::Con {
1472 qualifier,
1473 name,
1474 args: Vec::new(),
1475 pos,
1476 span: self.node_span(start_i),
1477 })
1478 }
1479 Some(Tok::IntLit(text)) => {
1480 self.bump();
1481 Some(Pat::Lit {
1482 kind: LitKind::Int,
1483 text,
1484 pos,
1485 span: self.node_span(start_i),
1486 })
1487 }
1488 Some(Tok::DecimalLit(text)) => {
1489 self.bump();
1490 Some(Pat::Lit {
1491 kind: LitKind::Decimal,
1492 text,
1493 pos,
1494 span: self.node_span(start_i),
1495 })
1496 }
1497 Some(Tok::StringLit(text)) => {
1498 self.bump();
1499 Some(Pat::Lit {
1500 kind: LitKind::Text,
1501 text,
1502 pos,
1503 span: self.node_span(start_i),
1504 })
1505 }
1506 Some(Tok::CharLit(text)) => {
1507 self.bump();
1508 Some(Pat::Lit {
1509 kind: LitKind::Char,
1510 text,
1511 pos,
1512 span: self.node_span(start_i),
1513 })
1514 }
1515 Some(Tok::LParen) => {
1516 self.bump();
1517 if self.eat(&Tok::RParen) {
1518 return Some(Pat::Con {
1519 qualifier: None,
1520 name: "()".to_string(),
1521 args: Vec::new(),
1522 pos,
1523 span: self.node_span(start_i),
1524 });
1525 }
1526 {
1532 let mut depth = 0usize;
1533 let mut j = self.i;
1534 let mut arrow = None;
1535 while let Some(t) = self.toks.get(j).map(|t| &t.tok) {
1536 match t {
1537 Tok::LParen | Tok::LBracket => depth += 1,
1538 Tok::RParen | Tok::RBracket => {
1539 if depth == 0 {
1540 break;
1541 }
1542 depth -= 1;
1543 }
1544 Tok::Op(o) if o == ":" && depth == 0 => break,
1545 Tok::Op(o) if o == "->" && depth == 0 => {
1546 arrow = Some(j);
1547 break;
1548 }
1549 Tok::VSemi | Tok::VRBrace => break,
1550 Tok::Op(o) if o == "\\" => break,
1552 _ => {}
1553 }
1554 j += 1;
1555 }
1556 if let Some(j) = arrow {
1557 self.i = j + 1; let inner = self.pattern()?;
1559 self.eat(&Tok::RParen);
1560 return Some(inner);
1561 }
1562 }
1563 let first = self.pattern()?;
1564 if self.at_op(":") {
1566 let mut depth = 0usize;
1567 while let Some(t) = self.peek() {
1568 match t {
1569 Tok::LParen | Tok::LBracket => depth += 1,
1570 Tok::RParen if depth == 0 => break,
1571 Tok::RParen | Tok::RBracket => depth -= 1,
1572 Tok::VSemi | Tok::VRBrace => break,
1573 _ => {}
1574 }
1575 self.i += 1;
1576 }
1577 }
1578 if self.at(&Tok::Comma) {
1579 let mut items = vec![first];
1580 while self.eat(&Tok::Comma) {
1581 items.push(self.pattern()?);
1582 }
1583 self.eat(&Tok::RParen);
1584 return Some(Pat::Tuple {
1585 items,
1586 pos,
1587 span: self.node_span(start_i),
1588 });
1589 }
1590 self.eat(&Tok::RParen);
1591 Some(first)
1592 }
1593 Some(Tok::LBracket) => {
1594 self.bump();
1595 let mut items = Vec::new();
1596 if !self.eat(&Tok::RBracket) {
1597 loop {
1598 items.push(self.pattern()?);
1599 if !self.eat(&Tok::Comma) {
1600 break;
1601 }
1602 }
1603 self.eat(&Tok::RBracket);
1604 }
1605 Some(Pat::List {
1606 items,
1607 pos,
1608 span: self.node_span(start_i),
1609 })
1610 }
1611 _ => None,
1612 }
1613 }
1614
1615 fn pattern(&mut self) -> Option<Pat> {
1617 if self.depth >= MAX_DEPTH {
1618 return None;
1619 }
1620 self.depth += 1;
1621 let result = self.pattern_inner();
1622 self.depth -= 1;
1623 result
1624 }
1625
1626 fn pattern_inner(&mut self) -> Option<Pat> {
1627 let pos = self.pos();
1628 let start_i = self.i;
1629 let first = match self.peek().cloned() {
1630 Some(Tok::UpperId { qualifier, name }) => {
1631 self.bump();
1632 if self.at(&Tok::LBrace) || self.at_keyword("with") {
1633 if self.eat_keyword("with") {
1634 let _ = self.record_fields();
1635 } else {
1636 self.skip_balanced_braces();
1637 }
1638 Pat::Con {
1639 qualifier,
1640 name,
1641 args: Vec::new(),
1642 pos,
1643 span: self.node_span(start_i),
1644 }
1645 } else {
1646 let mut args = Vec::new();
1647 while let Some(a) = self.try_pattern_atom() {
1648 args.push(a);
1649 }
1650 Pat::Con {
1651 qualifier,
1652 name,
1653 args,
1654 pos,
1655 span: self.node_span(start_i),
1656 }
1657 }
1658 }
1659 _ => self.pattern_atom()?,
1660 };
1661 if self.at_op("::") {
1662 self.bump();
1663 let rest = self.pattern()?;
1664 return Some(Pat::Con {
1665 qualifier: None,
1666 name: "::".to_string(),
1667 args: vec![first, rest],
1668 pos,
1669 span: self.node_span(start_i),
1670 });
1671 }
1672 Some(first)
1673 }
1674
1675 fn try_pattern_atom(&mut self) -> Option<Pat> {
1676 match self.peek() {
1677 Some(Tok::LowerId {
1678 qualifier: None, ..
1679 })
1680 | Some(Tok::UpperId { .. })
1681 | Some(Tok::IntLit(_))
1682 | Some(Tok::DecimalLit(_))
1683 | Some(Tok::StringLit(_))
1684 | Some(Tok::CharLit(_))
1685 | Some(Tok::LParen)
1686 | Some(Tok::LBracket) => self.pattern_atom(),
1687 _ => None,
1688 }
1689 }
1690
1691 fn skip_balanced_braces(&mut self) {
1692 let mut depth = 0usize;
1693 while let Some(t) = self.peek() {
1694 match t {
1695 Tok::LBrace => depth += 1,
1696 Tok::RBrace => {
1697 depth -= 1;
1698 if depth == 0 {
1699 self.i += 1;
1700 return;
1701 }
1702 }
1703 _ => {}
1704 }
1705 self.i += 1;
1706 }
1707 }
1708
1709 fn expr(&mut self) -> Expr {
1712 self.expr_prec(0, true)
1713 }
1714
1715 fn expr_no_do(&mut self) -> Expr {
1716 self.expr_prec(0, false)
1717 }
1718
1719 fn expr_comma_list(&mut self) -> Vec<Expr> {
1721 let mut out = vec![self.expr()];
1722 while self.eat(&Tok::Comma) {
1723 out.push(self.expr());
1724 }
1725 out
1726 }
1727
1728 fn expr_comma_list_no_do(&mut self) -> Vec<Expr> {
1729 let mut out = vec![self.expr_no_do()];
1730 while self.eat(&Tok::Comma) {
1731 out.push(self.expr_no_do());
1732 }
1733 out
1734 }
1735
1736 fn expr_prec(&mut self, min_prec: u8, allow_do: bool) -> Expr {
1737 let pos = self.pos();
1738 let start_i = self.i;
1739 if self.depth >= MAX_DEPTH {
1740 self.diag_cat(
1745 DiagnosticCategory::RecursionLimit,
1746 "expression nesting too deep; truncated to raw text",
1747 );
1748 let start = self.i;
1749 self.skip_to_item_end();
1750 if self.i == start {
1751 self.bump();
1752 }
1753 return Expr::Error {
1754 raw: self.slice_text(start),
1755 span: self.node_span(start),
1756 pos,
1757 };
1758 }
1759 self.depth += 1;
1760 let result = self.expr_prec_inner(min_prec, allow_do, pos, start_i);
1761 self.depth -= 1;
1762 result
1763 }
1764
1765 fn expr_prec_inner(&mut self, min_prec: u8, allow_do: bool, pos: Pos, start_i: usize) -> Expr {
1766 let mut lhs = match self.unary(allow_do) {
1767 Some(e) => e,
1768 None => {
1769 let start = self.i;
1771 self.skip_to_item_end();
1772 if self.i == start {
1773 self.bump();
1774 }
1775 return Expr::Error {
1776 raw: self.slice_text(start),
1777 span: self.node_span(start),
1778 pos,
1779 };
1780 }
1781 };
1782 loop {
1783 let (op, prec, right_assoc) = match self.peek() {
1784 Some(Tok::Op(o)) => {
1785 let o = o.clone();
1786 if is_reserved_op(&o) {
1787 if o == ":" {
1789 self.bump();
1790 self.skip_type_tokens();
1791 continue;
1792 }
1793 break;
1794 }
1795 let (p, r) = fixity(&o);
1796 (o, p, r)
1797 }
1798 Some(Tok::Backtick) => {
1799 let name = match self.peek_at(1) {
1801 Some(Tok::LowerId { qualifier, name })
1802 | Some(Tok::UpperId { qualifier, name }) => qualifier
1803 .as_ref()
1804 .map_or_else(|| name.clone(), |q| format!("{}.{}", q, name)),
1805 _ => break,
1806 };
1807 if self.peek_at(2) != Some(&Tok::Backtick) {
1808 break;
1809 }
1810 (format!("`{}`", name), 9, false)
1811 }
1812 _ => break,
1813 };
1814 if prec < min_prec {
1815 break;
1816 }
1817 self.bump();
1818 if op.starts_with('`') {
1819 self.bump();
1820 self.bump();
1821 }
1822 let next_min = if right_assoc { prec } else { prec + 1 };
1823 let rhs = self.expr_prec(next_min, allow_do);
1824 lhs = Expr::BinOp {
1825 op,
1826 lhs: Box::new(lhs),
1827 rhs: Box::new(rhs),
1828 pos,
1829 span: self.node_span(start_i),
1830 };
1831 }
1832 lhs
1833 }
1834
1835 fn unary(&mut self, allow_do: bool) -> Option<Expr> {
1836 let pos = self.pos();
1837 let start_i = self.i;
1838 if self.at_op("-") {
1839 self.bump();
1840 let e = self.unary(allow_do)?;
1841 return Some(Expr::Neg {
1842 expr: Box::new(e),
1843 pos,
1844 span: self.node_span(start_i),
1845 });
1846 }
1847 self.application(allow_do)
1848 }
1849
1850 fn application(&mut self, allow_do: bool) -> Option<Expr> {
1851 let pos = self.pos();
1852 let start_i = self.i;
1853 let head0 = self.atom(allow_do)?;
1854 let mut head = self.projection_tail(head0);
1855 let mut args = Vec::new();
1856 loop {
1857 if self.at_keyword("with") {
1860 let target = args.pop().unwrap_or_else(|| {
1861 std::mem::replace(
1862 &mut head,
1863 Expr::Error {
1864 raw: String::new(),
1865 pos,
1866 span: Span::default(),
1867 },
1868 )
1869 });
1870 self.bump(); let fields = self.record_fields();
1872 let tpos = target.pos();
1873 let sp = Span::new(target.span().start, self.end_byte());
1874 let rec = Expr::Record {
1875 base: Box::new(target),
1876 fields,
1877 pos: tpos,
1878 span: sp,
1879 };
1880 if matches!(head, Expr::Error { ref raw, .. } if raw.is_empty()) {
1881 head = rec;
1882 } else {
1883 args.push(rec);
1884 }
1885 continue;
1886 }
1887 if !allow_do && self.at_keyword("do") {
1888 break;
1889 }
1890 if self.at_op("@") {
1892 self.bump();
1893 match self.peek() {
1894 Some(Tok::UpperId { .. }) | Some(Tok::LowerId { .. }) => {
1895 self.bump();
1896 }
1897 Some(Tok::LParen) => self.skip_balanced_parens(),
1898 Some(Tok::LBracket) => {
1899 let mut depth = 0usize;
1900 while let Some(t) = self.peek() {
1901 match t {
1902 Tok::LBracket => depth += 1,
1903 Tok::RBracket => {
1904 depth -= 1;
1905 if depth == 0 {
1906 self.i += 1;
1907 break;
1908 }
1909 }
1910 _ => {}
1911 }
1912 self.i += 1;
1913 }
1914 }
1915 _ => {}
1916 }
1917 continue;
1918 }
1919 match self.try_atom(allow_do) {
1920 Some(a) => args.push(self.projection_tail(a)),
1921 None => break,
1922 }
1923 }
1924 if args.is_empty() {
1925 Some(head)
1926 } else {
1927 Some(Expr::App {
1928 func: Box::new(head),
1929 args,
1930 pos,
1931 span: self.node_span(start_i),
1932 })
1933 }
1934 }
1935
1936 fn record_fields(&mut self) -> Vec<FieldAssign> {
1938 let mut fields = Vec::new();
1939 let explicit = self.at(&Tok::LBrace);
1940 if !(self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace)) {
1941 return fields;
1942 }
1943 loop {
1944 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) || self.eat(&Tok::Comma) {}
1945 match self.peek() {
1946 None => break,
1947 Some(Tok::VRBrace) if !explicit => {
1948 self.bump();
1949 break;
1950 }
1951 Some(Tok::RBrace) => {
1952 self.bump();
1953 break;
1954 }
1955 Some(Tok::RParen) | Some(Tok::RBracket) => {
1957 self.bump();
1958 continue;
1959 }
1960 _ => {}
1961 }
1962 let pos = self.pos();
1963 let start_i = self.i;
1964 if self.at_op("..") {
1965 self.bump();
1966 fields.push(FieldAssign {
1967 name: "..".to_string(),
1968 value: None,
1969 pos,
1970 span: self.node_span(start_i),
1971 });
1972 continue;
1973 }
1974 let name = match self.peek().cloned() {
1975 Some(Tok::LowerId {
1976 qualifier: None,
1977 name,
1978 }) => {
1979 self.bump();
1980 name
1981 }
1982 _ => {
1983 self.skip_to_item_end();
1984 continue;
1985 }
1986 };
1987 if self.eat_op("=") {
1988 let value = self.expr_prec(1, true);
1989 fields.push(FieldAssign {
1990 name,
1991 value: Some(value),
1992 pos,
1993 span: self.node_span(start_i),
1994 });
1995 } else {
1996 fields.push(FieldAssign {
1998 name,
1999 value: None,
2000 pos,
2001 span: self.node_span(start_i),
2002 });
2003 }
2004 }
2005 fields
2006 }
2007
2008 fn try_atom(&mut self, allow_do: bool) -> Option<Expr> {
2009 match self.peek() {
2010 Some(Tok::LowerId { .. }) => {
2011 let kw = self.peek().and_then(|t| t.keyword());
2012 match kw {
2013 Some("do") if allow_do => self.atom(allow_do),
2015 Some(
2018 "if" | "case" | "do" | "let" | "try" | "where" | "then" | "else" | "of"
2019 | "in" | "controller" | "with" | "catch",
2020 ) => None,
2021 _ => self.atom(allow_do),
2022 }
2023 }
2024 Some(Tok::UpperId { .. })
2025 | Some(Tok::IntLit(_))
2026 | Some(Tok::DecimalLit(_))
2027 | Some(Tok::StringLit(_))
2028 | Some(Tok::CharLit(_))
2029 | Some(Tok::LParen)
2030 | Some(Tok::LBracket) => self.atom(allow_do),
2031 Some(Tok::Op(o)) if o == "\\" => self.atom(allow_do),
2033 _ => None,
2034 }
2035 }
2036
2037 fn projection_tail(&mut self, mut base: Expr) -> Expr {
2044 while self.at_tight_projection() {
2045 let start = base.span().start;
2046 let pos = base.pos();
2047 self.bump(); let field_tok = self.bump().expect("tight projection guarantees a field");
2049 let (qualifier, name) = match field_tok.tok {
2050 Tok::LowerId { qualifier, name } => (qualifier, name),
2051 other => unreachable!("at_tight_projection guarantees LowerId, got {other:?}"),
2052 };
2053 let field = Expr::Var {
2054 qualifier,
2055 name,
2056 pos: field_tok.pos,
2057 span: Span::new(field_tok.start, field_tok.end),
2058 };
2059 base = Expr::BinOp {
2060 op: ".".to_string(),
2061 lhs: Box::new(base),
2062 rhs: Box::new(field),
2063 pos,
2064 span: Span::new(start, self.end_byte()),
2065 };
2066 }
2067 base
2068 }
2069
2070 fn at_tight_projection(&self) -> bool {
2074 if self.i == 0 {
2075 return false;
2076 }
2077 let dot = match self.toks.get(self.i) {
2078 Some(t) => t,
2079 None => return false,
2080 };
2081 if !matches!(&dot.tok, Tok::Op(o) if o == ".") {
2082 return false;
2083 }
2084 let prev = &self.toks[self.i - 1];
2088 if prev.is_virtual() || prev.end != dot.start {
2089 return false;
2090 }
2091 self.toks.get(self.i + 1).is_some_and(|t| {
2093 matches!(
2094 &t.tok,
2095 Tok::LowerId {
2096 qualifier: None,
2097 ..
2098 }
2099 ) && t.start == dot.end
2100 })
2101 }
2102
2103 fn atom(&mut self, allow_do: bool) -> Option<Expr> {
2104 let pos = self.pos();
2105 let start_i = self.i;
2106 match self.peek().cloned() {
2107 Some(Tok::LowerId { qualifier, name }) => {
2108 match name.as_str() {
2109 "if" if qualifier.is_none() => return self.if_expr(),
2110 "case" if qualifier.is_none() => return self.case_expr(),
2111 "do" if qualifier.is_none() => {
2112 if !allow_do {
2113 return None;
2114 }
2115 return self.do_expr();
2116 }
2117 "let" if qualifier.is_none() => return self.let_expr(),
2118 "try" if qualifier.is_none() => return self.try_expr(),
2119 _ => {}
2120 }
2121 self.bump();
2122 Some(Expr::Var {
2123 qualifier,
2124 name,
2125 pos,
2126 span: self.node_span(start_i),
2127 })
2128 }
2129 Some(Tok::UpperId { qualifier, name }) => {
2130 self.bump();
2131 let base = Expr::Con {
2132 qualifier,
2133 name,
2134 pos,
2135 span: self.node_span(start_i),
2136 };
2137 if self.at(&Tok::LBrace) {
2139 let fields = self.record_fields();
2140 return Some(Expr::Record {
2141 base: Box::new(base),
2142 fields,
2143 pos,
2144 span: self.node_span(start_i),
2145 });
2146 }
2147 Some(base)
2148 }
2149 Some(Tok::IntLit(text)) => {
2150 self.bump();
2151 Some(Expr::Lit {
2152 kind: LitKind::Int,
2153 text,
2154 pos,
2155 span: self.node_span(start_i),
2156 })
2157 }
2158 Some(Tok::DecimalLit(text)) => {
2159 self.bump();
2160 Some(Expr::Lit {
2161 kind: LitKind::Decimal,
2162 text,
2163 pos,
2164 span: self.node_span(start_i),
2165 })
2166 }
2167 Some(Tok::StringLit(text)) => {
2168 self.bump();
2169 Some(Expr::Lit {
2170 kind: LitKind::Text,
2171 text,
2172 pos,
2173 span: self.node_span(start_i),
2174 })
2175 }
2176 Some(Tok::CharLit(text)) => {
2177 self.bump();
2178 Some(Expr::Lit {
2179 kind: LitKind::Char,
2180 text,
2181 pos,
2182 span: self.node_span(start_i),
2183 })
2184 }
2185 Some(Tok::Op(o)) if o == "\\" => self.lambda_expr(),
2186 Some(Tok::LParen) => self.paren_expr(),
2187 Some(Tok::LBracket) => self.list_expr(),
2188 _ => None,
2189 }
2190 }
2191
2192 fn if_expr(&mut self) -> Option<Expr> {
2193 let pos = self.pos();
2194 let start_i = self.i;
2195 self.bump(); let cond = self.expr();
2197 self.eat(&Tok::VSemi); if !self.eat_keyword("then") {
2199 self.diag("expected 'then'");
2200 return Some(Expr::Error {
2201 raw: format!("if {}", cond.render()),
2202 pos,
2203 span: self.node_span(start_i),
2204 });
2205 }
2206 let then_branch = self.expr();
2207 self.eat(&Tok::VSemi);
2208 if !self.eat_keyword("else") {
2209 self.diag("expected 'else'");
2210 return Some(Expr::Error {
2211 raw: format!("if {} then {}", cond.render(), then_branch.render()),
2212 pos,
2213 span: self.node_span(start_i),
2214 });
2215 }
2216 let else_branch = self.expr();
2217 Some(Expr::If {
2218 cond: Box::new(cond),
2219 then_branch: Box::new(then_branch),
2220 else_branch: Box::new(else_branch),
2221 pos,
2222 span: self.node_span(start_i),
2223 })
2224 }
2225
2226 fn case_expr(&mut self) -> Option<Expr> {
2227 let pos = self.pos();
2228 let start_i = self.i;
2229 self.bump(); let scrutinee = self.expr_no_do();
2231 if !self.eat_keyword("of") {
2232 self.diag("expected 'of' in case expression");
2233 return Some(Expr::Error {
2234 raw: format!("case {}", scrutinee.render()),
2235 pos,
2236 span: self.node_span(start_i),
2237 });
2238 }
2239 let mut alts = Vec::new();
2240 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2241 loop {
2242 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2243 match self.peek() {
2244 None => break,
2245 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
2246 self.bump();
2247 break;
2248 }
2249 Some(Tok::RParen) | Some(Tok::RBracket) => {
2251 self.bump();
2252 continue;
2253 }
2254 _ => {}
2255 }
2256 if self.eat_keyword("where") {
2258 let _ = self.binding_block();
2259 continue;
2260 }
2261 match self.case_alt() {
2262 Some(a) => alts.push(a),
2263 None => self.skip_to_item_end(),
2264 }
2265 }
2266 }
2267 Some(Expr::Case {
2268 scrutinee: Box::new(scrutinee),
2269 alts,
2270 pos,
2271 span: self.node_span(start_i),
2272 })
2273 }
2274
2275 fn case_alt(&mut self) -> Option<Alt> {
2276 let pos = self.pos();
2277 let start_i = self.i;
2278 let pat = self.pattern()?;
2279 if self.at_op("|") {
2280 let mut first: Option<Expr> = None;
2284 while self.eat_op("|") {
2285 loop {
2286 let _guard = self.expr();
2287 if self.eat_op("<-") {
2288 let _ = self.expr();
2289 }
2290 if !self.eat(&Tok::Comma) {
2291 break;
2292 }
2293 }
2294 if !self.eat_op("->") {
2295 self.diag("expected '->' in guarded case alternative");
2296 return None;
2297 }
2298 let body = self.expr();
2299 if first.is_none() {
2300 first = Some(body);
2301 }
2302 }
2303 return Some(Alt {
2304 pat,
2305 body: first?,
2306 pos,
2307 span: self.node_span(start_i),
2308 });
2309 }
2310 if !self.eat_op("->") {
2311 self.diag("expected '->' in case alternative");
2312 return None;
2313 }
2314 let body = self.expr();
2315 Some(Alt {
2316 pat,
2317 body,
2318 pos,
2319 span: self.node_span(start_i),
2320 })
2321 }
2322
2323 fn do_expr(&mut self) -> Option<Expr> {
2324 let pos = self.pos();
2325 let start_i = self.i;
2326 self.bump(); let mut stmts = Vec::new();
2328 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2329 loop {
2330 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2331 match self.peek() {
2332 None => break,
2333 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
2334 self.bump();
2335 break;
2336 }
2337 Some(Tok::RParen) | Some(Tok::RBracket) => {
2339 self.bump();
2340 continue;
2341 }
2342 _ => {}
2343 }
2344 stmts.push(self.do_stmt());
2345 }
2346 }
2347 Some(Expr::Do {
2348 stmts,
2349 pos,
2350 span: self.node_span(start_i),
2351 })
2352 }
2353
2354 fn do_stmt(&mut self) -> DoStmt {
2355 let pos = self.pos();
2356 let start_i = self.i;
2357 if self.at_keyword("let") {
2358 self.bump();
2359 let bindings = self.binding_block();
2360 if self.eat_keyword("in") {
2362 let body = self.expr();
2363 return DoStmt::Expr {
2364 expr: Expr::LetIn {
2365 bindings,
2366 body: Box::new(body),
2367 pos,
2368 span: self.node_span(start_i),
2369 },
2370 pos,
2371 span: self.node_span(start_i),
2372 };
2373 }
2374 return DoStmt::Let {
2375 bindings,
2376 pos,
2377 span: self.node_span(start_i),
2378 };
2379 }
2380 let snapshot = self.i;
2382 if let Some(pat) = self.try_bind_pattern() {
2383 if self.at_op("<-") {
2384 self.bump();
2385 let expr = self.expr();
2386 return DoStmt::Bind {
2387 pat,
2388 expr,
2389 pos,
2390 span: self.node_span(start_i),
2391 };
2392 }
2393 }
2394 self.i = snapshot;
2395 let expr = self.expr();
2396 DoStmt::Expr {
2397 expr,
2398 pos,
2399 span: self.node_span(start_i),
2400 }
2401 }
2402
2403 fn try_bind_pattern(&mut self) -> Option<Pat> {
2406 self.pattern()
2407 }
2408
2409 fn let_expr(&mut self) -> Option<Expr> {
2410 let pos = self.pos();
2411 let start_i = self.i;
2412 self.bump(); let bindings = self.binding_block();
2414 if self.eat_keyword("in") {
2415 let body = self.expr();
2416 return Some(Expr::LetIn {
2417 bindings,
2418 body: Box::new(body),
2419 pos,
2420 span: self.node_span(start_i),
2421 });
2422 }
2423 Some(Expr::LetIn {
2425 bindings,
2426 body: Box::new(Expr::Error {
2427 raw: String::new(),
2428 pos,
2429 span: self.node_span(start_i),
2430 }),
2431 pos,
2432 span: self.node_span(start_i),
2433 })
2434 }
2435
2436 fn try_expr(&mut self) -> Option<Expr> {
2437 let pos = self.pos();
2438 let start_i = self.i;
2439 self.bump(); let body = self.expr();
2441 let mut handlers = Vec::new();
2442 self.eat(&Tok::VSemi);
2443 if self.eat_keyword("catch") {
2444 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2445 loop {
2446 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2447 match self.peek() {
2448 None => break,
2449 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
2450 self.bump();
2451 break;
2452 }
2453 Some(Tok::RParen) | Some(Tok::RBracket) => {
2455 self.bump();
2456 continue;
2457 }
2458 _ => {}
2459 }
2460 match self.case_alt() {
2461 Some(a) => handlers.push(a),
2462 None => self.skip_to_item_end(),
2463 }
2464 }
2465 } else if let Some(a) = self.case_alt() {
2466 handlers.push(a);
2468 }
2469 }
2470 Some(Expr::Try {
2471 body: Box::new(body),
2472 handlers,
2473 pos,
2474 span: self.node_span(start_i),
2475 })
2476 }
2477
2478 fn lambda_expr(&mut self) -> Option<Expr> {
2479 let pos = self.pos();
2480 let start_i = self.i;
2481 self.bump(); if self.eat_keyword("case") {
2484 let mut alts = Vec::new();
2485 if self.eat(&Tok::VLBrace) || self.eat(&Tok::LBrace) {
2486 loop {
2487 while self.eat(&Tok::VSemi) || self.eat(&Tok::Semi) {}
2488 match self.peek() {
2489 None => break,
2490 Some(Tok::VRBrace) | Some(Tok::RBrace) => {
2491 self.bump();
2492 break;
2493 }
2494 Some(Tok::RParen) | Some(Tok::RBracket) => {
2495 self.bump();
2496 continue;
2497 }
2498 _ => {}
2499 }
2500 match self.case_alt() {
2501 Some(a) => alts.push(a),
2502 None => self.skip_to_item_end(),
2503 }
2504 }
2505 }
2506 return Some(Expr::Lambda {
2507 params: vec![Pat::Var {
2508 name: "_".to_string(),
2509 pos,
2510 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2511 }],
2512 body: Box::new(Expr::Case {
2513 scrutinee: Box::new(Expr::Var {
2514 qualifier: None,
2515 name: "_".to_string(),
2516 pos,
2517 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2518 }),
2519 alts,
2520 pos,
2521 span: self.node_span(start_i),
2522 }),
2523 pos,
2524 span: self.node_span(start_i),
2525 });
2526 }
2527 let mut params = Vec::new();
2528 while !self.at_op("->") {
2529 match self.pattern_atom() {
2530 Some(p) => params.push(p),
2531 None => {
2532 self.diag("bad lambda parameter");
2533 let start = self.i;
2534 self.skip_to_item_end();
2535 return Some(Expr::Error {
2536 raw: format!("\\{}", self.slice_text(start)),
2537 pos,
2538 span: self.node_span(start_i),
2539 });
2540 }
2541 }
2542 }
2543 self.bump(); let body = self.expr();
2545 Some(Expr::Lambda {
2546 params,
2547 body: Box::new(body),
2548 pos,
2549 span: self.node_span(start_i),
2550 })
2551 }
2552
2553 fn paren_expr(&mut self) -> Option<Expr> {
2554 let pos = self.pos();
2555 let start_i = self.i;
2556 self.bump(); if self.eat(&Tok::RParen) {
2558 return Some(Expr::Con {
2559 qualifier: None,
2560 name: "()".to_string(),
2561 pos,
2562 span: self.node_span(start_i),
2563 });
2564 }
2565 if let Some(Tok::Op(o)) = self.peek().cloned() {
2567 if !is_reserved_op(&o) && o != "\\" && o != "-" {
2568 self.bump();
2569 if self.eat(&Tok::RParen) {
2570 return Some(Expr::Section {
2571 op: o,
2572 operand: None,
2573 left: false,
2574 pos,
2575 span: self.node_span(start_i),
2576 });
2577 }
2578 let operand = self.expr();
2579 self.eat(&Tok::RParen);
2580 return Some(Expr::Section {
2581 op: o,
2582 operand: Some(Box::new(operand)),
2583 left: false,
2584 pos,
2585 span: self.node_span(start_i),
2586 });
2587 }
2588 }
2589 let first = self.expr();
2590 if self.at(&Tok::Comma) {
2591 let mut items = vec![first];
2592 while self.eat(&Tok::Comma) {
2593 items.push(self.expr());
2594 }
2595 self.eat(&Tok::RParen);
2596 return Some(Expr::Tuple {
2597 items,
2598 pos,
2599 span: self.node_span(start_i),
2600 });
2601 }
2602 if let Some(Tok::Op(o)) = self.peek().cloned() {
2604 if !is_reserved_op(&o) && self.peek_at(1) == Some(&Tok::RParen) {
2605 self.bump();
2606 self.bump();
2607 return Some(Expr::Section {
2608 op: o,
2609 operand: Some(Box::new(first)),
2610 left: true,
2611 pos,
2612 span: self.node_span(start_i),
2613 });
2614 }
2615 }
2616 self.eat(&Tok::RParen);
2617 Some(first)
2618 }
2619
2620 fn list_expr(&mut self) -> Option<Expr> {
2621 let pos = self.pos();
2622 let start_i = self.i;
2623 self.bump(); let mut items = Vec::new();
2625 if self.eat(&Tok::RBracket) {
2626 return Some(Expr::List {
2627 items,
2628 pos,
2629 span: self.node_span(start_i),
2630 });
2631 }
2632 loop {
2633 let e = self.expr();
2634 if self.at_op("..") {
2636 self.bump();
2637 let hi = if self.at(&Tok::RBracket) {
2638 Expr::Error {
2639 raw: String::new(),
2640 pos,
2641 span: self.node_span(start_i),
2642 }
2643 } else {
2644 self.expr()
2645 };
2646 self.eat(&Tok::RBracket);
2647 return Some(Expr::BinOp {
2648 op: "..".to_string(),
2649 lhs: Box::new(e),
2650 rhs: Box::new(hi),
2651 pos,
2652 span: self.node_span(start_i),
2653 });
2654 }
2655 if self.at_op("|") {
2657 let start = self.i;
2658 let mut brackets = 1usize;
2659 while let Some(t) = self.peek() {
2660 match t {
2661 Tok::LBracket => brackets += 1,
2662 Tok::RBracket => {
2663 brackets -= 1;
2664 if brackets == 0 {
2665 break;
2666 }
2667 }
2668 Tok::VSemi | Tok::VRBrace => break,
2669 _ => {}
2670 }
2671 self.i += 1;
2672 }
2673 let raw = self.slice_text(start);
2674 self.eat(&Tok::RBracket);
2675 return Some(Expr::App {
2676 func: Box::new(e),
2677 args: vec![Expr::Error {
2678 raw,
2679 pos,
2680 span: self.node_span(start_i),
2681 }],
2682 pos,
2683 span: self.node_span(start_i),
2684 });
2685 }
2686 items.push(e);
2687 if !self.eat(&Tok::Comma) {
2688 break;
2689 }
2690 }
2691 self.eat(&Tok::RBracket);
2692 Some(Expr::List {
2693 items,
2694 pos,
2695 span: self.node_span(start_i),
2696 })
2697 }
2698}
2699
2700fn is_reserved_op(op: &str) -> bool {
2703 matches!(op, "=" | "<-" | "->" | "|" | ":" | "=>" | "@" | "\\" | "..")
2704}
2705
2706fn fixity(op: &str) -> (u8, bool) {
2709 match op {
2710 "$" | "$!" => (1, true),
2711 ">>=" | ">>" | "=<<" | "<&>" => (2, false),
2712 "||" => (3, true),
2713 "&&" => (4, true),
2714 "==" | "/=" | "<" | "<=" | ">" | ">=" => (5, false),
2715 "::" | "++" | "<>" => (6, true),
2716 "+" | "-" => (7, false),
2717 "*" | "/" => (8, false),
2718 "^" | "**" => (9, true),
2719 "." | "!!" => (10, true),
2720 _ => (9, false),
2721 }
2722}
2723
2724fn equations_extent(eqs: &[Equation]) -> Option<Span> {
2729 let mut it = eqs.iter();
2730 let first = it.next()?;
2731 let mut s = first.span;
2732 for e in it {
2733 s.start = s.start.min(e.span.start);
2734 s.end = s.end.max(e.span.end);
2735 }
2736 Some(s)
2737}
2738
2739fn merge_functions(decls: &mut Vec<Decl>) {
2740 let mut out: Vec<Decl> = Vec::with_capacity(decls.len());
2741 for decl in decls.drain(..) {
2742 match decl {
2743 Decl::Function(f) => {
2744 let existing = out.iter_mut().find_map(|d| match d {
2745 Decl::Function(g) if g.name == f.name => Some(g),
2746 _ => None,
2747 });
2748 match existing {
2749 Some(g) => {
2750 if g.ty.is_none() {
2751 g.ty = f.ty.clone();
2752 }
2753 if g.sig_span.is_none() {
2754 g.sig_span = f.sig_span;
2755 }
2756 if g.equations.is_empty() && !f.equations.is_empty() {
2759 g.pos = f.pos;
2760 }
2761 g.equations.extend(f.equations);
2762 g.span = equations_extent(&g.equations)
2769 .or(g.sig_span)
2770 .unwrap_or(g.span);
2771 }
2772 None => out.push(Decl::Function(f)),
2773 }
2774 }
2775 other => out.push(other),
2776 }
2777 }
2778 *decls = out;
2779}
2780
2781pub(crate) fn parse_type_from_tokens(tokens: &[Token]) -> Option<Type> {
2790 let real_tokens: Vec<&Token> = tokens.iter().filter(|t| !t.is_virtual()).collect();
2793 if real_tokens.is_empty() {
2794 return None;
2795 }
2796 let mut parser = TypeTokenParser {
2797 tokens: &real_tokens,
2798 cursor: 0,
2799 };
2800 let ty = parser.parse_type()?;
2801 if parser.cursor == real_tokens.len() {
2804 Some(ty)
2805 } else {
2806 None
2807 }
2808}
2809
2810struct TypeTokenParser<'a> {
2811 tokens: &'a [&'a Token],
2812 cursor: usize,
2813}
2814
2815enum TypeAtom {
2818 ParsedType(Type),
2819 DroppedLiteral(Span),
2820}
2821
2822impl<'a> TypeTokenParser<'a> {
2823 fn peek(&self) -> Option<&'a Token> {
2824 self.tokens.get(self.cursor).copied()
2825 }
2826
2827 fn eat_op(&mut self, op: &str) -> bool {
2828 if self.peek().is_some_and(|t| t.tok.is_op(op)) {
2829 self.cursor += 1;
2830 true
2831 } else {
2832 false
2833 }
2834 }
2835
2836 fn parse_type(&mut self) -> Option<Type> {
2839 let lhs = self.parse_application_type()?;
2840 if self.eat_op("=>") {
2841 let body = self.parse_type()?;
2843 let span = Span::new(lhs.span().start, body.span().end);
2844 return Some(Type::Constrained(Box::new(body), span));
2845 }
2846 if self.eat_op("->") {
2847 let rhs = self.parse_type()?;
2848 let span = Span::new(lhs.span().start, rhs.span().end);
2849 return Some(Type::Fun(Box::new(lhs), Box::new(rhs), span));
2850 }
2851 Some(lhs)
2852 }
2853
2854 fn parse_application_type(&mut self) -> Option<Type> {
2856 let head = match self.parse_atom()? {
2857 TypeAtom::ParsedType(t) => t,
2858 TypeAtom::DroppedLiteral(_) => return None,
2860 };
2861 let mut args = Vec::new();
2862 let start = head.span().start;
2863 let mut end = head.span().end;
2864 loop {
2865 if !self.is_at_type_atom_start() {
2868 break;
2869 }
2870 match self.parse_atom()? {
2871 TypeAtom::ParsedType(t) => {
2872 end = t.span().end;
2873 args.push(t);
2874 }
2875 TypeAtom::DroppedLiteral(span) => {
2876 end = span.end;
2879 }
2880 }
2881 }
2882 let span = Span::new(start, end);
2883 if args.is_empty() {
2884 Some(head.with_span(span))
2885 } else {
2886 Some(Type::App(Box::new(head), args, span))
2887 }
2888 }
2889
2890 fn is_at_type_atom_start(&self) -> bool {
2893 matches!(
2894 self.peek().map(|t| &t.tok),
2895 Some(Tok::UpperId { .. })
2896 | Some(Tok::LowerId { .. })
2897 | Some(Tok::IntLit(_))
2898 | Some(Tok::DecimalLit(_))
2899 | Some(Tok::LBracket)
2900 | Some(Tok::LParen)
2901 )
2902 }
2903
2904 fn parse_atom(&mut self) -> Option<TypeAtom> {
2905 let tok = self.peek()?;
2906 match &tok.tok {
2907 Tok::UpperId { qualifier, name } => {
2908 let con = Type::Con {
2909 qualifier: qualifier.clone(),
2910 name: name.clone(),
2911 span: Span::new(tok.start, tok.end),
2912 };
2913 self.cursor += 1;
2914 Some(TypeAtom::ParsedType(con))
2915 }
2916 Tok::LowerId { name, .. } => {
2917 let var = Type::Var(name.clone(), Span::new(tok.start, tok.end));
2920 self.cursor += 1;
2921 Some(TypeAtom::ParsedType(var))
2922 }
2923 Tok::IntLit(_) | Tok::DecimalLit(_) => {
2924 self.cursor += 1;
2926 Some(TypeAtom::DroppedLiteral(Span::new(tok.start, tok.end)))
2927 }
2928 Tok::LBracket => {
2929 let start = tok.start;
2930 self.cursor += 1;
2931 let inner = self.parse_type()?;
2932 self.eat_token(Tok::RBracket).map(|end| {
2933 TypeAtom::ParsedType(Type::List(Box::new(inner), Span::new(start, end.end)))
2934 })
2935 }
2936 Tok::LParen => {
2937 let start = tok.start;
2938 self.cursor += 1;
2939 if let Some(end) = self.eat_token(Tok::RParen) {
2940 return Some(TypeAtom::ParsedType(Type::Unit(Span::new(start, end.end))));
2942 }
2943 let first = self.parse_type()?;
2944 if self.peek().map(|t| &t.tok) == Some(&Tok::Comma) {
2945 let mut items = vec![first];
2946 while self.eat_token(Tok::Comma).is_some() {
2947 items.push(self.parse_type()?);
2948 }
2949 self.eat_token(Tok::RParen).map(|end| {
2950 TypeAtom::ParsedType(Type::Tuple(items, Span::new(start, end.end)))
2951 })
2952 } else {
2953 self.eat_token(Tok::RParen).map(|end| {
2954 TypeAtom::ParsedType(first.with_span(Span::new(start, end.end)))
2956 })
2957 }
2958 }
2959 _ => None,
2960 }
2961 }
2962
2963 fn eat_token(&mut self, tok: Tok) -> Option<&'a Token> {
2964 if self.peek().is_some_and(|t| t.tok == tok) {
2965 let t = self.peek();
2966 self.cursor += 1;
2967 t
2968 } else {
2969 None
2970 }
2971 }
2972}
2973
2974fn render_token_slice(tokens: &[Token]) -> String {
2975 let mut s = String::new();
2976 let mut prev_no_space_after = true;
2977 for t in tokens {
2978 let (text, no_space_before, no_space_after): (String, bool, bool) = match &t.tok {
2979 Tok::LowerId { qualifier, name } | Tok::UpperId { qualifier, name } => (
2980 qualifier
2981 .as_ref()
2982 .map_or_else(|| name.clone(), |q| format!("{}.{}", q, name)),
2983 false,
2984 false,
2985 ),
2986 Tok::Op(o) => (o.clone(), false, false),
2987 Tok::IntLit(n) | Tok::DecimalLit(n) => (n.clone(), false, false),
2988 Tok::StringLit(v) => (format!("{:?}", v), false, false),
2989 Tok::CharLit(v) => (format!("'{}'", v), false, false),
2990 Tok::LParen => ("(".to_string(), false, true),
2991 Tok::RParen => (")".to_string(), true, false),
2992 Tok::LBracket => ("[".to_string(), false, true),
2993 Tok::RBracket => ("]".to_string(), true, false),
2994 Tok::LBrace => ("{".to_string(), false, true),
2995 Tok::RBrace => ("}".to_string(), true, false),
2996 Tok::Comma => (",".to_string(), true, false),
2997 Tok::Semi | Tok::VSemi => (";".to_string(), true, false),
2998 Tok::Backtick => ("`".to_string(), false, false),
2999 Tok::VLBrace | Tok::VRBrace => continue,
3000 };
3001 if !s.is_empty() && !no_space_before && !prev_no_space_after {
3002 s.push(' ');
3003 }
3004 s.push_str(&text);
3005 prev_no_space_after = no_space_after;
3006 }
3007 s
3008}
3009
3010#[cfg(test)]
3011mod type_tests {
3012 use super::*;
3013 use crate::lexer::lex;
3014
3015 fn ty(s: &str) -> Option<Type> {
3019 let (toks, errs) = lex(s);
3020 assert!(errs.is_empty(), "lex errors for {s:?}: {errs:?}");
3021 parse_type_from_tokens(&toks)
3022 }
3023
3024 fn con(name: &str) -> Type {
3025 Type::Con {
3026 qualifier: None,
3027 name: name.to_string(),
3028 span: Span::default(),
3029 }
3030 }
3031
3032 fn qualified_con(qualifier: &str, name: &str) -> Type {
3033 Type::Con {
3034 qualifier: Some(qualifier.to_string()),
3035 name: name.to_string(),
3036 span: Span::default(),
3037 }
3038 }
3039
3040 fn app(head: Type, args: Vec<Type>) -> Type {
3041 Type::App(Box::new(head), args, Span::default())
3042 }
3043
3044 fn list(inner: Type) -> Type {
3045 Type::List(Box::new(inner), Span::default())
3046 }
3047
3048 fn tuple(items: Vec<Type>) -> Type {
3049 Type::Tuple(items, Span::default())
3050 }
3051
3052 fn fun(param: Type, result: Type) -> Type {
3053 Type::Fun(Box::new(param), Box::new(result), Span::default())
3054 }
3055
3056 fn var(name: &str) -> Type {
3057 Type::Var(name.to_string(), Span::default())
3058 }
3059
3060 fn unit() -> Type {
3061 Type::Unit(Span::default())
3062 }
3063
3064 fn constrained(body: Type) -> Type {
3065 Type::Constrained(Box::new(body), Span::default())
3066 }
3067
3068 #[test]
3069 fn atoms() {
3070 assert_eq!(ty("Party"), Some(con("Party")));
3071 assert_eq!(ty("Decimal"), Some(con("Decimal")));
3072 assert_eq!(ty("a"), Some(var("a")));
3073 assert_eq!(ty("()"), Some(unit()));
3074 }
3075
3076 #[test]
3077 fn application_vs_constructor() {
3078 assert_eq!(
3081 ty("ContractId Foo"),
3082 Some(app(con("ContractId"), vec![con("Foo")]))
3083 );
3084 assert_eq!(
3085 ty("Optional (ContractId Foo)"),
3086 Some(app(
3087 con("Optional"),
3088 vec![app(con("ContractId"), vec![con("Foo")])]
3089 ))
3090 );
3091 assert_eq!(
3092 ty("Map Text Int"),
3093 Some(app(con("Map"), vec![con("Text"), con("Int")]))
3094 );
3095 }
3096
3097 #[test]
3098 fn qualified_constructor_keeps_qualifier() {
3099 assert_eq!(
3100 ty("DA.Map.Map Text Int"),
3101 Some(app(
3102 qualified_con("DA.Map", "Map"),
3103 vec![con("Text"), con("Int")]
3104 ))
3105 );
3106 }
3107
3108 #[test]
3109 fn list_and_tuple() {
3110 assert_eq!(ty("[Text]"), Some(list(con("Text"))));
3111 assert_eq!(
3112 ty("(Int, Text)"),
3113 Some(tuple(vec![con("Int"), con("Text")]))
3114 );
3115 assert_eq!(
3117 ty("(a, b, c)"),
3118 Some(tuple(vec![var("a"), var("b"), var("c")]))
3119 );
3120 assert_eq!(ty("(Text)"), Some(con("Text")));
3122 }
3123
3124 #[test]
3125 fn function_types_are_arrows_not_names() {
3126 assert_eq!(ty("Int -> Int"), Some(fun(con("Int"), con("Int"))));
3129 assert_eq!(
3131 ty("Int -> Text -> Bool"),
3132 Some(fun(con("Int"), fun(con("Text"), con("Bool"))))
3133 );
3134 assert_eq!(
3135 ty("Party -> Script ()"),
3136 Some(fun(con("Party"), app(con("Script"), vec![unit()])))
3137 );
3138 }
3139
3140 #[test]
3141 fn script_application() {
3142 assert_eq!(ty("Script ()"), Some(app(con("Script"), vec![unit()])));
3145 }
3146
3147 #[test]
3148 fn numeric_nat_literal_is_dropped() {
3149 assert_eq!(ty("Numeric 10"), Some(con("Numeric")));
3152 assert_eq!(ty("Numeric n"), Some(app(con("Numeric"), vec![var("n")])));
3153 }
3154
3155 #[test]
3156 fn constraint_context_is_dropped_body_kept() {
3157 assert_eq!(
3160 ty("NumericScale n => Numeric 37 -> Numeric n"),
3161 Some(constrained(fun(
3162 con("Numeric"),
3163 app(con("Numeric"), vec![var("n")])
3164 )))
3165 );
3166 assert_eq!(ty("(Eq a, Show a) => a"), Some(constrained(var("a"))));
3168 }
3169
3170 #[test]
3171 fn unparseable_is_none() {
3172 assert_eq!(ty("Int ->"), None);
3175 assert_eq!(ty("-> Int"), None);
3176 }
3177
3178 #[test]
3179 fn ty_is_populated_through_real_parse() {
3180 let src = r#"module M where
3183template T
3184 with
3185 owner : Party
3186 held : ContractId Asset
3187 where
3188 signatory owner
3189 choice Go : Optional (ContractId Asset)
3190 controller owner
3191 do
3192 pure None
3193"#;
3194 let (m, _) = parse_module(src);
3195 let t = match &m.decls[0] {
3196 Decl::Template(t) => t,
3197 other => panic!("expected template, got {other:?}"),
3198 };
3199 assert_eq!(t.fields[0].ty, Some(con("Party")));
3200 assert_eq!(
3201 t.fields[1].ty,
3202 Some(app(con("ContractId"), vec![con("Asset")]))
3203 );
3204 let choice = match &t
3205 .body
3206 .iter()
3207 .find(|d| matches!(d, TemplateBodyDecl::Choice(_)))
3208 {
3209 Some(TemplateBodyDecl::Choice(c)) => (*c).clone(),
3210 _ => panic!("expected choice"),
3211 };
3212 assert_eq!(
3213 choice.return_ty,
3214 Some(app(
3215 con("Optional"),
3216 vec![app(con("ContractId"), vec![con("Asset")])]
3217 ))
3218 );
3219 }
3220
3221 #[test]
3222 fn ty_is_populated_on_key_and_interface_method() {
3223 let src = r#"module M where
3226template T
3227 with
3228 owner : Party
3229 where
3230 signatory owner
3231 key owner : Party
3232 maintainer owner
3233
3234interface I where
3235 getAmount : Numeric 10
3236"#;
3237 let (m, _) = parse_module(src);
3238 let t = match &m.decls[0] {
3239 Decl::Template(t) => t,
3240 other => panic!("expected template, got {other:?}"),
3241 };
3242 let key_ty = t.body.iter().find_map(|d| match d {
3243 TemplateBodyDecl::Key { ty, .. } => Some(ty.clone()),
3244 _ => None,
3245 });
3246 assert_eq!(key_ty, Some(Some(con("Party"))));
3247
3248 let iface = match &m.decls[1] {
3249 Decl::Interface(i) => i,
3250 other => panic!("expected interface, got {other:?}"),
3251 };
3252 assert_eq!(iface.methods[0].ty, Some(con("Numeric")));
3254 }
3255}