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