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