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