1pub use crate::lexer::Pos;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
21pub struct Span {
22 pub start: usize,
23 pub end: usize,
24}
25
26impl Span {
27 pub const fn new(start: usize, end: usize) -> Self {
28 Self { start, end }
29 }
30
31 pub const fn is_valid(&self) -> bool {
33 self.start <= self.end
34 }
35
36 pub const fn is_empty(&self) -> bool {
38 self.start == self.end
39 }
40
41 pub const fn contains(&self, other: &Self) -> bool {
43 self.is_valid() && other.is_valid() && self.start <= other.start && other.end <= self.end
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub enum LitKind {
49 Int,
50 Decimal,
51 Text,
52 Char,
53}
54
55#[derive(Debug, Clone)]
56pub struct FieldAssign {
57 pub name: String,
58 pub value: Option<Expr>,
61 pub pos: Pos,
62 pub span: Span,
63}
64
65#[derive(Debug, Clone)]
66pub struct Alt {
67 pub pat: Pat,
68 pub body: Expr,
69 pub pos: Pos,
70 pub span: Span,
71}
72
73#[derive(Debug, Clone)]
74pub struct Binding {
75 pub pat: Pat,
77 pub params: Vec<Pat>,
79 pub expr: Expr,
80 pub pos: Pos,
81 pub span: Span,
82}
83
84#[derive(Debug, Clone)]
85pub enum Pat {
86 Var {
87 name: String,
88 pos: Pos,
89 span: Span,
90 },
91 Wild {
92 pos: Pos,
93 span: Span,
94 },
95 Con {
96 qualifier: Option<String>,
97 name: String,
98 args: Vec<Self>,
99 pos: Pos,
100 span: Span,
101 },
102 Tuple {
103 items: Vec<Self>,
104 pos: Pos,
105 span: Span,
106 },
107 List {
108 items: Vec<Self>,
109 pos: Pos,
110 span: Span,
111 },
112 Lit {
113 kind: LitKind,
114 text: String,
115 pos: Pos,
116 span: Span,
117 },
118 As {
120 name: String,
121 pat: Box<Self>,
122 pos: Pos,
123 span: Span,
124 },
125 Other {
127 raw: String,
128 pos: Pos,
129 span: Span,
130 },
131}
132
133#[derive(Debug, Clone)]
134pub enum Expr {
135 Var {
137 qualifier: Option<String>,
138 name: String,
139 pos: Pos,
140 span: Span,
141 },
142 Con {
144 qualifier: Option<String>,
145 name: String,
146 pos: Pos,
147 span: Span,
148 },
149 Lit {
150 kind: LitKind,
151 text: String,
152 pos: Pos,
153 span: Span,
154 },
155 App {
157 func: Box<Self>,
158 args: Vec<Self>,
159 pos: Pos,
160 span: Span,
161 },
162 BinOp {
164 op: String,
165 lhs: Box<Self>,
166 rhs: Box<Self>,
167 pos: Pos,
168 span: Span,
169 },
170 Neg {
172 expr: Box<Self>,
173 pos: Pos,
174 span: Span,
175 },
176 Lambda {
177 params: Vec<Pat>,
178 body: Box<Self>,
179 pos: Pos,
180 span: Span,
181 },
182 If {
183 cond: Box<Self>,
184 then_branch: Box<Self>,
185 else_branch: Box<Self>,
186 pos: Pos,
187 span: Span,
188 },
189 Case {
190 scrutinee: Box<Self>,
191 alts: Vec<Alt>,
192 pos: Pos,
193 span: Span,
194 },
195 Do {
196 stmts: Vec<DoStmt>,
197 pos: Pos,
198 span: Span,
199 },
200 LetIn {
201 bindings: Vec<Binding>,
202 body: Box<Self>,
203 pos: Pos,
204 span: Span,
205 },
206 Record {
209 base: Box<Self>,
210 fields: Vec<FieldAssign>,
211 pos: Pos,
212 span: Span,
213 },
214 Tuple {
215 items: Vec<Self>,
216 pos: Pos,
217 span: Span,
218 },
219 List {
220 items: Vec<Self>,
221 pos: Pos,
222 span: Span,
223 },
224 Try {
226 body: Box<Self>,
227 handlers: Vec<Alt>,
228 pos: Pos,
229 span: Span,
230 },
231 Section {
233 op: String,
234 operand: Option<Box<Self>>,
235 left: bool,
236 pos: Pos,
237 span: Span,
238 },
239 Error { raw: String, pos: Pos, span: Span },
242}
243
244#[derive(Debug, Clone)]
245pub enum DoStmt {
246 Bind {
248 pat: Pat,
249 expr: Expr,
250 pos: Pos,
251 span: Span,
252 },
253 Let {
255 bindings: Vec<Binding>,
256 pos: Pos,
257 span: Span,
258 },
259 Expr { expr: Expr, pos: Pos, span: Span },
261}
262
263#[derive(Debug, Clone)]
271pub enum Type {
272 Con {
274 qualifier: Option<String>,
275 name: String,
276 span: Span,
277 },
278 App(Box<Self>, Vec<Self>, Span),
283 List(Box<Self>, Span),
285 Tuple(Vec<Self>, Span),
287 Fun(Box<Self>, Box<Self>, Span),
289 Var(String, Span),
291 Unit(Span),
293 Constrained(Box<Self>, Span),
296}
297
298impl Type {
299 pub const fn span(&self) -> Span {
300 match self {
301 Self::Con { span, .. }
302 | Self::App(_, _, span)
303 | Self::List(_, span)
304 | Self::Tuple(_, span)
305 | Self::Fun(_, _, span)
306 | Self::Var(_, span)
307 | Self::Unit(span)
308 | Self::Constrained(_, span) => *span,
309 }
310 }
311
312 pub(crate) const fn with_span(mut self, span: Span) -> Self {
313 match &mut self {
314 Self::Con { span: s, .. }
315 | Self::App(_, _, s)
316 | Self::List(_, s)
317 | Self::Tuple(_, s)
318 | Self::Fun(_, _, s)
319 | Self::Var(_, s)
320 | Self::Unit(s)
321 | Self::Constrained(_, s) => *s = span,
322 }
323 self
324 }
325}
326
327impl PartialEq for Type {
332 fn eq(&self, other: &Self) -> bool {
333 match (self, other) {
334 (
335 Self::Con {
336 qualifier: aq,
337 name: an,
338 ..
339 },
340 Self::Con {
341 qualifier: bq,
342 name: bn,
343 ..
344 },
345 ) => aq == bq && an == bn,
346 (Self::App(ah, aa, _), Self::App(bh, ba, _)) => ah == bh && aa == ba,
347 (Self::List(a, _), Self::List(b, _))
348 | (Self::Constrained(a, _), Self::Constrained(b, _)) => a == b,
349 (Self::Tuple(a, _), Self::Tuple(b, _)) => a == b,
350 (Self::Fun(al, ar, _), Self::Fun(bl, br, _)) => al == bl && ar == br,
351 (Self::Var(a, _), Self::Var(b, _)) => a == b,
352 (Self::Unit(_), Self::Unit(_)) => true,
353 _ => false,
354 }
355 }
356}
357
358impl Eq for Type {}
359
360#[derive(Debug, Clone)]
361pub struct FieldDecl {
362 pub name: String,
363 pub ty: Option<Type>,
366 pub pos: Pos,
367 pub span: Span,
368}
369
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum Consuming {
372 Consuming,
373 NonConsuming,
374 PreConsuming,
375 PostConsuming,
376}
377
378#[derive(Debug, Clone)]
379pub struct ChoiceDecl {
380 pub name: String,
381 pub consuming: Consuming,
382 pub return_ty: Option<Type>,
385 pub params: Vec<FieldDecl>,
386 pub controllers: Vec<Expr>,
388 pub observers: Vec<Expr>,
390 pub body: Option<Expr>,
391 pub pos: Pos,
392 pub span: Span,
393}
394
395#[derive(Debug, Clone)]
396pub enum TemplateBodyDecl {
397 Signatory {
398 parties: Vec<Expr>,
399 pos: Pos,
400 span: Span,
401 },
402 Observer {
403 parties: Vec<Expr>,
404 pos: Pos,
405 span: Span,
406 },
407 Ensure {
408 expr: Expr,
409 pos: Pos,
410 span: Span,
411 },
412 Key {
413 expr: Expr,
414 ty: Option<Type>,
416 pos: Pos,
417 span: Span,
418 },
419 Maintainer {
420 expr: Expr,
421 pos: Pos,
422 span: Span,
423 },
424 Choice(ChoiceDecl),
425 InterfaceInstance(InterfaceInstanceDecl),
426 Other {
428 raw: String,
429 pos: Pos,
430 span: Span,
431 },
432}
433
434#[derive(Debug, Clone)]
435pub struct InterfaceInstanceDecl {
436 pub interface_name: String,
438 pub for_template: String,
441 pub methods: Vec<Binding>,
443 pub pos: Pos,
444 pub span: Span,
445}
446
447#[derive(Debug, Clone)]
448pub struct TemplateDecl {
449 pub name: String,
450 pub fields: Vec<FieldDecl>,
451 pub body: Vec<TemplateBodyDecl>,
452 pub pos: Pos,
453 pub span: Span,
454}
455
456#[derive(Debug, Clone)]
457pub struct InterfaceDecl {
458 pub name: String,
459 pub requires: Vec<String>,
461 pub viewtype: Option<String>,
462 pub methods: Vec<FieldDecl>,
464 pub choices: Vec<ChoiceDecl>,
465 pub pos: Pos,
466 pub span: Span,
467}
468
469#[derive(Debug, Clone)]
470pub struct Equation {
471 pub params: Vec<Pat>,
472 pub body: Expr,
473 pub guards: Vec<(Expr, Expr)>,
476 pub where_bindings: Vec<Binding>,
478 pub pos: Pos,
479 pub span: Span,
480}
481
482#[derive(Debug, Clone)]
483pub struct FunctionDecl {
484 pub name: String,
485 pub ty: Option<Type>,
486 pub equations: Vec<Equation>,
487 pub pos: Pos,
488 pub span: Span,
492 pub sig_span: Option<Span>,
494}
495
496#[derive(Debug, Clone)]
497pub struct ImportDecl {
498 pub module_name: String,
499 pub qualified: bool,
500 pub alias: Option<String>,
501 pub pos: Pos,
502 pub span: Span,
503}
504
505#[derive(Debug, Clone)]
506pub enum Decl {
507 Template(TemplateDecl),
508 Interface(InterfaceDecl),
509 Function(FunctionDecl),
510 TypeDef {
512 keyword: String,
513 name: String,
514 pos: Pos,
515 span: Span,
516 },
517 Unknown {
519 raw: String,
520 pos: Pos,
521 span: Span,
522 },
523}
524
525#[derive(Debug, Clone)]
526pub struct Module {
527 pub name: String,
528 pub pos: Pos,
529 pub span: Span,
531 pub header: Span,
535 pub imports: Vec<ImportDecl>,
536 pub decls: Vec<Decl>,
537}
538
539#[derive(Debug, Clone, Copy, PartialEq, Eq)]
545pub enum DiagnosticCategory {
546 SkippedDecl,
548 Malformed,
551 UnsupportedSyntax,
554 RecursionLimit,
557 Lex,
559}
560
561impl DiagnosticCategory {
562 pub const fn as_str(self) -> &'static str {
564 match self {
565 Self::SkippedDecl => "skipped-declaration",
566 Self::Malformed => "malformed",
567 Self::UnsupportedSyntax => "unsupported-syntax",
568 Self::RecursionLimit => "recursion-limit",
569 Self::Lex => "lexical-error",
570 }
571 }
572}
573
574#[derive(Debug, Clone)]
576pub struct ParseDiagnostic {
577 pub message: String,
578 pub pos: Pos,
579 pub span: Span,
583 pub category: DiagnosticCategory,
584}
585
586impl Expr {
587 pub const fn pos(&self) -> Pos {
588 match self {
589 Self::Var { pos, .. }
590 | Self::Con { pos, .. }
591 | Self::Lit { pos, .. }
592 | Self::App { pos, .. }
593 | Self::BinOp { pos, .. }
594 | Self::Neg { pos, .. }
595 | Self::Lambda { pos, .. }
596 | Self::If { pos, .. }
597 | Self::Case { pos, .. }
598 | Self::Do { pos, .. }
599 | Self::LetIn { pos, .. }
600 | Self::Record { pos, .. }
601 | Self::Tuple { pos, .. }
602 | Self::List { pos, .. }
603 | Self::Try { pos, .. }
604 | Self::Section { pos, .. }
605 | Self::Error { pos, .. } => *pos,
606 }
607 }
608
609 pub const fn span(&self) -> Span {
611 match self {
612 Self::Var { span, .. }
613 | Self::Con { span, .. }
614 | Self::Lit { span, .. }
615 | Self::App { span, .. }
616 | Self::BinOp { span, .. }
617 | Self::Neg { span, .. }
618 | Self::Lambda { span, .. }
619 | Self::If { span, .. }
620 | Self::Case { span, .. }
621 | Self::Do { span, .. }
622 | Self::LetIn { span, .. }
623 | Self::Record { span, .. }
624 | Self::Tuple { span, .. }
625 | Self::List { span, .. }
626 | Self::Try { span, .. }
627 | Self::Section { span, .. }
628 | Self::Error { span, .. } => *span,
629 }
630 }
631
632 pub fn render(&self) -> String {
642 match self {
643 Self::Var {
644 qualifier, name, ..
645 }
646 | Self::Con {
647 qualifier, name, ..
648 } => qualifier
649 .as_ref()
650 .map_or_else(|| name.clone(), |q| format!("{q}.{name}")),
651 Self::Lit { kind, text, .. } => match kind {
652 LitKind::Text => format!("{text:?}"),
653 LitKind::Char => format!("'{text}'"),
654 _ => text.clone(),
655 },
656 Self::App { func, args, .. } => {
657 let mut s = func.render_atomic();
658 for a in args {
659 s.push(' ');
660 s.push_str(&a.render_atomic());
661 }
662 s
663 }
664 Self::BinOp { op, lhs, rhs, .. } => {
665 if op == "." {
666 format!("{}.{}", lhs.render_atomic(), rhs.render_atomic())
668 } else {
669 format!("{} {} {}", lhs.render_atomic(), op, rhs.render_atomic())
670 }
671 }
672 Self::Neg { expr, .. } => format!("-{}", expr.render_atomic()),
673 Self::Lambda { params, body, .. } => {
674 let ps: Vec<String> = params.iter().map(|p| p.render()).collect();
675 format!("\\{} -> {}", ps.join(" "), body.render())
676 }
677 Self::If {
678 cond,
679 then_branch,
680 else_branch,
681 ..
682 } => format!(
683 "if {} then {} else {}",
684 cond.render(),
685 then_branch.render(),
686 else_branch.render()
687 ),
688 Self::Case {
689 scrutinee, alts, ..
690 } => {
691 let arms: Vec<String> = alts
692 .iter()
693 .map(|a| format!("{} -> {}", a.pat.render(), a.body.render()))
694 .collect();
695 format!("case {} of {}", scrutinee.render(), arms.join("; "))
696 }
697 Self::Do { stmts, .. } => {
698 let body: Vec<String> = stmts.iter().map(render_do_stmt).collect();
699 format!("do {}", body.join("; "))
700 }
701 Self::LetIn { bindings, body, .. } => {
702 let bs: Vec<String> = bindings.iter().map(render_binding).collect();
703 format!("let {} in {}", bs.join("; "), body.render())
704 }
705 Self::Record { base, fields, .. } => {
706 let fs: Vec<String> = fields
707 .iter()
708 .map(|f| {
709 f.value.as_ref().map_or_else(
710 || f.name.clone(),
711 |v| format!("{} = {}", f.name, v.render()),
712 )
713 })
714 .collect();
715 format!("{} with {}", base.render_atomic(), fs.join("; "))
716 }
717 Self::Tuple { items, .. } => {
718 let xs: Vec<String> = items.iter().map(|e| e.render()).collect();
719 format!("({})", xs.join(", "))
720 }
721 Self::List { items, .. } => {
722 let xs: Vec<String> = items.iter().map(|e| e.render()).collect();
723 format!("[{}]", xs.join(", "))
724 }
725 Self::Try { body, handlers, .. } => {
726 let hs: Vec<String> = handlers
727 .iter()
728 .map(|a| format!("{} -> {}", a.pat.render(), a.body.render()))
729 .collect();
730 format!("try {} catch {}", body.render(), hs.join("; "))
731 }
732 Self::Section {
733 op, operand, left, ..
734 } => match (operand, left) {
735 (Some(e), true) => format!("({} {})", e.render(), op),
736 (Some(e), false) => format!("({} {})", op, e.render()),
737 (None, _) => format!("({op})"),
738 },
739 Self::Error { raw, .. } => raw.clone(),
740 }
741 }
742
743 fn render_atomic(&self) -> String {
746 match self {
747 Self::Var { .. }
748 | Self::Con { .. }
749 | Self::Lit { .. }
750 | Self::Tuple { .. }
751 | Self::List { .. }
752 | Self::Section { .. }
753 | Self::Error { .. } => self.render(),
754 _ => format!("({})", self.render()),
755 }
756 }
757
758 pub fn application_head(&self) -> &Self {
761 match self {
762 Self::App { func, .. } => func.application_head(),
763 _ => self,
764 }
765 }
766
767 pub fn application_args(&self) -> &[Self] {
771 match self {
772 Self::App { args, .. } => args,
773 _ => &[],
774 }
775 }
776}
777
778fn render_do_stmt(s: &DoStmt) -> String {
779 match s {
780 DoStmt::Bind { pat, expr, .. } => format!("{} <- {}", pat.render(), expr.render()),
781 DoStmt::Let { bindings, .. } => {
782 let bs: Vec<String> = bindings.iter().map(render_binding).collect();
783 format!("let {}", bs.join("; "))
784 }
785 DoStmt::Expr { expr, .. } => expr.render(),
786 }
787}
788
789fn render_binding(b: &Binding) -> String {
790 let mut s = b.pat.render();
791 for p in &b.params {
792 s.push(' ');
793 s.push_str(&p.render());
794 }
795 format!("{} = {}", s, b.expr.render())
796}
797
798impl Pat {
799 pub const fn pos(&self) -> Pos {
800 match self {
801 Self::Var { pos, .. }
802 | Self::Wild { pos, .. }
803 | Self::Con { pos, .. }
804 | Self::Tuple { pos, .. }
805 | Self::List { pos, .. }
806 | Self::Lit { pos, .. }
807 | Self::As { pos, .. }
808 | Self::Other { pos, .. } => *pos,
809 }
810 }
811
812 pub const fn span(&self) -> Span {
814 match self {
815 Self::Var { span, .. }
816 | Self::Wild { span, .. }
817 | Self::Con { span, .. }
818 | Self::Tuple { span, .. }
819 | Self::List { span, .. }
820 | Self::Lit { span, .. }
821 | Self::As { span, .. }
822 | Self::Other { span, .. } => *span,
823 }
824 }
825
826 pub fn render(&self) -> String {
830 match self {
831 Self::Var { name, .. } => name.clone(),
832 Self::Wild { .. } => "_".to_string(),
833 Self::Con {
834 qualifier,
835 name,
836 args,
837 ..
838 } => {
839 let head = qualifier
840 .as_ref()
841 .map_or_else(|| name.clone(), |q| format!("{q}.{name}"));
842 if args.is_empty() {
843 head
844 } else {
845 let parts: Vec<String> = args.iter().map(|p| p.render()).collect();
846 format!("({} {})", head, parts.join(" "))
847 }
848 }
849 Self::Tuple { items, .. } => {
850 let xs: Vec<String> = items.iter().map(|p| p.render()).collect();
851 format!("({})", xs.join(", "))
852 }
853 Self::List { items, .. } => {
854 let xs: Vec<String> = items.iter().map(|p| p.render()).collect();
855 format!("[{}]", xs.join(", "))
856 }
857 Self::Lit { kind, text, .. } => match kind {
858 LitKind::Text => format!("{text:?}"),
859 LitKind::Char => format!("'{text}'"),
860 _ => text.clone(),
861 },
862 Self::As { name, pat, .. } => format!("{}@{}", name, pat.render()),
863 Self::Other { raw, .. } => raw.clone(),
864 }
865 }
866}
867
868#[cfg(test)]
869mod tests {
870 use super::*;
871
872 fn pos() -> Pos {
873 Pos { line: 1, column: 1 }
874 }
875
876 fn span(start: usize, end: usize) -> Span {
877 Span::new(start, end)
878 }
879
880 #[test]
881 fn span_distinguishes_empty_from_invalid() {
882 assert!(span(3, 3).is_valid());
883 assert!(span(3, 3).is_empty());
884
885 assert!(!span(4, 3).is_valid());
886 assert!(!span(4, 3).is_empty());
887 }
888
889 #[test]
890 fn contains_rejects_invalid_spans() {
891 let parent = span(1, 10);
892
893 assert!(parent.contains(&span(3, 7)));
894 assert!(!parent.contains(&span(7, 3)));
895 assert!(!span(10, 1).contains(&span(3, 7)));
896 }
897
898 #[test]
899 fn expr_render_keeps_normalized_application_and_projection_shape() {
900 let projection = Expr::BinOp {
901 op: ".".to_string(),
902 lhs: Box::new(Expr::Var {
903 qualifier: None,
904 name: "this".to_string(),
905 pos: pos(),
906 span: span(0, 4),
907 }),
908 rhs: Box::new(Expr::Var {
909 qualifier: None,
910 name: "note".to_string(),
911 pos: pos(),
912 span: span(5, 9),
913 }),
914 pos: pos(),
915 span: span(0, 9),
916 };
917
918 let expr = Expr::App {
919 func: Box::new(Expr::Var {
920 qualifier: None,
921 name: "length".to_string(),
922 pos: pos(),
923 span: span(0, 6),
924 }),
925 args: vec![projection],
926 pos: pos(),
927 span: span(0, 16),
928 };
929
930 assert_eq!(expr.render(), "length (this.note)");
931 }
932
933 #[test]
934 fn pat_render_preserves_collection_shape() {
935 let pat = Pat::Tuple {
936 items: vec![
937 Pat::Var {
938 name: "owner".to_string(),
939 pos: pos(),
940 span: span(1, 6),
941 },
942 Pat::List {
943 items: Vec::new(),
944 pos: pos(),
945 span: span(8, 10),
946 },
947 ],
948 pos: pos(),
949 span: span(0, 11),
950 };
951
952 assert_eq!(pat.render(), "(owner, [])");
953 }
954}