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 qualified = self.eat_keyword("qualified");
566 if matches!(self.peek(), Some(TokenKind::StringLit(_))) {
568 self.bump();
569 }
570 let module_name = match self.peek().cloned() {
571 Some(TokenKind::UpperId { qualifier, name }) => {
572 self.bump();
573 match qualifier {
574 Some(q) => format!("{q}.{name}"),
575 None => name,
576 }
577 }
578 _ => {
579 self.diag("expected module name after 'import'");
580 return None;
581 }
582 };
583 if self.eat_keyword("qualified") {
585 qualified = true;
586 }
587 let mut alias = None;
588 if self.eat_keyword("as") {
589 if let Some(TokenKind::UpperId { qualifier, name }) = self.peek().cloned() {
590 self.bump();
591 alias = Some(match qualifier {
592 Some(q) => format!("{q}.{name}"),
593 None => name,
594 });
595 }
596 }
597 Some(ImportDecl {
599 module_name,
600 qualified,
601 alias,
602 pos,
603 span: self.node_span(start_i),
604 })
605 }
606
607 fn upper_name(&mut self) -> Option<String> {
610 match self.peek().cloned() {
611 Some(TokenKind::UpperId { qualifier, name }) => {
612 self.bump();
613 Some(match qualifier {
614 Some(q) => format!("{q}.{name}"),
615 None => name,
616 })
617 }
618 _ => None,
619 }
620 }
621
622 fn template_decl(&mut self) -> Option<TemplateDecl> {
623 let pos = self.pos();
624 let start_i = self.i;
625 self.bump(); if self.at_keyword("instance") {
627 return None; }
629 let name = self.upper_name()?;
630
631 let mut fields = Vec::new();
632 if self.eat_keyword("with") {
633 (fields, _) = self.field_block();
634 }
635 let body = if self.eat_keyword("where") {
636 self.template_body()
637 } else {
638 Vec::new()
639 };
640 Some(TemplateDecl {
641 name,
642 fields,
643 body,
644 pos,
645 span: self.node_span(start_i),
646 })
647 }
648
649 fn field_block(&mut self) -> (Vec<FieldDecl>, bool) {
655 let mut fields = Vec::new();
656 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
657 return (fields, false);
658 }
659 loop {
660 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
661 match self.peek() {
662 None => break,
663 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
664 self.bump();
665 break;
666 }
667 Some(TokenKind::RParen | TokenKind::RBracket) => {
672 self.bump();
673 continue;
674 }
675 _ => {}
676 }
677 {
682 let mut j = self.i;
683 while let Some(TokenKind::LowerId {
684 qualifier: None, ..
685 }) = self.toks.get(j).map(|t| &t.kind)
686 {
687 j += 1;
688 match self.toks.get(j).map(|t| &t.kind) {
689 Some(TokenKind::Comma) => j += 1,
690 _ => break,
691 }
692 }
693 let is_field = j > self.i
694 && self
695 .toks
696 .get(j)
697 .map(|t| &t.kind)
698 .is_some_and(|t| t.is_op(":"));
699 if !is_field {
700 return (fields, true);
701 }
702 }
703 let mut names: Vec<(String, Pos, Span)> = Vec::new();
705 while let Some(TokenKind::LowerId {
706 qualifier: None,
707 name,
708 }) = self.peek().cloned()
709 {
710 let p = self.pos();
711 let nspan = Span::new(self.toks[self.i].start, self.toks[self.i].end);
712 self.bump();
713 names.push((name, p, nspan));
714 if !self.eat(&TokenKind::Comma) {
715 break;
716 }
717 }
718 if names.is_empty() || !self.eat_op(":") {
719 self.diag("expected 'name : Type' field");
720 self.skip_to_item_end();
721 continue;
722 }
723 let ty_start = self.i;
724 self.skip_to_item_end();
725 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
726 let type_end = self.end_byte();
731 let last = names.len() - 1;
732 for (idx, (name, p, nspan)) in names.into_iter().enumerate() {
733 let span = if idx == last {
734 Span::new(nspan.start, type_end.max(nspan.end))
735 } else {
736 nspan
737 };
738 fields.push(FieldDecl {
739 name,
740 ty: ty.clone(),
741 pos: p,
742 span,
743 });
744 }
745 }
746 (fields, false)
747 }
748
749 fn template_body(&mut self) -> Vec<TemplateBodyDecl> {
752 let mut body = Vec::new();
753 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
754 return body;
755 }
756 loop {
757 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
758 match self.peek() {
759 None => break,
760 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
761 self.bump();
762 break;
763 }
764 Some(TokenKind::RParen | TokenKind::RBracket) => {
769 self.bump();
770 continue;
771 }
772 _ => {}
773 }
774 let pos = self.pos();
775 let start = self.i;
776 let decl = self.template_body_item(pos, start);
777 body.push(decl);
778 }
779 body
780 }
781
782 fn template_body_item(&mut self, pos: Pos, start: usize) -> TemplateBodyDecl {
783 match self.peek().and_then(|t| t.keyword()) {
784 Some("signatory") => {
785 self.bump();
786 let parties = self.expr_comma_list();
787 self.skip_to_item_end();
788 TemplateBodyDecl::Signatory {
789 parties,
790 pos,
791 span: self.node_span(start),
792 }
793 }
794 Some("observer") => {
795 self.bump();
796 let parties = self.expr_comma_list();
797 self.skip_to_item_end();
798 TemplateBodyDecl::Observer {
799 parties,
800 pos,
801 span: self.node_span(start),
802 }
803 }
804 Some("ensure") => {
805 self.bump();
806 let expr = self.expr();
807 self.skip_to_item_end();
808 TemplateBodyDecl::Ensure {
809 expr,
810 pos,
811 span: self.node_span(start),
812 }
813 }
814 Some("key") => {
815 self.bump();
816 let expr_start = self.i;
817 let expr = self.expr();
818 let ty = if self.eat_op(":") {
819 let ty_start = self.i;
820 self.skip_to_item_end();
821 parse_type_from_tokens(&self.toks[ty_start..self.i])
822 } else {
823 let mut depth = 0i32;
826 let mut colon = None;
827 for j in expr_start..self.i {
828 match &self.toks[j].kind {
829 TokenKind::LParen | TokenKind::LBracket => depth += 1,
830 TokenKind::RParen | TokenKind::RBracket if depth > 0 => depth -= 1,
831 TokenKind::Op(o) if o == ":" && depth == 0 => colon = Some(j),
832 _ => {}
833 }
834 }
835 let ty = colon.and_then(|j| parse_type_from_tokens(&self.toks[j + 1..self.i]));
836 self.skip_to_item_end();
837 ty
838 };
839 TemplateBodyDecl::Key {
840 expr,
841 ty,
842 pos,
843 span: self.node_span(start),
844 }
845 }
846 Some("maintainer") => {
847 self.bump();
848 let expr = self.expr();
849 self.skip_to_item_end();
850 TemplateBodyDecl::Maintainer {
851 expr,
852 pos,
853 span: self.node_span(start),
854 }
855 }
856 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
857 self.choice_decl().map_or_else(
858 || {
859 self.skip_to_item_end();
860 TemplateBodyDecl::Other {
861 raw: self.slice_text(start),
862 span: self.node_span(start),
863 pos,
864 }
865 },
866 TemplateBodyDecl::Choice,
867 )
868 }
869 Some("interface") => self.interface_instance_decl().map_or_else(
870 || {
871 self.skip_to_item_end();
872 TemplateBodyDecl::Other {
873 raw: self.slice_text(start),
874 span: self.node_span(start),
875 pos,
876 }
877 },
878 TemplateBodyDecl::InterfaceInstance,
879 ),
880 Some("controller") => {
881 self.diag_cat(
885 DiagnosticCategory::UnsupportedSyntax,
886 "legacy 'controller ... can' syntax is not supported; \
887 choices inside this block are not analyzed",
888 );
889 self.skip_to_item_end();
890 TemplateBodyDecl::Other {
891 raw: self.slice_text(start),
892 span: self.node_span(start),
893 pos,
894 }
895 }
896 _ => {
897 self.skip_to_item_end();
898 TemplateBodyDecl::Other {
899 raw: self.slice_text(start),
900 span: self.node_span(start),
901 pos,
902 }
903 }
904 }
905 }
906
907 fn choice_decl(&mut self) -> Option<ChoiceDecl> {
908 let pos = self.pos();
909 let start_i = self.i;
910 let consuming = match self.peek().and_then(|t| t.keyword()) {
911 Some("nonconsuming") => {
912 self.bump();
913 Consuming::NonConsuming
914 }
915 Some("preconsuming") => {
916 self.bump();
917 Consuming::PreConsuming
918 }
919 Some("postconsuming") => {
920 self.bump();
921 Consuming::PostConsuming
922 }
923 _ => Consuming::Consuming,
924 };
925 if !self.eat_keyword("choice") {
926 return None;
927 }
928 let name = self.upper_name()?;
929 let return_ty = if self.eat_op(":") {
930 let ty_start = self.i;
931 self.skip_type_tokens();
932 parse_type_from_tokens(&self.toks[ty_start..self.i])
933 } else {
934 None
935 };
936 let mut params = Vec::new();
937 let mut dangling = false;
938 if self.eat_keyword("with") {
939 (params, dangling) = self.field_block();
940 }
941 let mut observers = Vec::new();
942 let mut controllers = Vec::new();
943 loop {
944 if dangling {
948 while self.eat(&TokenKind::VSemi) {}
949 }
950 if self.eat_keyword("observer") {
951 observers = self.expr_comma_list_no_do();
952 } else if self.eat_keyword("controller") {
953 controllers = self.expr_comma_list_no_do();
954 } else {
955 break;
956 }
957 }
958 if dangling {
959 while self.eat(&TokenKind::VSemi) {}
960 }
961 let body = if self.peek().is_some_and(|t| {
962 !matches!(
963 t,
964 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace
965 )
966 }) {
967 Some(self.expr())
968 } else {
969 None
970 };
971 self.skip_to_item_end();
972 if dangling {
973 self.eat(&TokenKind::VRBrace);
976 self.skip_to_item_end();
977 }
978 Some(ChoiceDecl {
979 name,
980 consuming,
981 return_ty,
982 params,
983 controllers,
984 observers,
985 body,
986 pos,
987 span: self.node_span(start_i),
988 })
989 }
990
991 fn skip_type_tokens(&mut self) {
994 let mut brackets = 0usize;
995 while let Some(t) = self.peek() {
996 match t {
997 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::VLBrace | TokenKind::Semi => {
998 return
999 }
1000 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1001 TokenKind::RParen | TokenKind::RBracket => {
1002 if brackets == 0 {
1003 return;
1004 }
1005 brackets -= 1;
1006 }
1007 _ if brackets == 0
1008 && matches!(
1009 t.keyword(),
1010 Some("with" | "controller" | "observer" | "do" | "where")
1011 ) =>
1012 {
1013 return
1014 }
1015 _ => {}
1016 }
1017 self.i += 1;
1018 }
1019 }
1020
1021 fn interface_decl(&mut self) -> Option<InterfaceDecl> {
1024 let pos = self.pos();
1025 let start_i = self.i;
1026 self.bump(); if self.at_keyword("instance") {
1028 return None;
1030 }
1031 let name = self.upper_name()?;
1032 let mut requires = Vec::new();
1033 if self.eat_keyword("requires") {
1034 while let Some(r) = self.upper_name() {
1035 requires.push(r);
1036 if !self.eat(&TokenKind::Comma) {
1037 break;
1038 }
1039 }
1040 }
1041 if !self.eat_keyword("where") {
1042 return None;
1043 }
1044 let mut viewtype = None;
1045 let mut methods = Vec::new();
1046 let mut choices = Vec::new();
1047 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1048 return Some(InterfaceDecl {
1049 name,
1050 requires,
1051 viewtype,
1052 methods,
1053 choices,
1054 pos,
1055 span: self.node_span(start_i),
1056 });
1057 }
1058 loop {
1059 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1060 match self.peek() {
1061 None => break,
1062 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1063 self.bump();
1064 break;
1065 }
1066 Some(TokenKind::RParen | TokenKind::RBracket) => {
1071 self.bump();
1072 continue;
1073 }
1074 _ => {}
1075 }
1076 match self.peek().and_then(|t| t.keyword()) {
1077 Some("viewtype") => {
1078 self.bump();
1079 viewtype = self.upper_name();
1080 self.skip_to_item_end();
1081 }
1082 Some("choice" | "nonconsuming" | "preconsuming" | "postconsuming") => {
1083 if let Some(c) = self.choice_decl() {
1084 choices.push(c);
1085 } else {
1086 self.skip_to_item_end();
1087 }
1088 }
1089 _ => {
1090 let mpos = self.pos();
1093 if let Some(TokenKind::LowerId {
1094 qualifier: None,
1095 name: mname,
1096 }) = self.peek().cloned()
1097 {
1098 if self.peek_at(1).is_some_and(|t| t.is_op(":")) {
1099 let mstart = self.toks[self.i].start;
1100 self.bump();
1101 self.bump();
1102 let ty_start = self.i;
1103 self.skip_to_item_end();
1104 methods.push(FieldDecl {
1106 name: mname,
1107 ty: parse_type_from_tokens(&self.toks[ty_start..self.i]),
1108 pos: mpos,
1109 span: Span::new(mstart, self.end_byte().max(mstart)),
1110 });
1111 continue;
1112 }
1113 }
1114 self.skip_to_item_end();
1115 }
1116 }
1117 }
1118 Some(InterfaceDecl {
1119 name,
1120 requires,
1121 viewtype,
1122 methods,
1123 choices,
1124 pos,
1125 span: self.node_span(start_i),
1126 })
1127 }
1128
1129 fn interface_instance_decl(&mut self) -> Option<InterfaceInstanceDecl> {
1131 let pos = self.pos();
1132 let start_i = self.i;
1133 self.bump(); if !self.eat_keyword("instance") {
1135 return None;
1136 }
1137 let interface_name = self.upper_name()?;
1138 let for_template = if self.eat_keyword("for") {
1139 self.upper_name().unwrap_or_default()
1140 } else {
1141 String::new()
1142 };
1143 let mut methods = Vec::new();
1144 if self.eat_keyword("where")
1145 && (self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace))
1146 {
1147 loop {
1148 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1149 match self.peek() {
1150 None => break,
1151 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1152 self.bump();
1153 break;
1154 }
1155 Some(TokenKind::RParen | TokenKind::RBracket) => {
1157 self.bump();
1158 continue;
1159 }
1160 _ => {}
1161 }
1162 if let Some(b) = self.binding() {
1163 methods.push(b);
1164 } else {
1165 self.skip_to_item_end();
1166 }
1167 }
1168 }
1169 Some(InterfaceInstanceDecl {
1170 interface_name,
1171 for_template,
1172 methods,
1173 pos,
1174 span: self.node_span(start_i),
1175 })
1176 }
1177
1178 fn function_item(&mut self) -> Option<Decl> {
1184 let pos = self.pos();
1185 let start_i = self.i;
1186 let name = match self.peek().cloned() {
1187 Some(TokenKind::LowerId {
1188 qualifier: None,
1189 name,
1190 }) => name,
1191 _ => return None,
1192 };
1193
1194 let mut j = self.i + 1;
1196 let mut is_sig = false;
1197 loop {
1198 match self.toks.get(j).map(|t| &t.kind) {
1199 Some(TokenKind::Comma) => {
1200 j += 1;
1201 if matches!(
1202 self.toks.get(j).map(|t| &t.kind),
1203 Some(TokenKind::LowerId {
1204 qualifier: None,
1205 ..
1206 })
1207 ) {
1208 j += 1;
1209 continue;
1210 }
1211 break;
1212 }
1213 Some(TokenKind::Op(o)) if o == ":" => {
1214 is_sig = true;
1215 break;
1216 }
1217 _ => break,
1218 }
1219 }
1220 if is_sig {
1221 self.bump(); while self.eat(&TokenKind::Comma) {
1223 self.bump(); }
1225 self.eat_op(":");
1226 let ty_start = self.i;
1227 self.skip_to_item_end();
1228 let ty = parse_type_from_tokens(&self.toks[ty_start..self.i]);
1229 return Some(Decl::Function(FunctionDecl {
1230 name,
1231 ty,
1232 equations: Vec::new(),
1233 pos,
1234 sig_span: Some(self.node_span(start_i)),
1235 span: self.node_span(start_i),
1236 }));
1237 }
1238
1239 self.bump(); let mut params = Vec::new();
1242 while !self.at_op("=") && !self.at_op("|") {
1243 if self.at_op(":") {
1246 self.bump();
1247 let mut brackets = 0usize;
1248 while let Some(t) = self.peek() {
1249 match t {
1250 TokenKind::Op(o) if o == "=" && brackets == 0 => break,
1251 TokenKind::VSemi
1252 | TokenKind::VRBrace
1253 | TokenKind::Semi
1254 | TokenKind::RBrace => break,
1255 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1256 TokenKind::RParen | TokenKind::RBracket => {
1257 brackets = brackets.saturating_sub(1)
1258 }
1259 _ => {}
1260 }
1261 self.i += 1;
1262 }
1263 continue;
1264 }
1265 if matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o)) {
1268 self.skip_to_item_end();
1269 return None;
1270 }
1271 match self.peek() {
1272 None
1273 | Some(
1274 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace,
1275 ) => {
1276 self.diag(format!("could not parse equation for '{name}'"));
1277 return None;
1278 }
1279 _ => {}
1280 }
1281 match self.pattern_atom() {
1282 Some(p) => params.push(p),
1283 None => {
1284 self.diag(format!("bad parameter pattern in '{name}'"));
1285 return None;
1286 }
1287 }
1288 }
1289 let (body, guards) = self.equation_rhs()?;
1290 let where_bindings = if self.eat_keyword("where") {
1291 self.binding_block()
1292 } else {
1293 Vec::new()
1294 };
1295 self.skip_to_item_end();
1296 Some(Decl::Function(FunctionDecl {
1297 name,
1298 ty: None,
1299 equations: vec![Equation {
1300 params,
1301 body,
1302 guards,
1303 where_bindings,
1304 pos,
1305 span: self.node_span(start_i),
1306 }],
1307 pos,
1308 sig_span: None,
1309 span: self.node_span(start_i),
1310 }))
1311 }
1312
1313 fn equation_rhs(&mut self) -> Option<(Expr, Vec<(Expr, Expr)>)> {
1315 if self.eat_op("=") {
1316 return Some((self.expr(), Vec::new()));
1317 }
1318 let mut guards = Vec::new();
1319 while self.eat_op("|") {
1320 let g = loop {
1323 let g = self.expr();
1324 if self.eat_op("<-") {
1325 let _ = self.expr(); }
1327 if !self.eat(&TokenKind::Comma) {
1328 break g;
1329 }
1330 };
1331 if !self.eat_op("=") {
1332 self.diag("expected '=' after guard");
1333 return None;
1334 }
1335 let e = self.expr();
1336 guards.push((g, e));
1337 }
1338 if guards.is_empty() {
1339 self.diag("expected '=' or guarded right-hand side in equation");
1340 None
1341 } else {
1342 let first = guards[0].1.clone();
1343 Some((first, guards))
1344 }
1345 }
1346
1347 fn binding_block(&mut self) -> Vec<Binding> {
1349 let mut bindings = Vec::new();
1350 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
1351 return bindings;
1352 }
1353 loop {
1354 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
1355 match self.peek() {
1356 None => break,
1357 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
1358 self.bump();
1359 break;
1360 }
1361 Some(TokenKind::RParen | TokenKind::RBracket) => {
1366 self.bump();
1367 continue;
1368 }
1369 _ => {}
1370 }
1371 match self.binding() {
1372 Some(b) => bindings.push(b),
1373 None => self.skip_to_item_end(),
1374 }
1375 }
1376 bindings
1377 }
1378
1379 fn binding(&mut self) -> Option<Binding> {
1382 let pos = self.pos();
1383 let start_i = self.i;
1384 if self.at(&TokenKind::LParen)
1387 && matches!(self.peek_at(1), Some(TokenKind::Op(_)))
1388 && self.peek_at(2) == Some(&TokenKind::RParen)
1389 {
1390 self.skip_to_item_end();
1391 return None;
1392 }
1393 let pat = self.pattern_atom()?;
1394 let mut params = Vec::new();
1395 loop {
1396 if self.at_op("=") {
1397 self.bump();
1398 let expr = self.expr();
1399 if self.eat_keyword("where") {
1401 let _ = self.binding_block();
1402 }
1403 return Some(Binding {
1404 pat,
1405 params,
1406 expr,
1407 pos,
1408 span: self.node_span(start_i),
1409 });
1410 }
1411 if self.at_op("|") {
1412 let (body, _) = self.equation_rhs()?;
1413 if self.eat_keyword("where") {
1414 let _ = self.binding_block();
1415 }
1416 return Some(Binding {
1417 pat,
1418 params,
1419 expr: body,
1420 pos,
1421 span: self.node_span(start_i),
1422 });
1423 }
1424 if self.at_op(":") {
1425 if params.is_empty() {
1426 self.skip_to_item_end();
1428 return None;
1429 }
1430 self.bump();
1433 let mut brackets = 0usize;
1434 while let Some(t) = self.peek() {
1435 match t {
1436 TokenKind::Op(o) if o == "=" && brackets == 0 => break,
1437 TokenKind::VSemi
1438 | TokenKind::VRBrace
1439 | TokenKind::Semi
1440 | TokenKind::RBrace => break,
1441 TokenKind::LParen | TokenKind::LBracket => brackets += 1,
1442 TokenKind::RParen | TokenKind::RBracket => {
1443 brackets = brackets.saturating_sub(1)
1444 }
1445 _ => {}
1446 }
1447 self.i += 1;
1448 }
1449 continue;
1450 }
1451 if matches!(self.peek(), Some(TokenKind::Op(o)) if !is_reserved_op(o)) {
1454 self.skip_to_item_end();
1455 return None;
1456 }
1457 match self.peek() {
1458 None
1459 | Some(
1460 TokenKind::VSemi | TokenKind::VRBrace | TokenKind::Semi | TokenKind::RBrace,
1461 ) => return None,
1462 _ => {}
1463 }
1464 params.push(self.pattern_atom()?);
1465 }
1466 }
1467
1468 fn pattern_atom(&mut self) -> Option<Pat> {
1471 if self.depth >= MAX_RECURSION_DEPTH {
1472 return None;
1473 }
1474 self.depth += 1;
1475 let result = self.pattern_atom_inner();
1476 self.depth -= 1;
1477 result
1478 }
1479
1480 fn pattern_atom_inner(&mut self) -> Option<Pat> {
1481 let pos = self.pos();
1482 let start_i = self.i;
1483 if self.at_op("~") || self.at_op("!") {
1485 self.bump();
1486 return self.pattern_atom();
1487 }
1488 match self.peek().cloned() {
1489 Some(TokenKind::LowerId {
1490 qualifier: None,
1491 name,
1492 }) => {
1493 self.bump();
1494 if name == "_" {
1495 return Some(Pat::Wild {
1496 pos,
1497 span: self.node_span(start_i),
1498 });
1499 }
1500 if self.at_op("@") {
1501 self.bump();
1502 let inner = self.pattern_atom()?;
1503 return Some(Pat::As {
1504 name,
1505 pat: Box::new(inner),
1506 pos,
1507 span: self.node_span(start_i),
1508 });
1509 }
1510 Some(Pat::Var {
1511 name,
1512 pos,
1513 span: self.node_span(start_i),
1514 })
1515 }
1516 Some(TokenKind::Op(o)) if o == "_" => {
1517 self.bump();
1518 Some(Pat::Wild {
1519 pos,
1520 span: self.node_span(start_i),
1521 })
1522 }
1523 Some(TokenKind::UpperId { qualifier, name }) => {
1524 self.bump();
1525 if self.at(&TokenKind::LBrace) {
1528 self.skip_balanced_braces();
1529 } else if self.eat_keyword("with") {
1530 let _ = self.record_fields();
1531 }
1532 Some(Pat::Con {
1533 qualifier,
1534 name,
1535 args: Vec::new(),
1536 pos,
1537 span: self.node_span(start_i),
1538 })
1539 }
1540 Some(TokenKind::IntLit(text)) => {
1541 self.bump();
1542 Some(Pat::Lit {
1543 kind: LitKind::Int,
1544 text,
1545 pos,
1546 span: self.node_span(start_i),
1547 })
1548 }
1549 Some(TokenKind::DecimalLit(text)) => {
1550 self.bump();
1551 Some(Pat::Lit {
1552 kind: LitKind::Decimal,
1553 text,
1554 pos,
1555 span: self.node_span(start_i),
1556 })
1557 }
1558 Some(TokenKind::StringLit(text)) => {
1559 self.bump();
1560 Some(Pat::Lit {
1561 kind: LitKind::Text,
1562 text,
1563 pos,
1564 span: self.node_span(start_i),
1565 })
1566 }
1567 Some(TokenKind::CharLit(text)) => {
1568 self.bump();
1569 Some(Pat::Lit {
1570 kind: LitKind::Char,
1571 text,
1572 pos,
1573 span: self.node_span(start_i),
1574 })
1575 }
1576 Some(TokenKind::LParen) => {
1577 self.bump();
1578 if self.eat(&TokenKind::RParen) {
1579 return Some(Pat::Con {
1580 qualifier: None,
1581 name: "()".to_string(),
1582 args: Vec::new(),
1583 pos,
1584 span: self.node_span(start_i),
1585 });
1586 }
1587 {
1593 let mut depth = 0usize;
1594 let mut j = self.i;
1595 let mut arrow = None;
1596 while let Some(t) = self.toks.get(j).map(|t| &t.kind) {
1597 match t {
1598 TokenKind::LParen | TokenKind::LBracket => depth += 1,
1599 TokenKind::RParen | TokenKind::RBracket => {
1600 if depth == 0 {
1601 break;
1602 }
1603 depth -= 1;
1604 }
1605 TokenKind::Op(o) if o == ":" && depth == 0 => break,
1606 TokenKind::Op(o) if o == "->" && depth == 0 => {
1607 arrow = Some(j);
1608 break;
1609 }
1610 TokenKind::VSemi | TokenKind::VRBrace => break,
1611 TokenKind::Op(o) if o == "\\" => break,
1613 _ => {}
1614 }
1615 j += 1;
1616 }
1617 if let Some(j) = arrow {
1618 self.i = j + 1; let inner = self.pattern()?;
1620 self.eat(&TokenKind::RParen);
1621 return Some(inner);
1622 }
1623 }
1624 let first = self.pattern()?;
1625 if self.at_op(":") {
1627 let mut depth = 0usize;
1628 while let Some(t) = self.peek() {
1629 match t {
1630 TokenKind::LParen | TokenKind::LBracket => depth += 1,
1631 TokenKind::RParen if depth == 0 => break,
1632 TokenKind::RParen | TokenKind::RBracket => {
1633 depth = depth.saturating_sub(1)
1634 }
1635 TokenKind::VSemi | TokenKind::VRBrace => break,
1636 _ => {}
1637 }
1638 self.i += 1;
1639 }
1640 }
1641 if self.at(&TokenKind::Comma) {
1642 let mut items = vec![first];
1643 while self.eat(&TokenKind::Comma) {
1644 items.push(self.pattern()?);
1645 }
1646 self.eat(&TokenKind::RParen);
1647 return Some(Pat::Tuple {
1648 items,
1649 pos,
1650 span: self.node_span(start_i),
1651 });
1652 }
1653 self.eat(&TokenKind::RParen);
1654 Some(first)
1655 }
1656 Some(TokenKind::LBracket) => {
1657 self.bump();
1658 let mut items = Vec::new();
1659 if !self.eat(&TokenKind::RBracket) {
1660 loop {
1661 items.push(self.pattern()?);
1662 if !self.eat(&TokenKind::Comma) {
1663 break;
1664 }
1665 }
1666 self.eat(&TokenKind::RBracket);
1667 }
1668 Some(Pat::List {
1669 items,
1670 pos,
1671 span: self.node_span(start_i),
1672 })
1673 }
1674 _ => None,
1675 }
1676 }
1677
1678 fn pattern(&mut self) -> Option<Pat> {
1680 if self.depth >= MAX_RECURSION_DEPTH {
1681 return None;
1682 }
1683 self.depth += 1;
1684 let result = self.pattern_inner();
1685 self.depth -= 1;
1686 result
1687 }
1688
1689 fn pattern_inner(&mut self) -> Option<Pat> {
1690 let pos = self.pos();
1691 let start_i = self.i;
1692 let first = match self.peek().cloned() {
1693 Some(TokenKind::UpperId { qualifier, name }) => {
1694 self.bump();
1695 if self.at(&TokenKind::LBrace) || self.at_keyword("with") {
1696 if self.eat_keyword("with") {
1697 let _ = self.record_fields();
1698 } else {
1699 self.skip_balanced_braces();
1700 }
1701 Pat::Con {
1702 qualifier,
1703 name,
1704 args: Vec::new(),
1705 pos,
1706 span: self.node_span(start_i),
1707 }
1708 } else {
1709 let mut args = Vec::new();
1710 while let Some(a) = self.try_pattern_atom() {
1711 args.push(a);
1712 }
1713 Pat::Con {
1714 qualifier,
1715 name,
1716 args,
1717 pos,
1718 span: self.node_span(start_i),
1719 }
1720 }
1721 }
1722 _ => self.pattern_atom()?,
1723 };
1724 if self.at_op("::") {
1725 self.bump();
1726 let rest = self.pattern()?;
1727 return Some(Pat::Con {
1728 qualifier: None,
1729 name: "::".to_string(),
1730 args: vec![first, rest],
1731 pos,
1732 span: self.node_span(start_i),
1733 });
1734 }
1735 Some(first)
1736 }
1737
1738 fn try_pattern_atom(&mut self) -> Option<Pat> {
1739 match self.peek() {
1740 Some(
1741 TokenKind::LowerId {
1742 qualifier: None, ..
1743 }
1744 | TokenKind::UpperId { .. }
1745 | TokenKind::IntLit(_)
1746 | TokenKind::DecimalLit(_)
1747 | TokenKind::StringLit(_)
1748 | TokenKind::CharLit(_)
1749 | TokenKind::LParen
1750 | TokenKind::LBracket,
1751 ) => self.pattern_atom(),
1752 _ => None,
1753 }
1754 }
1755
1756 fn skip_balanced_braces(&mut self) {
1757 let mut depth = 0usize;
1758 while let Some(t) = self.peek() {
1759 match t {
1760 TokenKind::LBrace => depth += 1,
1761 TokenKind::RBrace => {
1762 if depth == 0 {
1763 return;
1764 }
1765 depth -= 1;
1766 if depth == 0 {
1767 self.i += 1;
1768 return;
1769 }
1770 }
1771 _ => {}
1772 }
1773 self.i += 1;
1774 }
1775 }
1776
1777 fn expr(&mut self) -> Expr {
1780 self.expr_prec(0, true)
1781 }
1782
1783 fn expr_no_do(&mut self) -> Expr {
1784 self.expr_prec(0, false)
1785 }
1786
1787 fn expr_comma_list(&mut self) -> Vec<Expr> {
1789 let mut out = vec![self.expr()];
1790 while self.eat(&TokenKind::Comma) {
1791 out.push(self.expr());
1792 }
1793 out
1794 }
1795
1796 fn expr_comma_list_no_do(&mut self) -> Vec<Expr> {
1797 let mut out = vec![self.expr_no_do()];
1798 while self.eat(&TokenKind::Comma) {
1799 out.push(self.expr_no_do());
1800 }
1801 out
1802 }
1803
1804 fn expr_prec(&mut self, min_prec: u8, allow_do: bool) -> Expr {
1805 let pos = self.pos();
1806 let start_i = self.i;
1807 if self.depth >= MAX_RECURSION_DEPTH {
1808 self.diag_cat(
1813 DiagnosticCategory::RecursionLimit,
1814 "expression nesting too deep; truncated to raw text",
1815 );
1816 let start = self.i;
1817 self.skip_to_item_end();
1818 if self.i == start {
1819 self.bump();
1820 }
1821 return Expr::Error {
1822 raw: self.slice_text(start),
1823 span: self.node_span(start),
1824 pos,
1825 };
1826 }
1827 self.depth += 1;
1828 let result = self.expr_prec_inner(min_prec, allow_do, pos, start_i);
1829 self.depth -= 1;
1830 result
1831 }
1832
1833 fn expr_prec_inner(&mut self, min_prec: u8, allow_do: bool, pos: Pos, start_i: usize) -> Expr {
1834 let mut lhs = match self.unary(allow_do) {
1835 Some(e) => e,
1836 None => {
1837 let start = self.i;
1839 self.skip_to_item_end();
1840 if self.i == start {
1841 self.bump();
1842 }
1843 return Expr::Error {
1844 raw: self.slice_text(start),
1845 span: self.node_span(start),
1846 pos,
1847 };
1848 }
1849 };
1850 loop {
1851 let (op, prec, right_assoc) = match self.peek() {
1852 Some(TokenKind::Op(o)) => {
1853 let o = o.clone();
1854 if is_reserved_op(&o) {
1855 if o == ":" {
1857 self.bump();
1858 self.skip_type_tokens();
1859 continue;
1860 }
1861 break;
1862 }
1863 let (p, r) = fixity(&o);
1864 (o, p, r)
1865 }
1866 Some(TokenKind::Backtick) => {
1867 let name = match self.peek_at(1) {
1869 Some(
1870 TokenKind::LowerId { qualifier, name }
1871 | TokenKind::UpperId { qualifier, name },
1872 ) => qualifier
1873 .as_ref()
1874 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
1875 _ => break,
1876 };
1877 if self.peek_at(2) != Some(&TokenKind::Backtick) {
1878 break;
1879 }
1880 (format!("`{name}`"), 9, false)
1881 }
1882 _ => break,
1883 };
1884 if prec < min_prec {
1885 break;
1886 }
1887 self.bump();
1888 if op.starts_with('`') {
1889 self.bump();
1890 self.bump();
1891 }
1892 let next_min = if right_assoc { prec } else { prec + 1 };
1893 let rhs = self.expr_prec(next_min, allow_do);
1894 lhs = Expr::BinOp {
1895 op,
1896 lhs: Box::new(lhs),
1897 rhs: Box::new(rhs),
1898 pos,
1899 span: self.node_span(start_i),
1900 };
1901 }
1902 lhs
1903 }
1904
1905 fn unary(&mut self, allow_do: bool) -> Option<Expr> {
1906 let pos = self.pos();
1907 let start_i = self.i;
1908 if self.at_op("-") {
1909 self.bump();
1910 let e = self.unary(allow_do)?;
1911 return Some(Expr::Neg {
1912 expr: Box::new(e),
1913 pos,
1914 span: self.node_span(start_i),
1915 });
1916 }
1917 self.application(allow_do)
1918 }
1919
1920 fn application(&mut self, allow_do: bool) -> Option<Expr> {
1921 let pos = self.pos();
1922 let start_i = self.i;
1923 let head0 = self.atom(allow_do)?;
1924 let mut head = self.projection_tail(head0);
1925 let mut args = Vec::new();
1926 loop {
1927 if self.at_keyword("with") {
1930 let target = args.pop().unwrap_or_else(|| {
1931 std::mem::replace(
1932 &mut head,
1933 Expr::Error {
1934 raw: String::new(),
1935 pos,
1936 span: Span::default(),
1937 },
1938 )
1939 });
1940 self.bump(); let fields = self.record_fields();
1942 let tpos = target.pos();
1943 let sp = Span::new(target.span().start, self.end_byte());
1944 let rec = Expr::Record {
1945 base: Box::new(target),
1946 fields,
1947 pos: tpos,
1948 span: sp,
1949 };
1950 if matches!(head, Expr::Error { ref raw, .. } if raw.is_empty()) {
1951 head = rec;
1952 } else {
1953 args.push(rec);
1954 }
1955 continue;
1956 }
1957 if !allow_do && self.at_keyword("do") {
1958 break;
1959 }
1960 if self.at_op("@") {
1962 self.bump();
1963 match self.peek() {
1964 Some(TokenKind::UpperId { .. } | TokenKind::LowerId { .. }) => {
1965 self.bump();
1966 }
1967 Some(TokenKind::LParen) => self.skip_balanced_parens(),
1968 Some(TokenKind::LBracket) => {
1969 let mut depth = 0usize;
1970 while let Some(t) = self.peek() {
1971 match t {
1972 TokenKind::LBracket => depth += 1,
1973 TokenKind::RBracket => {
1974 if depth == 0 {
1975 break;
1976 }
1977 depth -= 1;
1978 if depth == 0 {
1979 self.i += 1;
1980 break;
1981 }
1982 }
1983 _ => {}
1984 }
1985 self.i += 1;
1986 }
1987 }
1988 _ => {}
1989 }
1990 continue;
1991 }
1992 match self.try_atom(allow_do) {
1993 Some(a) => args.push(self.projection_tail(a)),
1994 None => break,
1995 }
1996 }
1997 if args.is_empty() {
1998 Some(head)
1999 } else {
2000 Some(Expr::App {
2001 func: Box::new(head),
2002 args,
2003 pos,
2004 span: self.node_span(start_i),
2005 })
2006 }
2007 }
2008
2009 fn record_fields(&mut self) -> Vec<FieldAssign> {
2011 let mut fields = Vec::new();
2012 let explicit = self.at(&TokenKind::LBrace);
2013 if !(self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace)) {
2014 return fields;
2015 }
2016 loop {
2017 while self.eat(&TokenKind::VSemi)
2018 || self.eat(&TokenKind::Semi)
2019 || self.eat(&TokenKind::Comma)
2020 {}
2021 match self.peek() {
2022 None => break,
2023 Some(TokenKind::VRBrace) if !explicit => {
2024 self.bump();
2025 break;
2026 }
2027 Some(TokenKind::RBrace) => {
2028 self.bump();
2029 break;
2030 }
2031 Some(TokenKind::RParen | TokenKind::RBracket) => {
2033 self.bump();
2034 continue;
2035 }
2036 _ => {}
2037 }
2038 let pos = self.pos();
2039 let start_i = self.i;
2040 if self.at_op("..") {
2041 self.bump();
2042 fields.push(FieldAssign {
2043 name: "..".to_string(),
2044 value: None,
2045 pos,
2046 span: self.node_span(start_i),
2047 });
2048 continue;
2049 }
2050 let name = match self.peek().cloned() {
2051 Some(TokenKind::LowerId {
2052 qualifier: None,
2053 name,
2054 }) => {
2055 self.bump();
2056 name
2057 }
2058 _ => {
2059 self.skip_to_item_end();
2060 continue;
2061 }
2062 };
2063 if self.eat_op("=") {
2064 let value = self.expr_prec(1, true);
2065 fields.push(FieldAssign {
2066 name,
2067 value: Some(value),
2068 pos,
2069 span: self.node_span(start_i),
2070 });
2071 } else {
2072 fields.push(FieldAssign {
2074 name,
2075 value: None,
2076 pos,
2077 span: self.node_span(start_i),
2078 });
2079 }
2080 }
2081 fields
2082 }
2083
2084 fn try_atom(&mut self, allow_do: bool) -> Option<Expr> {
2085 match self.peek() {
2086 Some(TokenKind::LowerId { .. }) => {
2087 let kw = self.peek().and_then(|t| t.keyword());
2088 match kw {
2089 Some("do") if allow_do => self.atom(allow_do),
2091 Some(
2094 "if" | "case" | "do" | "let" | "try" | "where" | "then" | "else" | "of"
2095 | "in" | "controller" | "with" | "catch",
2096 ) => None,
2097 _ => self.atom(allow_do),
2098 }
2099 }
2100 Some(
2101 TokenKind::UpperId { .. }
2102 | TokenKind::IntLit(_)
2103 | TokenKind::DecimalLit(_)
2104 | TokenKind::StringLit(_)
2105 | TokenKind::CharLit(_)
2106 | TokenKind::LParen
2107 | TokenKind::LBracket,
2108 ) => self.atom(allow_do),
2109 Some(TokenKind::Op(o)) if o == "\\" => self.atom(allow_do),
2111 _ => None,
2112 }
2113 }
2114
2115 fn projection_tail(&mut self, mut base: Expr) -> Expr {
2122 while self.at_tight_projection() {
2123 let start = base.span().start;
2124 let pos = base.pos();
2125 self.bump(); let Some(field_tok) = self.bump() else {
2127 self.diag("expected projection field after '.'");
2128 return base;
2129 };
2130 let TokenKind::LowerId { qualifier, name } = field_tok.kind else {
2131 self.diag("expected projection field after '.'");
2132 return base;
2133 };
2134 let field = Expr::Var {
2135 qualifier,
2136 name,
2137 pos: field_tok.pos,
2138 span: Span::new(field_tok.start, field_tok.end),
2139 };
2140 base = Expr::BinOp {
2141 op: ".".to_string(),
2142 lhs: Box::new(base),
2143 rhs: Box::new(field),
2144 pos,
2145 span: Span::new(start, self.end_byte()),
2146 };
2147 }
2148 base
2149 }
2150
2151 fn at_tight_projection(&self) -> bool {
2155 if self.i == 0 {
2156 return false;
2157 }
2158 let dot = match self.toks.get(self.i) {
2159 Some(t) => t,
2160 None => return false,
2161 };
2162 if !matches!(&dot.kind, TokenKind::Op(o) if o == ".") {
2163 return false;
2164 }
2165 let prev = &self.toks[self.i - 1];
2169 if prev.is_virtual() || prev.end != dot.start {
2170 return false;
2171 }
2172 self.toks.get(self.i + 1).is_some_and(|t| {
2174 matches!(
2175 &t.kind,
2176 TokenKind::LowerId {
2177 qualifier: None,
2178 ..
2179 }
2180 ) && t.start == dot.end
2181 })
2182 }
2183
2184 fn atom(&mut self, allow_do: bool) -> Option<Expr> {
2185 let pos = self.pos();
2186 let start_i = self.i;
2187 match self.peek().cloned() {
2188 Some(TokenKind::LowerId { qualifier, name }) => {
2189 match name.as_str() {
2190 "if" if qualifier.is_none() => return self.if_expr(),
2191 "case" if qualifier.is_none() => return self.case_expr(),
2192 "do" if qualifier.is_none() => {
2193 if !allow_do {
2194 return None;
2195 }
2196 return self.do_expr();
2197 }
2198 "let" if qualifier.is_none() => return self.let_expr(),
2199 "try" if qualifier.is_none() => return self.try_expr(),
2200 _ => {}
2201 }
2202 self.bump();
2203 Some(Expr::Var {
2204 qualifier,
2205 name,
2206 pos,
2207 span: self.node_span(start_i),
2208 })
2209 }
2210 Some(TokenKind::UpperId { qualifier, name }) => {
2211 self.bump();
2212 let base = Expr::Con {
2213 qualifier,
2214 name,
2215 pos,
2216 span: self.node_span(start_i),
2217 };
2218 if self.at(&TokenKind::LBrace) {
2220 let fields = self.record_fields();
2221 return Some(Expr::Record {
2222 base: Box::new(base),
2223 fields,
2224 pos,
2225 span: self.node_span(start_i),
2226 });
2227 }
2228 Some(base)
2229 }
2230 Some(TokenKind::IntLit(text)) => {
2231 self.bump();
2232 Some(Expr::Lit {
2233 kind: LitKind::Int,
2234 text,
2235 pos,
2236 span: self.node_span(start_i),
2237 })
2238 }
2239 Some(TokenKind::DecimalLit(text)) => {
2240 self.bump();
2241 Some(Expr::Lit {
2242 kind: LitKind::Decimal,
2243 text,
2244 pos,
2245 span: self.node_span(start_i),
2246 })
2247 }
2248 Some(TokenKind::StringLit(text)) => {
2249 self.bump();
2250 Some(Expr::Lit {
2251 kind: LitKind::Text,
2252 text,
2253 pos,
2254 span: self.node_span(start_i),
2255 })
2256 }
2257 Some(TokenKind::CharLit(text)) => {
2258 self.bump();
2259 Some(Expr::Lit {
2260 kind: LitKind::Char,
2261 text,
2262 pos,
2263 span: self.node_span(start_i),
2264 })
2265 }
2266 Some(TokenKind::Op(o)) if o == "\\" => self.lambda_expr(),
2267 Some(TokenKind::LParen) => self.paren_expr(),
2268 Some(TokenKind::LBracket) => self.list_expr(),
2269 _ => None,
2270 }
2271 }
2272
2273 fn if_expr(&mut self) -> Option<Expr> {
2274 let pos = self.pos();
2275 let start_i = self.i;
2276 self.bump(); let cond = self.expr();
2278 self.eat(&TokenKind::VSemi); if !self.eat_keyword("then") {
2280 self.diag("expected 'then'");
2281 return Some(Expr::Error {
2282 raw: format!("if {}", cond.render()),
2283 pos,
2284 span: self.node_span(start_i),
2285 });
2286 }
2287 let then_branch = self.expr();
2288 self.eat(&TokenKind::VSemi);
2289 if !self.eat_keyword("else") {
2290 self.diag("expected 'else'");
2291 return Some(Expr::Error {
2292 raw: format!("if {} then {}", cond.render(), then_branch.render()),
2293 pos,
2294 span: self.node_span(start_i),
2295 });
2296 }
2297 let else_branch = self.expr();
2298 Some(Expr::If {
2299 cond: Box::new(cond),
2300 then_branch: Box::new(then_branch),
2301 else_branch: Box::new(else_branch),
2302 pos,
2303 span: self.node_span(start_i),
2304 })
2305 }
2306
2307 fn case_expr(&mut self) -> Option<Expr> {
2308 let pos = self.pos();
2309 let start_i = self.i;
2310 self.bump(); let scrutinee = self.expr_no_do();
2312 if !self.eat_keyword("of") {
2313 self.diag("expected 'of' in case expression");
2314 return Some(Expr::Error {
2315 raw: format!("case {}", scrutinee.render()),
2316 pos,
2317 span: self.node_span(start_i),
2318 });
2319 }
2320 let mut alts = Vec::new();
2321 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2322 loop {
2323 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2324 match self.peek() {
2325 None => break,
2326 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2327 self.bump();
2328 break;
2329 }
2330 Some(TokenKind::RParen | TokenKind::RBracket) => {
2332 self.bump();
2333 continue;
2334 }
2335 _ => {}
2336 }
2337 if self.eat_keyword("where") {
2339 let _ = self.binding_block();
2340 continue;
2341 }
2342 match self.case_alt() {
2343 Some(a) => alts.push(a),
2344 None => self.skip_to_item_end(),
2345 }
2346 }
2347 }
2348 Some(Expr::Case {
2349 scrutinee: Box::new(scrutinee),
2350 alts,
2351 pos,
2352 span: self.node_span(start_i),
2353 })
2354 }
2355
2356 fn case_alt(&mut self) -> Option<Alt> {
2357 let pos = self.pos();
2358 let start_i = self.i;
2359 let pat = self.pattern()?;
2360 if self.at_op("|") {
2361 let mut first: Option<Expr> = None;
2365 while self.eat_op("|") {
2366 loop {
2367 let _guard = self.expr();
2368 if self.eat_op("<-") {
2369 let _ = self.expr();
2370 }
2371 if !self.eat(&TokenKind::Comma) {
2372 break;
2373 }
2374 }
2375 if !self.eat_op("->") {
2376 self.diag("expected '->' in guarded case alternative");
2377 return None;
2378 }
2379 let body = self.expr();
2380 if first.is_none() {
2381 first = Some(body);
2382 }
2383 }
2384 return Some(Alt {
2385 pat,
2386 body: first?,
2387 pos,
2388 span: self.node_span(start_i),
2389 });
2390 }
2391 if !self.eat_op("->") {
2392 self.diag("expected '->' in case alternative");
2393 return None;
2394 }
2395 let body = self.expr();
2396 Some(Alt {
2397 pat,
2398 body,
2399 pos,
2400 span: self.node_span(start_i),
2401 })
2402 }
2403
2404 fn do_expr(&mut self) -> Option<Expr> {
2405 let pos = self.pos();
2406 let start_i = self.i;
2407 self.bump(); let mut stmts = Vec::new();
2409 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2410 loop {
2411 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2412 match self.peek() {
2413 None => break,
2414 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2415 self.bump();
2416 break;
2417 }
2418 Some(TokenKind::RParen | TokenKind::RBracket) => {
2420 self.bump();
2421 continue;
2422 }
2423 _ => {}
2424 }
2425 stmts.push(self.do_stmt());
2426 }
2427 }
2428 Some(Expr::Do {
2429 stmts,
2430 pos,
2431 span: self.node_span(start_i),
2432 })
2433 }
2434
2435 fn do_stmt(&mut self) -> DoStmt {
2436 let pos = self.pos();
2437 let start_i = self.i;
2438 if self.at_keyword("let") {
2439 self.bump();
2440 let bindings = self.binding_block();
2441 if self.eat_keyword("in") {
2443 let body = self.expr();
2444 return DoStmt::Expr {
2445 expr: Expr::LetIn {
2446 bindings,
2447 body: Box::new(body),
2448 pos,
2449 span: self.node_span(start_i),
2450 },
2451 pos,
2452 span: self.node_span(start_i),
2453 };
2454 }
2455 return DoStmt::Let {
2456 bindings,
2457 pos,
2458 span: self.node_span(start_i),
2459 };
2460 }
2461 let snapshot = self.i;
2463 if let Some(pat) = self.try_bind_pattern() {
2464 if self.at_op("<-") {
2465 self.bump();
2466 let expr = self.expr();
2467 return DoStmt::Bind {
2468 pat,
2469 expr,
2470 pos,
2471 span: self.node_span(start_i),
2472 };
2473 }
2474 }
2475 self.i = snapshot;
2476 let expr = self.expr();
2477 DoStmt::Expr {
2478 expr,
2479 pos,
2480 span: self.node_span(start_i),
2481 }
2482 }
2483
2484 fn try_bind_pattern(&mut self) -> Option<Pat> {
2487 self.pattern()
2488 }
2489
2490 fn let_expr(&mut self) -> Option<Expr> {
2491 let pos = self.pos();
2492 let start_i = self.i;
2493 self.bump(); let bindings = self.binding_block();
2495 if self.eat_keyword("in") {
2496 let body = self.expr();
2497 return Some(Expr::LetIn {
2498 bindings,
2499 body: Box::new(body),
2500 pos,
2501 span: self.node_span(start_i),
2502 });
2503 }
2504 Some(Expr::LetIn {
2506 bindings,
2507 body: Box::new(Expr::Error {
2508 raw: String::new(),
2509 pos,
2510 span: self.node_span(start_i),
2511 }),
2512 pos,
2513 span: self.node_span(start_i),
2514 })
2515 }
2516
2517 fn try_expr(&mut self) -> Option<Expr> {
2518 let pos = self.pos();
2519 let start_i = self.i;
2520 self.bump(); let body = self.expr();
2522 let mut handlers = Vec::new();
2523 self.eat(&TokenKind::VSemi);
2524 if self.eat_keyword("catch") {
2525 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2526 loop {
2527 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2528 match self.peek() {
2529 None => break,
2530 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2531 self.bump();
2532 break;
2533 }
2534 Some(TokenKind::RParen | TokenKind::RBracket) => {
2536 self.bump();
2537 continue;
2538 }
2539 _ => {}
2540 }
2541 match self.case_alt() {
2542 Some(a) => handlers.push(a),
2543 None => self.skip_to_item_end(),
2544 }
2545 }
2546 } else if let Some(a) = self.case_alt() {
2547 handlers.push(a);
2549 }
2550 }
2551 Some(Expr::Try {
2552 body: Box::new(body),
2553 handlers,
2554 pos,
2555 span: self.node_span(start_i),
2556 })
2557 }
2558
2559 fn lambda_expr(&mut self) -> Option<Expr> {
2560 let pos = self.pos();
2561 let start_i = self.i;
2562 self.bump(); if self.eat_keyword("case") {
2565 let mut alts = Vec::new();
2566 if self.eat(&TokenKind::VLBrace) || self.eat(&TokenKind::LBrace) {
2567 loop {
2568 while self.eat(&TokenKind::VSemi) || self.eat(&TokenKind::Semi) {}
2569 match self.peek() {
2570 None => break,
2571 Some(TokenKind::VRBrace | TokenKind::RBrace) => {
2572 self.bump();
2573 break;
2574 }
2575 Some(TokenKind::RParen | TokenKind::RBracket) => {
2576 self.bump();
2577 continue;
2578 }
2579 _ => {}
2580 }
2581 match self.case_alt() {
2582 Some(a) => alts.push(a),
2583 None => self.skip_to_item_end(),
2584 }
2585 }
2586 }
2587 return Some(Expr::Lambda {
2588 params: vec![Pat::Var {
2589 name: "_".to_string(),
2590 pos,
2591 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2592 }],
2593 body: Box::new(Expr::Case {
2594 scrutinee: Box::new(Expr::Var {
2595 qualifier: None,
2596 name: "_".to_string(),
2597 pos,
2598 span: Span::new(self.byte_at(start_i), self.byte_at(start_i)),
2599 }),
2600 alts,
2601 pos,
2602 span: self.node_span(start_i),
2603 }),
2604 pos,
2605 span: self.node_span(start_i),
2606 });
2607 }
2608 let mut params = Vec::new();
2609 while !self.at_op("->") {
2610 match self.pattern_atom() {
2611 Some(p) => params.push(p),
2612 None => {
2613 self.diag("bad lambda parameter");
2614 let start = self.i;
2615 self.skip_to_item_end();
2616 return Some(Expr::Error {
2617 raw: format!("\\{}", self.slice_text(start)),
2618 pos,
2619 span: self.node_span(start_i),
2620 });
2621 }
2622 }
2623 }
2624 self.bump(); let body = self.expr();
2626 Some(Expr::Lambda {
2627 params,
2628 body: Box::new(body),
2629 pos,
2630 span: self.node_span(start_i),
2631 })
2632 }
2633
2634 fn paren_expr(&mut self) -> Option<Expr> {
2635 let pos = self.pos();
2636 let start_i = self.i;
2637 self.bump(); if self.eat(&TokenKind::RParen) {
2639 return Some(Expr::Con {
2640 qualifier: None,
2641 name: "()".to_string(),
2642 pos,
2643 span: self.node_span(start_i),
2644 });
2645 }
2646 if let Some(TokenKind::Op(o)) = self.peek().cloned() {
2648 if !is_reserved_op(&o) && o != "\\" && o != "-" {
2649 self.bump();
2650 if self.eat(&TokenKind::RParen) {
2651 return Some(Expr::Section {
2652 op: o,
2653 operand: None,
2654 left: false,
2655 pos,
2656 span: self.node_span(start_i),
2657 });
2658 }
2659 let operand = self.expr();
2660 self.eat(&TokenKind::RParen);
2661 return Some(Expr::Section {
2662 op: o,
2663 operand: Some(Box::new(operand)),
2664 left: false,
2665 pos,
2666 span: self.node_span(start_i),
2667 });
2668 }
2669 }
2670 let first = self.expr();
2671 if self.at(&TokenKind::Comma) {
2672 let mut items = vec![first];
2673 while self.eat(&TokenKind::Comma) {
2674 items.push(self.expr());
2675 }
2676 self.eat(&TokenKind::RParen);
2677 return Some(Expr::Tuple {
2678 items,
2679 pos,
2680 span: self.node_span(start_i),
2681 });
2682 }
2683 if let Some(TokenKind::Op(o)) = self.peek().cloned() {
2685 if !is_reserved_op(&o) && self.peek_at(1) == Some(&TokenKind::RParen) {
2686 self.bump();
2687 self.bump();
2688 return Some(Expr::Section {
2689 op: o,
2690 operand: Some(Box::new(first)),
2691 left: true,
2692 pos,
2693 span: self.node_span(start_i),
2694 });
2695 }
2696 }
2697 self.eat(&TokenKind::RParen);
2698 Some(first)
2699 }
2700
2701 fn list_expr(&mut self) -> Option<Expr> {
2702 let pos = self.pos();
2703 let start_i = self.i;
2704 self.bump(); let mut items = Vec::new();
2706 if self.eat(&TokenKind::RBracket) {
2707 return Some(Expr::List {
2708 items,
2709 pos,
2710 span: self.node_span(start_i),
2711 });
2712 }
2713 loop {
2714 let e = self.expr();
2715 if self.at_op("..") {
2717 self.bump();
2718 let hi = if self.at(&TokenKind::RBracket) {
2719 Expr::Error {
2720 raw: String::new(),
2721 pos,
2722 span: self.node_span(start_i),
2723 }
2724 } else {
2725 self.expr()
2726 };
2727 self.eat(&TokenKind::RBracket);
2728 return Some(Expr::BinOp {
2729 op: "..".to_string(),
2730 lhs: Box::new(e),
2731 rhs: Box::new(hi),
2732 pos,
2733 span: self.node_span(start_i),
2734 });
2735 }
2736 if self.at_op("|") {
2738 let start = self.i;
2739 let mut brackets = 1usize;
2740 while let Some(t) = self.peek() {
2741 match t {
2742 TokenKind::LBracket => brackets += 1,
2743 TokenKind::RBracket => {
2744 brackets -= 1;
2745 if brackets == 0 {
2746 break;
2747 }
2748 }
2749 TokenKind::VSemi | TokenKind::VRBrace => break,
2750 _ => {}
2751 }
2752 self.i += 1;
2753 }
2754 let raw = self.slice_text(start);
2755 self.eat(&TokenKind::RBracket);
2756 return Some(Expr::App {
2757 func: Box::new(e),
2758 args: vec![Expr::Error {
2759 raw,
2760 pos,
2761 span: self.node_span(start_i),
2762 }],
2763 pos,
2764 span: self.node_span(start_i),
2765 });
2766 }
2767 items.push(e);
2768 if !self.eat(&TokenKind::Comma) {
2769 break;
2770 }
2771 }
2772 self.eat(&TokenKind::RBracket);
2773 Some(Expr::List {
2774 items,
2775 pos,
2776 span: self.node_span(start_i),
2777 })
2778 }
2779}
2780
2781fn is_reserved_op(op: &str) -> bool {
2784 matches!(op, "=" | "<-" | "->" | "|" | ":" | "=>" | "@" | "\\" | "..")
2785}
2786
2787fn fixity(op: &str) -> (u8, bool) {
2790 match op {
2791 "$" | "$!" => (1, true),
2792 ">>=" | ">>" | "=<<" | "<&>" => (2, false),
2793 "||" => (3, true),
2794 "&&" => (4, true),
2795 "==" | "/=" | "<" | "<=" | ">" | ">=" => (5, false),
2796 "::" | "++" | "<>" => (6, true),
2797 "+" | "-" => (7, false),
2798 "*" | "/" => (8, false),
2799 "^" | "**" => (9, true),
2800 "." | "!!" => (10, true),
2801 _ => (9, false),
2802 }
2803}
2804
2805fn equations_extent(eqs: &[Equation]) -> Option<Span> {
2810 let mut it = eqs.iter();
2811 let first = it.next()?;
2812 let mut s = first.span;
2813 for e in it {
2814 s.start = s.start.min(e.span.start);
2815 s.end = s.end.max(e.span.end);
2816 }
2817 Some(s)
2818}
2819
2820fn merge_functions(decls: &mut Vec<Decl>) {
2821 let mut out: Vec<Decl> = Vec::with_capacity(decls.len());
2822 let mut function_index_by_name: HashMap<String, usize> = HashMap::new();
2823 for decl in decls.drain(..) {
2824 match decl {
2825 Decl::Function(f) => {
2826 if let Some(existing_index) = function_index_by_name.get(&f.name).copied() {
2827 let Decl::Function(g) = &mut out[existing_index] else {
2828 out.push(Decl::Function(f));
2829 continue;
2830 };
2831 if g.ty.is_none() {
2832 g.ty = f.ty.clone();
2833 }
2834 if g.sig_span.is_none() {
2835 g.sig_span = f.sig_span;
2836 }
2837 if g.equations.is_empty() && !f.equations.is_empty() {
2840 g.pos = f.pos;
2841 }
2842 g.equations.extend(f.equations);
2843 g.span = equations_extent(&g.equations)
2850 .or(g.sig_span)
2851 .unwrap_or(g.span);
2852 } else {
2853 function_index_by_name.insert(f.name.clone(), out.len());
2854 out.push(Decl::Function(f));
2855 }
2856 }
2857 other => out.push(other),
2858 }
2859 }
2860 *decls = out;
2861}
2862
2863pub(crate) fn parse_type_from_tokens(tokens: &[Token]) -> Option<Type> {
2872 let real_tokens: Vec<&Token> = tokens.iter().filter(|t| !t.is_virtual()).collect();
2875 if real_tokens.is_empty() {
2876 return None;
2877 }
2878 let mut parser = TypeTokenParser {
2879 tokens: &real_tokens,
2880 cursor: 0,
2881 };
2882 let ty = parser.parse_type()?;
2883 if parser.cursor == real_tokens.len() {
2886 Some(ty)
2887 } else {
2888 None
2889 }
2890}
2891
2892struct TypeTokenParser<'a> {
2893 tokens: &'a [&'a Token],
2894 cursor: usize,
2895}
2896
2897enum TypeAtom {
2900 ParsedType(Type),
2901 DroppedLiteral(Span),
2902}
2903
2904impl<'a> TypeTokenParser<'a> {
2905 fn peek(&self) -> Option<&'a Token> {
2906 self.tokens.get(self.cursor).copied()
2907 }
2908
2909 fn eat_op(&mut self, op: &str) -> bool {
2910 if self.peek().is_some_and(|t| t.kind.is_op(op)) {
2911 self.cursor += 1;
2912 true
2913 } else {
2914 false
2915 }
2916 }
2917
2918 fn parse_type(&mut self) -> Option<Type> {
2921 let lhs = self.parse_application_type()?;
2922 if self.eat_op("=>") {
2923 let body = self.parse_type()?;
2925 let span = Span::new(lhs.span().start, body.span().end);
2926 return Some(Type::Constrained(Box::new(body), span));
2927 }
2928 if self.eat_op("->") {
2929 let rhs = self.parse_type()?;
2930 let span = Span::new(lhs.span().start, rhs.span().end);
2931 return Some(Type::Fun(Box::new(lhs), Box::new(rhs), span));
2932 }
2933 Some(lhs)
2934 }
2935
2936 fn parse_application_type(&mut self) -> Option<Type> {
2938 let head = match self.parse_atom()? {
2939 TypeAtom::ParsedType(t) => t,
2940 TypeAtom::DroppedLiteral(_) => return None,
2942 };
2943 let mut args = Vec::new();
2944 let start = head.span().start;
2945 let mut end = head.span().end;
2946 loop {
2947 if !self.is_at_type_atom_start() {
2950 break;
2951 }
2952 match self.parse_atom()? {
2953 TypeAtom::ParsedType(t) => {
2954 end = t.span().end;
2955 args.push(t);
2956 }
2957 TypeAtom::DroppedLiteral(span) => {
2958 end = span.end;
2961 }
2962 }
2963 }
2964 let span = Span::new(start, end);
2965 if args.is_empty() {
2966 Some(head.with_span(span))
2967 } else {
2968 Some(Type::App(Box::new(head), args, span))
2969 }
2970 }
2971
2972 fn is_at_type_atom_start(&self) -> bool {
2975 matches!(
2976 self.peek().map(|t| &t.kind),
2977 Some(
2978 TokenKind::UpperId { .. }
2979 | TokenKind::LowerId { .. }
2980 | TokenKind::IntLit(_)
2981 | TokenKind::DecimalLit(_)
2982 | TokenKind::LBracket
2983 | TokenKind::LParen
2984 )
2985 )
2986 }
2987
2988 fn parse_atom(&mut self) -> Option<TypeAtom> {
2989 let tok = self.peek()?;
2990 match &tok.kind {
2991 TokenKind::UpperId { qualifier, name } => {
2992 let con = Type::Con {
2993 qualifier: qualifier.clone(),
2994 name: name.clone(),
2995 span: Span::new(tok.start, tok.end),
2996 };
2997 self.cursor += 1;
2998 Some(TypeAtom::ParsedType(con))
2999 }
3000 TokenKind::LowerId { name, .. } => {
3001 let var = Type::Var(name.clone(), Span::new(tok.start, tok.end));
3004 self.cursor += 1;
3005 Some(TypeAtom::ParsedType(var))
3006 }
3007 TokenKind::IntLit(_) | TokenKind::DecimalLit(_) => {
3008 self.cursor += 1;
3010 Some(TypeAtom::DroppedLiteral(Span::new(tok.start, tok.end)))
3011 }
3012 TokenKind::LBracket => {
3013 let start = tok.start;
3014 self.cursor += 1;
3015 let inner = self.parse_type()?;
3016 self.eat_token(&TokenKind::RBracket).map(|end| {
3017 TypeAtom::ParsedType(Type::List(Box::new(inner), Span::new(start, end.end)))
3018 })
3019 }
3020 TokenKind::LParen => {
3021 let start = tok.start;
3022 self.cursor += 1;
3023 if let Some(end) = self.eat_token(&TokenKind::RParen) {
3024 return Some(TypeAtom::ParsedType(Type::Unit(Span::new(start, end.end))));
3026 }
3027 let first = self.parse_type()?;
3028 if self.peek().map(|t| &t.kind) == Some(&TokenKind::Comma) {
3029 let mut items = vec![first];
3030 while self.eat_token(&TokenKind::Comma).is_some() {
3031 items.push(self.parse_type()?);
3032 }
3033 self.eat_token(&TokenKind::RParen).map(|end| {
3034 TypeAtom::ParsedType(Type::Tuple(items, Span::new(start, end.end)))
3035 })
3036 } else {
3037 self.eat_token(&TokenKind::RParen).map(|end| {
3038 TypeAtom::ParsedType(first.with_span(Span::new(start, end.end)))
3040 })
3041 }
3042 }
3043 _ => None,
3044 }
3045 }
3046
3047 fn eat_token(&mut self, tok: &TokenKind) -> Option<&'a Token> {
3048 if self.peek().is_some_and(|t| t.kind == *tok) {
3049 let t = self.peek();
3050 self.cursor += 1;
3051 t
3052 } else {
3053 None
3054 }
3055 }
3056}
3057
3058fn render_token_slice(tokens: &[Token]) -> String {
3059 let mut s = String::new();
3060 let mut prev_no_space_after = true;
3061 for t in tokens {
3062 let (text, no_space_before, no_space_after): (String, bool, bool) = match &t.kind {
3063 TokenKind::LowerId { qualifier, name } | TokenKind::UpperId { qualifier, name } => (
3064 qualifier
3065 .as_ref()
3066 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
3067 false,
3068 false,
3069 ),
3070 TokenKind::Op(o) => (o.clone(), false, false),
3071 TokenKind::IntLit(n) | TokenKind::DecimalLit(n) => (n.clone(), false, false),
3072 TokenKind::StringLit(v) => (format!("{v:?}"), false, false),
3073 TokenKind::CharLit(v) => (format!("'{v}'"), false, false),
3074 TokenKind::LParen => ("(".to_string(), false, true),
3075 TokenKind::RParen => (")".to_string(), true, false),
3076 TokenKind::LBracket => ("[".to_string(), false, true),
3077 TokenKind::RBracket => ("]".to_string(), true, false),
3078 TokenKind::LBrace => ("{".to_string(), false, true),
3079 TokenKind::RBrace => ("}".to_string(), true, false),
3080 TokenKind::Comma => (",".to_string(), true, false),
3081 TokenKind::Semi | TokenKind::VSemi => (";".to_string(), true, false),
3082 TokenKind::Backtick => ("`".to_string(), false, false),
3083 TokenKind::VLBrace | TokenKind::VRBrace => continue,
3084 };
3085 if !s.is_empty() && !no_space_before && !prev_no_space_after {
3086 s.push(' ');
3087 }
3088 s.push_str(&text);
3089 prev_no_space_after = no_space_after;
3090 }
3091 s
3092}
3093
3094#[cfg(test)]
3095mod type_tests {
3096 use super::*;
3097 use crate::lexer::lex;
3098
3099 fn ty(s: &str) -> Option<Type> {
3103 let (toks, errs) = lex(s).into_parts();
3104 assert!(errs.is_empty(), "lex errors for {s:?}: {errs:?}");
3105 parse_type_from_tokens(&toks)
3106 }
3107
3108 fn con(name: &str) -> Type {
3109 Type::Con {
3110 qualifier: None,
3111 name: name.to_string(),
3112 span: Span::default(),
3113 }
3114 }
3115
3116 fn qualified_con(qualifier: &str, name: &str) -> Type {
3117 Type::Con {
3118 qualifier: Some(qualifier.to_string()),
3119 name: name.to_string(),
3120 span: Span::default(),
3121 }
3122 }
3123
3124 fn app(head: Type, args: Vec<Type>) -> Type {
3125 Type::App(Box::new(head), args, Span::default())
3126 }
3127
3128 fn list(inner: Type) -> Type {
3129 Type::List(Box::new(inner), Span::default())
3130 }
3131
3132 fn tuple(items: Vec<Type>) -> Type {
3133 Type::Tuple(items, Span::default())
3134 }
3135
3136 fn fun(param: Type, result: Type) -> Type {
3137 Type::Fun(Box::new(param), Box::new(result), Span::default())
3138 }
3139
3140 fn var(name: &str) -> Type {
3141 Type::Var(name.to_string(), Span::default())
3142 }
3143
3144 fn unit() -> Type {
3145 Type::Unit(Span::default())
3146 }
3147
3148 fn constrained(body: Type) -> Type {
3149 Type::Constrained(Box::new(body), Span::default())
3150 }
3151
3152 #[test]
3153 fn atoms() {
3154 assert_eq!(ty("Party"), Some(con("Party")));
3155 assert_eq!(ty("Decimal"), Some(con("Decimal")));
3156 assert_eq!(ty("a"), Some(var("a")));
3157 assert_eq!(ty("()"), Some(unit()));
3158 }
3159
3160 #[test]
3161 fn application_vs_constructor() {
3162 assert_eq!(
3165 ty("ContractId Foo"),
3166 Some(app(con("ContractId"), vec![con("Foo")]))
3167 );
3168 assert_eq!(
3169 ty("Optional (ContractId Foo)"),
3170 Some(app(
3171 con("Optional"),
3172 vec![app(con("ContractId"), vec![con("Foo")])]
3173 ))
3174 );
3175 assert_eq!(
3176 ty("Map Text Int"),
3177 Some(app(con("Map"), vec![con("Text"), con("Int")]))
3178 );
3179 }
3180
3181 #[test]
3182 fn qualified_constructor_keeps_qualifier() {
3183 assert_eq!(
3184 ty("DA.Map.Map Text Int"),
3185 Some(app(
3186 qualified_con("DA.Map", "Map"),
3187 vec![con("Text"), con("Int")]
3188 ))
3189 );
3190 }
3191
3192 #[test]
3193 fn list_and_tuple() {
3194 assert_eq!(ty("[Text]"), Some(list(con("Text"))));
3195 assert_eq!(
3196 ty("(Int, Text)"),
3197 Some(tuple(vec![con("Int"), con("Text")]))
3198 );
3199 assert_eq!(
3201 ty("(a, b, c)"),
3202 Some(tuple(vec![var("a"), var("b"), var("c")]))
3203 );
3204 assert_eq!(ty("(Text)"), Some(con("Text")));
3206 }
3207
3208 #[test]
3209 fn function_types_are_arrows_not_names() {
3210 assert_eq!(ty("Int -> Int"), Some(fun(con("Int"), con("Int"))));
3213 assert_eq!(
3215 ty("Int -> Text -> Bool"),
3216 Some(fun(con("Int"), fun(con("Text"), con("Bool"))))
3217 );
3218 assert_eq!(
3219 ty("Party -> Script ()"),
3220 Some(fun(con("Party"), app(con("Script"), vec![unit()])))
3221 );
3222 }
3223
3224 #[test]
3225 fn script_application() {
3226 assert_eq!(ty("Script ()"), Some(app(con("Script"), vec![unit()])));
3229 }
3230
3231 #[test]
3232 fn numeric_nat_literal_is_dropped() {
3233 assert_eq!(ty("Numeric 10"), Some(con("Numeric")));
3236 assert_eq!(ty("Numeric n"), Some(app(con("Numeric"), vec![var("n")])));
3237 }
3238
3239 #[test]
3240 fn constraint_context_is_dropped_body_kept() {
3241 assert_eq!(
3244 ty("NumericScale n => Numeric 37 -> Numeric n"),
3245 Some(constrained(fun(
3246 con("Numeric"),
3247 app(con("Numeric"), vec![var("n")])
3248 )))
3249 );
3250 assert_eq!(ty("(Eq a, Show a) => a"), Some(constrained(var("a"))));
3252 }
3253
3254 #[test]
3255 fn unparseable_is_none() {
3256 assert_eq!(ty("Int ->"), None);
3259 assert_eq!(ty("-> Int"), None);
3260 }
3261
3262 #[test]
3263 fn ty_is_populated_through_real_parse() {
3264 let src = r#"module M where
3267template T
3268 with
3269 owner : Party
3270 held : ContractId Asset
3271 where
3272 signatory owner
3273 choice Go : Optional (ContractId Asset)
3274 controller owner
3275 do
3276 pure None
3277"#;
3278 let (m, _) = parse_module(src).into_parts();
3279 let t = match &m.decls[0] {
3280 Decl::Template(t) => t,
3281 other => panic!("expected template, got {other:?}"),
3282 };
3283 assert_eq!(t.fields[0].ty, Some(con("Party")));
3284 assert_eq!(
3285 t.fields[1].ty,
3286 Some(app(con("ContractId"), vec![con("Asset")]))
3287 );
3288 let choice = match &t
3289 .body
3290 .iter()
3291 .find(|d| matches!(d, TemplateBodyDecl::Choice(_)))
3292 {
3293 Some(TemplateBodyDecl::Choice(c)) => (*c).clone(),
3294 _ => panic!("expected choice"),
3295 };
3296 assert_eq!(
3297 choice.return_ty,
3298 Some(app(
3299 con("Optional"),
3300 vec![app(con("ContractId"), vec![con("Asset")])]
3301 ))
3302 );
3303 }
3304
3305 #[test]
3306 fn ty_is_populated_on_key_and_interface_method() {
3307 let src = r#"module M where
3310template T
3311 with
3312 owner : Party
3313 where
3314 signatory owner
3315 key owner : Party
3316 maintainer owner
3317
3318interface I where
3319 getAmount : Numeric 10
3320"#;
3321 let (m, _) = parse_module(src).into_parts();
3322 let t = match &m.decls[0] {
3323 Decl::Template(t) => t,
3324 other => panic!("expected template, got {other:?}"),
3325 };
3326 let key_ty = t.body.iter().find_map(|d| match d {
3327 TemplateBodyDecl::Key { ty, .. } => Some(ty.clone()),
3328 _ => None,
3329 });
3330 assert_eq!(key_ty, Some(Some(con("Party"))));
3331
3332 let iface = match &m.decls[1] {
3333 Decl::Interface(i) => i,
3334 other => panic!("expected interface, got {other:?}"),
3335 };
3336 assert_eq!(iface.methods[0].ty, Some(con("Numeric")));
3338 }
3339
3340 #[test]
3341 fn malformed_guarded_equation_reports_missing_equals_and_continues() {
3342 let src = "module M where\nf x | x > 0\ng = 1\n";
3343 let (module, diagnostics) = parse_module(src).into_parts();
3344
3345 assert!(
3346 diagnostics.iter().any(
3347 |diagnostic| diagnostic.message == "expected '=' after guard"
3348 && diagnostic.category == DiagnosticCategory::Malformed
3349 ),
3350 "expected guard diagnostic, got {diagnostics:?}"
3351 );
3352 assert!(
3353 module
3354 .decls
3355 .iter()
3356 .any(|decl| matches!(decl, Decl::Function(function) if function.name == "g")),
3357 "parser should recover to the following declaration: {:?}",
3358 module.decls
3359 );
3360 }
3361
3362 #[test]
3363 fn malformed_brackets_do_not_underflow_recovery_scans() {
3364 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";
3365 let (module, _diagnostics) = parse_module(src).into_parts();
3366
3367 assert_eq!(module.name, "M");
3368 assert!(
3369 module
3370 .decls
3371 .iter()
3372 .any(|decl| matches!(decl, Decl::Function(function) if function.name == "g")),
3373 "parser should recover to the following declaration: {:?}",
3374 module.decls
3375 );
3376 }
3377}