1pub use bock_errors::{FileId, Span};
8
9pub mod visitor;
10
11pub type NodeId = u32;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct Ident {
21 pub name: String,
22 pub span: Span,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct TypePath {
28 pub segments: Vec<Ident>,
29 pub span: Span,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct ModulePath {
35 pub segments: Vec<Ident>,
36 pub span: Span,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
43pub enum Visibility {
44 #[default]
46 Private,
47 Internal,
49 Public,
51}
52
53#[derive(Debug, Clone, PartialEq)]
57pub struct AnnotationArg {
58 pub label: Option<Ident>,
59 pub value: Expr,
60}
61
62#[derive(Debug, Clone, PartialEq)]
65pub struct Annotation {
66 pub id: NodeId,
67 pub span: Span,
68 pub name: Ident,
69 pub args: Vec<AnnotationArg>,
70}
71
72#[derive(Debug, Clone, PartialEq)]
76pub struct GenericParam {
77 pub id: NodeId,
78 pub span: Span,
79 pub name: Ident,
80 pub bounds: Vec<TypePath>,
81}
82
83#[derive(Debug, Clone, PartialEq)]
85pub struct TypeConstraint {
86 pub id: NodeId,
87 pub span: Span,
88 pub param: Ident,
89 pub bounds: Vec<TypePath>,
90}
91
92#[derive(Debug, Clone, PartialEq)]
96pub enum TypeExpr {
97 Named {
99 id: NodeId,
100 span: Span,
101 path: TypePath,
102 args: Vec<TypeExpr>,
103 },
104 Tuple {
106 id: NodeId,
107 span: Span,
108 elems: Vec<TypeExpr>,
109 },
110 Function {
112 id: NodeId,
113 span: Span,
114 params: Vec<TypeExpr>,
115 ret: Box<TypeExpr>,
116 effects: Vec<TypePath>,
118 },
119 Optional {
121 id: NodeId,
122 span: Span,
123 inner: Box<TypeExpr>,
124 },
125 SelfType { id: NodeId, span: Span },
127}
128
129impl TypeExpr {
130 #[must_use]
132 pub fn node_id(&self) -> NodeId {
133 match self {
134 TypeExpr::Named { id, .. }
135 | TypeExpr::Tuple { id, .. }
136 | TypeExpr::Function { id, .. }
137 | TypeExpr::Optional { id, .. }
138 | TypeExpr::SelfType { id, .. } => *id,
139 }
140 }
141
142 #[must_use]
144 pub fn span(&self) -> Span {
145 match self {
146 TypeExpr::Named { span, .. }
147 | TypeExpr::Tuple { span, .. }
148 | TypeExpr::Function { span, .. }
149 | TypeExpr::Optional { span, .. }
150 | TypeExpr::SelfType { span, .. } => *span,
151 }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq)]
159pub enum Literal {
160 Int(String),
162 Float(String),
164 Bool(bool),
166 Char(String),
168 String(String),
170 Unit,
172}
173
174const TYPE_SUFFIXES: &[&str] = &[
176 "i128", "i64", "i32", "i16", "i8", "u64", "u32", "u16", "u8", "f64", "f32",
177];
178
179#[must_use]
184pub fn strip_type_suffix(s: &str) -> (&str, Option<&str>) {
185 for suffix in TYPE_SUFFIXES {
186 let with_underscore_len = 1 + suffix.len();
188 if s.len() > with_underscore_len {
189 let split = s.len() - with_underscore_len;
190 if s.as_bytes()[split] == b'_' && &s[split + 1..] == *suffix {
191 return (&s[..split], Some(suffix));
192 }
193 }
194 }
195 (s, None)
196}
197
198#[derive(Debug, Clone, PartialEq)]
202pub enum Pattern {
203 Wildcard { id: NodeId, span: Span },
205 Bind { id: NodeId, span: Span, name: Ident },
207 MutBind { id: NodeId, span: Span, name: Ident },
209 Literal {
211 id: NodeId,
212 span: Span,
213 lit: Literal,
214 },
215 Constructor {
217 id: NodeId,
218 span: Span,
219 path: TypePath,
220 fields: Vec<Pattern>,
221 },
222 Record {
224 id: NodeId,
225 span: Span,
226 path: TypePath,
227 fields: Vec<RecordPatternField>,
228 rest: bool,
230 },
231 Tuple {
233 id: NodeId,
234 span: Span,
235 elems: Vec<Pattern>,
236 },
237 List {
239 id: NodeId,
240 span: Span,
241 elems: Vec<Pattern>,
242 rest: Option<Box<Pattern>>,
243 },
244 Or {
246 id: NodeId,
247 span: Span,
248 alternatives: Vec<Pattern>,
249 },
250 Range {
252 id: NodeId,
253 span: Span,
254 lo: Box<Pattern>,
255 hi: Box<Pattern>,
256 inclusive: bool,
257 },
258 Rest { id: NodeId, span: Span },
260}
261
262impl Pattern {
263 #[must_use]
265 pub fn node_id(&self) -> NodeId {
266 match self {
267 Pattern::Wildcard { id, .. }
268 | Pattern::Bind { id, .. }
269 | Pattern::MutBind { id, .. }
270 | Pattern::Literal { id, .. }
271 | Pattern::Constructor { id, .. }
272 | Pattern::Record { id, .. }
273 | Pattern::Tuple { id, .. }
274 | Pattern::List { id, .. }
275 | Pattern::Or { id, .. }
276 | Pattern::Range { id, .. }
277 | Pattern::Rest { id, .. } => *id,
278 }
279 }
280
281 #[must_use]
283 pub fn span(&self) -> Span {
284 match self {
285 Pattern::Wildcard { span, .. }
286 | Pattern::Bind { span, .. }
287 | Pattern::MutBind { span, .. }
288 | Pattern::Literal { span, .. }
289 | Pattern::Constructor { span, .. }
290 | Pattern::Record { span, .. }
291 | Pattern::Tuple { span, .. }
292 | Pattern::List { span, .. }
293 | Pattern::Or { span, .. }
294 | Pattern::Range { span, .. }
295 | Pattern::Rest { span, .. } => *span,
296 }
297 }
298}
299
300#[derive(Debug, Clone, PartialEq)]
302pub struct RecordPatternField {
303 pub span: Span,
304 pub name: Ident,
305 pub pattern: Option<Pattern>,
307}
308
309#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
313pub enum BinOp {
314 Add,
316 Sub,
317 Mul,
318 Div,
319 Rem,
320 Pow,
321 Eq,
323 Ne,
324 Lt,
325 Le,
326 Gt,
327 Ge,
328 And,
330 Or,
331 BitAnd,
333 BitOr,
334 BitXor,
335 Compose, Is,
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
343pub enum UnaryOp {
344 Neg,
345 Not,
346 BitNot,
348}
349
350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
352pub enum AssignOp {
353 Assign,
354 AddAssign,
355 SubAssign,
356 MulAssign,
357 DivAssign,
358 RemAssign,
359}
360
361#[derive(Debug, Clone, PartialEq)]
363pub struct Arg {
364 pub span: Span,
365 pub label: Option<Ident>,
366 pub mutable: bool,
368 pub value: Expr,
369}
370
371#[derive(Debug, Clone, PartialEq)]
373pub struct RecordField {
374 pub span: Span,
375 pub name: Ident,
376 pub value: Option<Expr>,
378}
379
380#[derive(Debug, Clone, PartialEq)]
382pub struct RecordSpread {
383 pub span: Span,
384 pub expr: Expr,
385}
386
387#[derive(Debug, Clone, PartialEq)]
389pub struct MatchArm {
390 pub id: NodeId,
391 pub span: Span,
392 pub pattern: Pattern,
393 pub guard: Option<Expr>,
394 pub body: Expr,
395}
396
397#[derive(Debug, Clone, PartialEq)]
399pub struct PropertyBinding {
400 pub span: Span,
401 pub name: Ident,
402 pub ty: TypeExpr,
403}
404
405#[derive(Debug, Clone, PartialEq)]
407pub struct HandlerPair {
408 pub span: Span,
409 pub effect: TypePath,
410 pub handler: Expr,
411}
412
413#[derive(Debug, Clone, PartialEq)]
415pub enum Expr {
416 Literal {
418 id: NodeId,
419 span: Span,
420 lit: Literal,
421 },
422
423 Identifier { id: NodeId, span: Span, name: Ident },
425
426 Binary {
428 id: NodeId,
429 span: Span,
430 op: BinOp,
431 left: Box<Expr>,
432 right: Box<Expr>,
433 },
434
435 Unary {
437 id: NodeId,
438 span: Span,
439 op: UnaryOp,
440 operand: Box<Expr>,
441 },
442
443 Assign {
445 id: NodeId,
446 span: Span,
447 op: AssignOp,
448 target: Box<Expr>,
449 value: Box<Expr>,
450 },
451
452 Call {
454 id: NodeId,
455 span: Span,
456 callee: Box<Expr>,
457 args: Vec<Arg>,
458 type_args: Vec<TypeExpr>,
459 },
460
461 MethodCall {
463 id: NodeId,
464 span: Span,
465 receiver: Box<Expr>,
466 method: Ident,
467 type_args: Vec<TypeExpr>,
468 args: Vec<Arg>,
469 },
470
471 FieldAccess {
473 id: NodeId,
474 span: Span,
475 object: Box<Expr>,
476 field: Ident,
477 },
478
479 Index {
481 id: NodeId,
482 span: Span,
483 object: Box<Expr>,
484 index: Box<Expr>,
485 },
486
487 Try {
489 id: NodeId,
490 span: Span,
491 expr: Box<Expr>,
492 },
493
494 Lambda {
496 id: NodeId,
497 span: Span,
498 params: Vec<Param>,
499 body: Box<Expr>,
500 },
501
502 Pipe {
504 id: NodeId,
505 span: Span,
506 left: Box<Expr>,
507 right: Box<Expr>,
508 },
509
510 Compose {
512 id: NodeId,
513 span: Span,
514 left: Box<Expr>,
515 right: Box<Expr>,
516 },
517
518 If {
520 id: NodeId,
521 span: Span,
522 let_pattern: Option<Pattern>,
524 condition: Box<Expr>,
525 then_block: Block,
526 else_block: Option<Box<Expr>>,
527 },
528
529 Match {
531 id: NodeId,
532 span: Span,
533 scrutinee: Box<Expr>,
534 arms: Vec<MatchArm>,
535 },
536
537 Loop { id: NodeId, span: Span, body: Block },
539
540 Block {
542 id: NodeId,
543 span: Span,
544 block: Block,
545 },
546
547 RecordConstruct {
549 id: NodeId,
550 span: Span,
551 path: TypePath,
552 fields: Vec<RecordField>,
553 spread: Option<Box<RecordSpread>>,
554 },
555
556 ListLiteral {
558 id: NodeId,
559 span: Span,
560 elems: Vec<Expr>,
561 },
562
563 MapLiteral {
565 id: NodeId,
566 span: Span,
567 entries: Vec<(Expr, Expr)>,
568 },
569
570 SetLiteral {
572 id: NodeId,
573 span: Span,
574 elems: Vec<Expr>,
575 },
576
577 TupleLiteral {
579 id: NodeId,
580 span: Span,
581 elems: Vec<Expr>,
582 },
583
584 Range {
586 id: NodeId,
587 span: Span,
588 lo: Box<Expr>,
589 hi: Box<Expr>,
590 inclusive: bool,
591 },
592
593 Await {
595 id: NodeId,
596 span: Span,
597 expr: Box<Expr>,
598 },
599
600 Return {
602 id: NodeId,
603 span: Span,
604 value: Option<Box<Expr>>,
605 },
606
607 Break {
609 id: NodeId,
610 span: Span,
611 value: Option<Box<Expr>>,
612 },
613
614 Continue { id: NodeId, span: Span },
616
617 Unreachable { id: NodeId, span: Span },
619
620 Interpolation {
622 id: NodeId,
623 span: Span,
624 parts: Vec<InterpolationPart>,
625 },
626
627 Placeholder { id: NodeId, span: Span },
629
630 Is {
635 id: NodeId,
636 span: Span,
637 expr: Box<Expr>,
638 type_expr: TypeExpr,
639 },
640}
641
642impl Expr {
643 #[must_use]
645 pub fn node_id(&self) -> NodeId {
646 match self {
647 Expr::Literal { id, .. }
648 | Expr::Identifier { id, .. }
649 | Expr::Binary { id, .. }
650 | Expr::Unary { id, .. }
651 | Expr::Assign { id, .. }
652 | Expr::Call { id, .. }
653 | Expr::MethodCall { id, .. }
654 | Expr::FieldAccess { id, .. }
655 | Expr::Index { id, .. }
656 | Expr::Try { id, .. }
657 | Expr::Lambda { id, .. }
658 | Expr::Pipe { id, .. }
659 | Expr::Compose { id, .. }
660 | Expr::If { id, .. }
661 | Expr::Match { id, .. }
662 | Expr::Loop { id, .. }
663 | Expr::Block { id, .. }
664 | Expr::RecordConstruct { id, .. }
665 | Expr::ListLiteral { id, .. }
666 | Expr::MapLiteral { id, .. }
667 | Expr::SetLiteral { id, .. }
668 | Expr::TupleLiteral { id, .. }
669 | Expr::Range { id, .. }
670 | Expr::Await { id, .. }
671 | Expr::Return { id, .. }
672 | Expr::Break { id, .. }
673 | Expr::Continue { id, .. }
674 | Expr::Unreachable { id, .. }
675 | Expr::Interpolation { id, .. }
676 | Expr::Placeholder { id, .. }
677 | Expr::Is { id, .. } => *id,
678 }
679 }
680
681 #[must_use]
683 pub fn span(&self) -> Span {
684 match self {
685 Expr::Literal { span, .. }
686 | Expr::Identifier { span, .. }
687 | Expr::Binary { span, .. }
688 | Expr::Unary { span, .. }
689 | Expr::Assign { span, .. }
690 | Expr::Call { span, .. }
691 | Expr::MethodCall { span, .. }
692 | Expr::FieldAccess { span, .. }
693 | Expr::Index { span, .. }
694 | Expr::Try { span, .. }
695 | Expr::Lambda { span, .. }
696 | Expr::Pipe { span, .. }
697 | Expr::Compose { span, .. }
698 | Expr::If { span, .. }
699 | Expr::Match { span, .. }
700 | Expr::Loop { span, .. }
701 | Expr::Block { span, .. }
702 | Expr::RecordConstruct { span, .. }
703 | Expr::ListLiteral { span, .. }
704 | Expr::MapLiteral { span, .. }
705 | Expr::SetLiteral { span, .. }
706 | Expr::TupleLiteral { span, .. }
707 | Expr::Range { span, .. }
708 | Expr::Await { span, .. }
709 | Expr::Return { span, .. }
710 | Expr::Break { span, .. }
711 | Expr::Continue { span, .. }
712 | Expr::Unreachable { span, .. }
713 | Expr::Interpolation { span, .. }
714 | Expr::Placeholder { span, .. }
715 | Expr::Is { span, .. } => *span,
716 }
717 }
718}
719
720#[derive(Debug, Clone, PartialEq)]
722pub enum InterpolationPart {
723 Literal(String),
725 Expr(Expr),
727}
728
729#[derive(Debug, Clone, PartialEq)]
733pub enum Stmt {
734 Let(LetStmt),
736 Expr(Expr),
738 For(ForLoop),
740 While(WhileLoop),
742 Loop(LoopStmt),
744 Guard(GuardStmt),
746 Handling(HandlingBlock),
748 Empty,
750}
751
752#[derive(Debug, Clone, PartialEq)]
754pub struct Block {
755 pub id: NodeId,
756 pub span: Span,
757 pub stmts: Vec<Stmt>,
758 pub tail: Option<Box<Expr>>,
760}
761
762#[derive(Debug, Clone, PartialEq)]
764pub struct LetStmt {
765 pub id: NodeId,
766 pub span: Span,
767 pub pattern: Pattern,
768 pub ty: Option<TypeExpr>,
769 pub value: Expr,
770}
771
772#[derive(Debug, Clone, PartialEq)]
774pub struct ForLoop {
775 pub id: NodeId,
776 pub span: Span,
777 pub pattern: Pattern,
778 pub iterable: Expr,
779 pub body: Block,
780}
781
782#[derive(Debug, Clone, PartialEq)]
784pub struct WhileLoop {
785 pub id: NodeId,
786 pub span: Span,
787 pub condition: Expr,
788 pub body: Block,
789}
790
791#[derive(Debug, Clone, PartialEq)]
793pub struct LoopStmt {
794 pub id: NodeId,
795 pub span: Span,
796 pub body: Block,
797}
798
799#[derive(Debug, Clone, PartialEq)]
803pub struct GuardStmt {
804 pub id: NodeId,
805 pub span: Span,
806 pub let_pattern: Option<Pattern>,
808 pub condition: Expr,
809 pub else_block: Block,
810}
811
812#[derive(Debug, Clone, PartialEq)]
814pub struct HandlingBlock {
815 pub id: NodeId,
816 pub span: Span,
817 pub handlers: Vec<HandlerPair>,
818 pub body: Block,
819}
820
821#[derive(Debug, Clone, PartialEq)]
825pub struct Param {
826 pub id: NodeId,
827 pub span: Span,
828 pub pattern: Pattern,
829 pub ty: Option<TypeExpr>,
830 pub default: Option<Expr>,
832}
833
834#[derive(Debug, Clone, PartialEq)]
838pub struct FnDecl {
839 pub id: NodeId,
840 pub span: Span,
841 pub annotations: Vec<Annotation>,
842 pub visibility: Visibility,
843 pub is_async: bool,
844 pub name: Ident,
845 pub generic_params: Vec<GenericParam>,
846 pub params: Vec<Param>,
847 pub return_type: Option<TypeExpr>,
848 pub effect_clause: Vec<TypePath>,
850 pub where_clause: Vec<TypeConstraint>,
851 pub body: Option<Block>,
853}
854
855#[derive(Debug, Clone, PartialEq)]
857pub struct RecordDecl {
858 pub id: NodeId,
859 pub span: Span,
860 pub annotations: Vec<Annotation>,
861 pub visibility: Visibility,
862 pub name: Ident,
863 pub generic_params: Vec<GenericParam>,
864 pub where_clause: Vec<TypeConstraint>,
865 pub fields: Vec<RecordDeclField>,
866}
867
868#[derive(Debug, Clone, PartialEq)]
870pub struct RecordDeclField {
871 pub id: NodeId,
872 pub span: Span,
873 pub name: Ident,
874 pub ty: TypeExpr,
875 pub default: Option<Expr>,
876}
877
878#[derive(Debug, Clone, PartialEq)]
880pub struct EnumDecl {
881 pub id: NodeId,
882 pub span: Span,
883 pub annotations: Vec<Annotation>,
884 pub visibility: Visibility,
885 pub name: Ident,
886 pub generic_params: Vec<GenericParam>,
887 pub where_clause: Vec<TypeConstraint>,
888 pub variants: Vec<EnumVariant>,
889}
890
891#[derive(Debug, Clone, PartialEq)]
893pub enum EnumVariant {
894 Unit { id: NodeId, span: Span, name: Ident },
896 Struct {
898 id: NodeId,
899 span: Span,
900 name: Ident,
901 fields: Vec<RecordDeclField>,
902 },
903 Tuple {
905 id: NodeId,
906 span: Span,
907 name: Ident,
908 tys: Vec<TypeExpr>,
909 },
910}
911
912#[derive(Debug, Clone, PartialEq)]
914pub struct ClassDecl {
915 pub id: NodeId,
916 pub span: Span,
917 pub annotations: Vec<Annotation>,
918 pub visibility: Visibility,
919 pub name: Ident,
920 pub generic_params: Vec<GenericParam>,
921 pub base: Option<TypePath>,
923 pub traits: Vec<TypePath>,
925 pub where_clause: Vec<TypeConstraint>,
926 pub fields: Vec<RecordDeclField>,
927 pub methods: Vec<FnDecl>,
928}
929
930#[derive(Debug, Clone, PartialEq)]
932pub struct TraitDecl {
933 pub id: NodeId,
934 pub span: Span,
935 pub annotations: Vec<Annotation>,
936 pub visibility: Visibility,
937 pub is_platform: bool,
938 pub name: Ident,
939 pub generic_params: Vec<GenericParam>,
940 pub supertraits: Vec<TypePath>,
942 pub associated_types: Vec<AssociatedType>,
943 pub methods: Vec<FnDecl>,
944}
945
946#[derive(Debug, Clone, PartialEq)]
948pub struct AssociatedType {
949 pub id: NodeId,
950 pub span: Span,
951 pub name: Ident,
952 pub bounds: Vec<TypePath>,
953}
954
955#[derive(Debug, Clone, PartialEq)]
957pub struct TypeAssignment {
958 pub id: NodeId,
959 pub span: Span,
960 pub name: Ident,
961 pub type_expr: TypeExpr,
962}
963
964#[derive(Debug, Clone, PartialEq)]
966pub struct ImplBlock {
967 pub id: NodeId,
968 pub span: Span,
969 pub annotations: Vec<Annotation>,
970 pub generic_params: Vec<GenericParam>,
971 pub trait_path: Option<TypePath>,
973 pub trait_args: Vec<TypeExpr>,
976 pub target: TypeExpr,
978 pub where_clause: Vec<TypeConstraint>,
979 pub type_assignments: Vec<TypeAssignment>,
981 pub methods: Vec<FnDecl>,
982}
983
984#[derive(Debug, Clone, PartialEq)]
986pub struct EffectDecl {
987 pub id: NodeId,
988 pub span: Span,
989 pub annotations: Vec<Annotation>,
990 pub visibility: Visibility,
991 pub name: Ident,
992 pub generic_params: Vec<GenericParam>,
993 pub components: Vec<TypePath>,
995 pub operations: Vec<FnDecl>,
996}
997
998#[derive(Debug, Clone, PartialEq)]
1000pub struct TypeAliasDecl {
1001 pub id: NodeId,
1002 pub span: Span,
1003 pub annotations: Vec<Annotation>,
1004 pub visibility: Visibility,
1005 pub name: Ident,
1006 pub generic_params: Vec<GenericParam>,
1007 pub ty: TypeExpr,
1008 pub where_clause: Vec<TypeConstraint>,
1009}
1010
1011#[derive(Debug, Clone, PartialEq)]
1013pub struct ConstDecl {
1014 pub id: NodeId,
1015 pub span: Span,
1016 pub annotations: Vec<Annotation>,
1017 pub visibility: Visibility,
1018 pub name: Ident,
1019 pub ty: TypeExpr,
1020 pub value: Expr,
1021}
1022
1023#[derive(Debug, Clone, PartialEq)]
1025pub struct ModuleHandleDecl {
1026 pub id: NodeId,
1027 pub span: Span,
1028 pub effect: TypePath,
1030 pub handler: Expr,
1032}
1033
1034#[derive(Debug, Clone, PartialEq)]
1036pub struct PropertyTestDecl {
1037 pub id: NodeId,
1038 pub span: Span,
1039 pub name: String,
1041 pub bindings: Vec<PropertyBinding>,
1043 pub body: Block,
1044}
1045
1046#[derive(Debug, Clone, PartialEq)]
1050pub struct ImportDecl {
1051 pub id: NodeId,
1052 pub span: Span,
1053 pub visibility: Visibility,
1054 pub path: ModulePath,
1055 pub items: ImportItems,
1056}
1057
1058#[derive(Debug, Clone, PartialEq)]
1060pub enum ImportItems {
1061 Module,
1063 Named(Vec<ImportedName>),
1065 Glob,
1067}
1068
1069#[derive(Debug, Clone, PartialEq)]
1071pub struct ImportedName {
1072 pub span: Span,
1073 pub name: Ident,
1074 pub alias: Option<Ident>,
1076}
1077
1078#[derive(Debug, Clone, PartialEq)]
1082pub enum Item {
1083 Fn(FnDecl),
1084 Record(RecordDecl),
1085 Enum(EnumDecl),
1086 Class(ClassDecl),
1087 Trait(TraitDecl),
1088 PlatformTrait(TraitDecl),
1089 Impl(ImplBlock),
1090 Effect(EffectDecl),
1091 TypeAlias(TypeAliasDecl),
1092 Const(ConstDecl),
1093 ModuleHandle(ModuleHandleDecl),
1095 PropertyTest(PropertyTestDecl),
1097 Error {
1099 id: NodeId,
1100 span: Span,
1101 },
1102}
1103
1104impl Item {
1105 #[must_use]
1107 pub fn span(&self) -> Span {
1108 match self {
1109 Item::Fn(d) => d.span,
1110 Item::Record(d) => d.span,
1111 Item::Enum(d) => d.span,
1112 Item::Class(d) => d.span,
1113 Item::Trait(d) | Item::PlatformTrait(d) => d.span,
1114 Item::Impl(d) => d.span,
1115 Item::Effect(d) => d.span,
1116 Item::TypeAlias(d) => d.span,
1117 Item::Const(d) => d.span,
1118 Item::ModuleHandle(d) => d.span,
1119 Item::PropertyTest(d) => d.span,
1120 Item::Error { span, .. } => *span,
1121 }
1122 }
1123}
1124
1125#[derive(Debug, Clone, PartialEq)]
1129pub struct Module {
1130 pub id: NodeId,
1131 pub span: Span,
1132 pub doc: Vec<String>,
1134 pub path: Option<ModulePath>,
1136 pub imports: Vec<ImportDecl>,
1137 pub items: Vec<Item>,
1138}
1139
1140#[cfg(test)]
1143mod tests {
1144 use super::*;
1145 use bock_errors::FileId;
1146
1147 fn dummy_span() -> Span {
1148 Span {
1149 file: FileId(0),
1150 start: 0,
1151 end: 0,
1152 }
1153 }
1154
1155 fn dummy_ident(name: &str) -> Ident {
1156 Ident {
1157 name: name.to_string(),
1158 span: dummy_span(),
1159 }
1160 }
1161
1162 #[test]
1163 fn module_is_debug() {
1164 let m = Module {
1165 id: 0,
1166 span: dummy_span(),
1167 doc: vec![],
1168 path: None,
1169 imports: vec![],
1170 items: vec![],
1171 };
1172 let s = format!("{m:?}");
1173 assert!(s.contains("Module"));
1174 }
1175
1176 #[test]
1177 fn item_fn_span() {
1178 let fn_decl = FnDecl {
1179 id: 1,
1180 span: Span {
1181 file: FileId(1),
1182 start: 5,
1183 end: 20,
1184 },
1185 annotations: vec![],
1186 visibility: Visibility::Public,
1187 is_async: false,
1188 name: dummy_ident("foo"),
1189 generic_params: vec![],
1190 params: vec![],
1191 return_type: None,
1192 effect_clause: vec![],
1193 where_clause: vec![],
1194 body: Some(Block {
1195 id: 2,
1196 span: Span {
1197 file: FileId(1),
1198 start: 10,
1199 end: 20,
1200 },
1201 stmts: vec![],
1202 tail: None,
1203 }),
1204 };
1205 let item = Item::Fn(fn_decl);
1206 assert_eq!(item.span().start, 5);
1207 }
1208
1209 #[test]
1210 fn item_module_handle_and_property_test_exist() {
1211 let mh = Item::ModuleHandle(ModuleHandleDecl {
1212 id: 10,
1213 span: dummy_span(),
1214 effect: TypePath {
1215 segments: vec![dummy_ident("Log")],
1216 span: dummy_span(),
1217 },
1218 handler: Expr::Identifier {
1219 id: 11,
1220 span: dummy_span(),
1221 name: dummy_ident("console_log"),
1222 },
1223 });
1224 let pt = Item::PropertyTest(PropertyTestDecl {
1225 id: 20,
1226 span: dummy_span(),
1227 name: "addition is commutative".into(),
1228 bindings: vec![],
1229 body: Block {
1230 id: 21,
1231 span: dummy_span(),
1232 stmts: vec![],
1233 tail: None,
1234 },
1235 });
1236 assert!(format!("{mh:?}").contains("ModuleHandle"));
1237 assert!(format!("{pt:?}").contains("PropertyTest"));
1238 }
1239
1240 #[test]
1241 fn expr_node_id_and_span() {
1242 let span = Span {
1243 file: FileId(1),
1244 start: 3,
1245 end: 7,
1246 };
1247 let e = Expr::Literal {
1248 id: 42,
1249 span,
1250 lit: Literal::Int("42".into()),
1251 };
1252 assert_eq!(e.node_id(), 42);
1253 assert_eq!(e.span(), span);
1254 }
1255
1256 #[test]
1257 fn pattern_wildcard_debug() {
1258 let p = Pattern::Wildcard {
1259 id: 0,
1260 span: dummy_span(),
1261 };
1262 assert!(format!("{p:?}").contains("Wildcard"));
1263 }
1264
1265 #[test]
1266 fn type_expr_optional_debug() {
1267 let inner = TypeExpr::Named {
1268 id: 0,
1269 span: dummy_span(),
1270 path: TypePath {
1271 segments: vec![dummy_ident("Int")],
1272 span: dummy_span(),
1273 },
1274 args: vec![],
1275 };
1276 let opt = TypeExpr::Optional {
1277 id: 1,
1278 span: dummy_span(),
1279 inner: Box::new(inner),
1280 };
1281 assert!(format!("{opt:?}").contains("Optional"));
1282 }
1283
1284 #[test]
1285 fn visibility_default_is_private() {
1286 assert_eq!(Visibility::default(), Visibility::Private);
1287 }
1288
1289 #[test]
1290 fn enum_variant_kinds() {
1291 let unit = EnumVariant::Unit {
1292 id: 0,
1293 span: dummy_span(),
1294 name: dummy_ident("A"),
1295 };
1296 let strukt = EnumVariant::Struct {
1297 id: 1,
1298 span: dummy_span(),
1299 name: dummy_ident("B"),
1300 fields: vec![],
1301 };
1302 let tuple = EnumVariant::Tuple {
1303 id: 2,
1304 span: dummy_span(),
1305 name: dummy_ident("C"),
1306 tys: vec![],
1307 };
1308 assert!(format!("{unit:?}").contains("Unit"));
1309 assert!(format!("{strukt:?}").contains("Struct"));
1310 assert!(format!("{tuple:?}").contains("Tuple"));
1311 }
1312
1313 #[test]
1314 fn all_expr_variants_have_span() {
1315 let span = dummy_span();
1316 let exprs: Vec<Expr> = vec![
1317 Expr::Literal {
1318 id: 0,
1319 span,
1320 lit: Literal::Bool(true),
1321 },
1322 Expr::Identifier {
1323 id: 1,
1324 span,
1325 name: dummy_ident("x"),
1326 },
1327 Expr::Continue { id: 2, span },
1328 Expr::Unreachable { id: 3, span },
1329 Expr::Placeholder { id: 4, span },
1330 ];
1331 for e in &exprs {
1332 assert_eq!(e.span(), span);
1333 }
1334 }
1335}