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 target: TypeExpr,
975 pub where_clause: Vec<TypeConstraint>,
976 pub type_assignments: Vec<TypeAssignment>,
978 pub methods: Vec<FnDecl>,
979}
980
981#[derive(Debug, Clone, PartialEq)]
983pub struct EffectDecl {
984 pub id: NodeId,
985 pub span: Span,
986 pub annotations: Vec<Annotation>,
987 pub visibility: Visibility,
988 pub name: Ident,
989 pub generic_params: Vec<GenericParam>,
990 pub components: Vec<TypePath>,
992 pub operations: Vec<FnDecl>,
993}
994
995#[derive(Debug, Clone, PartialEq)]
997pub struct TypeAliasDecl {
998 pub id: NodeId,
999 pub span: Span,
1000 pub annotations: Vec<Annotation>,
1001 pub visibility: Visibility,
1002 pub name: Ident,
1003 pub generic_params: Vec<GenericParam>,
1004 pub ty: TypeExpr,
1005 pub where_clause: Vec<TypeConstraint>,
1006}
1007
1008#[derive(Debug, Clone, PartialEq)]
1010pub struct ConstDecl {
1011 pub id: NodeId,
1012 pub span: Span,
1013 pub annotations: Vec<Annotation>,
1014 pub visibility: Visibility,
1015 pub name: Ident,
1016 pub ty: TypeExpr,
1017 pub value: Expr,
1018}
1019
1020#[derive(Debug, Clone, PartialEq)]
1022pub struct ModuleHandleDecl {
1023 pub id: NodeId,
1024 pub span: Span,
1025 pub effect: TypePath,
1027 pub handler: Expr,
1029}
1030
1031#[derive(Debug, Clone, PartialEq)]
1033pub struct PropertyTestDecl {
1034 pub id: NodeId,
1035 pub span: Span,
1036 pub name: String,
1038 pub bindings: Vec<PropertyBinding>,
1040 pub body: Block,
1041}
1042
1043#[derive(Debug, Clone, PartialEq)]
1047pub struct ImportDecl {
1048 pub id: NodeId,
1049 pub span: Span,
1050 pub visibility: Visibility,
1051 pub path: ModulePath,
1052 pub items: ImportItems,
1053}
1054
1055#[derive(Debug, Clone, PartialEq)]
1057pub enum ImportItems {
1058 Module,
1060 Named(Vec<ImportedName>),
1062 Glob,
1064}
1065
1066#[derive(Debug, Clone, PartialEq)]
1068pub struct ImportedName {
1069 pub span: Span,
1070 pub name: Ident,
1071 pub alias: Option<Ident>,
1073}
1074
1075#[derive(Debug, Clone, PartialEq)]
1079pub enum Item {
1080 Fn(FnDecl),
1081 Record(RecordDecl),
1082 Enum(EnumDecl),
1083 Class(ClassDecl),
1084 Trait(TraitDecl),
1085 PlatformTrait(TraitDecl),
1086 Impl(ImplBlock),
1087 Effect(EffectDecl),
1088 TypeAlias(TypeAliasDecl),
1089 Const(ConstDecl),
1090 ModuleHandle(ModuleHandleDecl),
1092 PropertyTest(PropertyTestDecl),
1094 Error {
1096 id: NodeId,
1097 span: Span,
1098 },
1099}
1100
1101impl Item {
1102 #[must_use]
1104 pub fn span(&self) -> Span {
1105 match self {
1106 Item::Fn(d) => d.span,
1107 Item::Record(d) => d.span,
1108 Item::Enum(d) => d.span,
1109 Item::Class(d) => d.span,
1110 Item::Trait(d) | Item::PlatformTrait(d) => d.span,
1111 Item::Impl(d) => d.span,
1112 Item::Effect(d) => d.span,
1113 Item::TypeAlias(d) => d.span,
1114 Item::Const(d) => d.span,
1115 Item::ModuleHandle(d) => d.span,
1116 Item::PropertyTest(d) => d.span,
1117 Item::Error { span, .. } => *span,
1118 }
1119 }
1120}
1121
1122#[derive(Debug, Clone, PartialEq)]
1126pub struct Module {
1127 pub id: NodeId,
1128 pub span: Span,
1129 pub doc: Vec<String>,
1131 pub path: Option<ModulePath>,
1133 pub imports: Vec<ImportDecl>,
1134 pub items: Vec<Item>,
1135}
1136
1137#[cfg(test)]
1140mod tests {
1141 use super::*;
1142 use bock_errors::FileId;
1143
1144 fn dummy_span() -> Span {
1145 Span {
1146 file: FileId(0),
1147 start: 0,
1148 end: 0,
1149 }
1150 }
1151
1152 fn dummy_ident(name: &str) -> Ident {
1153 Ident {
1154 name: name.to_string(),
1155 span: dummy_span(),
1156 }
1157 }
1158
1159 #[test]
1160 fn module_is_debug() {
1161 let m = Module {
1162 id: 0,
1163 span: dummy_span(),
1164 doc: vec![],
1165 path: None,
1166 imports: vec![],
1167 items: vec![],
1168 };
1169 let s = format!("{m:?}");
1170 assert!(s.contains("Module"));
1171 }
1172
1173 #[test]
1174 fn item_fn_span() {
1175 let fn_decl = FnDecl {
1176 id: 1,
1177 span: Span {
1178 file: FileId(1),
1179 start: 5,
1180 end: 20,
1181 },
1182 annotations: vec![],
1183 visibility: Visibility::Public,
1184 is_async: false,
1185 name: dummy_ident("foo"),
1186 generic_params: vec![],
1187 params: vec![],
1188 return_type: None,
1189 effect_clause: vec![],
1190 where_clause: vec![],
1191 body: Some(Block {
1192 id: 2,
1193 span: Span {
1194 file: FileId(1),
1195 start: 10,
1196 end: 20,
1197 },
1198 stmts: vec![],
1199 tail: None,
1200 }),
1201 };
1202 let item = Item::Fn(fn_decl);
1203 assert_eq!(item.span().start, 5);
1204 }
1205
1206 #[test]
1207 fn item_module_handle_and_property_test_exist() {
1208 let mh = Item::ModuleHandle(ModuleHandleDecl {
1209 id: 10,
1210 span: dummy_span(),
1211 effect: TypePath {
1212 segments: vec![dummy_ident("Log")],
1213 span: dummy_span(),
1214 },
1215 handler: Expr::Identifier {
1216 id: 11,
1217 span: dummy_span(),
1218 name: dummy_ident("console_log"),
1219 },
1220 });
1221 let pt = Item::PropertyTest(PropertyTestDecl {
1222 id: 20,
1223 span: dummy_span(),
1224 name: "addition is commutative".into(),
1225 bindings: vec![],
1226 body: Block {
1227 id: 21,
1228 span: dummy_span(),
1229 stmts: vec![],
1230 tail: None,
1231 },
1232 });
1233 assert!(format!("{mh:?}").contains("ModuleHandle"));
1234 assert!(format!("{pt:?}").contains("PropertyTest"));
1235 }
1236
1237 #[test]
1238 fn expr_node_id_and_span() {
1239 let span = Span {
1240 file: FileId(1),
1241 start: 3,
1242 end: 7,
1243 };
1244 let e = Expr::Literal {
1245 id: 42,
1246 span,
1247 lit: Literal::Int("42".into()),
1248 };
1249 assert_eq!(e.node_id(), 42);
1250 assert_eq!(e.span(), span);
1251 }
1252
1253 #[test]
1254 fn pattern_wildcard_debug() {
1255 let p = Pattern::Wildcard {
1256 id: 0,
1257 span: dummy_span(),
1258 };
1259 assert!(format!("{p:?}").contains("Wildcard"));
1260 }
1261
1262 #[test]
1263 fn type_expr_optional_debug() {
1264 let inner = TypeExpr::Named {
1265 id: 0,
1266 span: dummy_span(),
1267 path: TypePath {
1268 segments: vec![dummy_ident("Int")],
1269 span: dummy_span(),
1270 },
1271 args: vec![],
1272 };
1273 let opt = TypeExpr::Optional {
1274 id: 1,
1275 span: dummy_span(),
1276 inner: Box::new(inner),
1277 };
1278 assert!(format!("{opt:?}").contains("Optional"));
1279 }
1280
1281 #[test]
1282 fn visibility_default_is_private() {
1283 assert_eq!(Visibility::default(), Visibility::Private);
1284 }
1285
1286 #[test]
1287 fn enum_variant_kinds() {
1288 let unit = EnumVariant::Unit {
1289 id: 0,
1290 span: dummy_span(),
1291 name: dummy_ident("A"),
1292 };
1293 let strukt = EnumVariant::Struct {
1294 id: 1,
1295 span: dummy_span(),
1296 name: dummy_ident("B"),
1297 fields: vec![],
1298 };
1299 let tuple = EnumVariant::Tuple {
1300 id: 2,
1301 span: dummy_span(),
1302 name: dummy_ident("C"),
1303 tys: vec![],
1304 };
1305 assert!(format!("{unit:?}").contains("Unit"));
1306 assert!(format!("{strukt:?}").contains("Struct"));
1307 assert!(format!("{tuple:?}").contains("Tuple"));
1308 }
1309
1310 #[test]
1311 fn all_expr_variants_have_span() {
1312 let span = dummy_span();
1313 let exprs: Vec<Expr> = vec![
1314 Expr::Literal {
1315 id: 0,
1316 span,
1317 lit: Literal::Bool(true),
1318 },
1319 Expr::Identifier {
1320 id: 1,
1321 span,
1322 name: dummy_ident("x"),
1323 },
1324 Expr::Continue { id: 2, span },
1325 Expr::Unreachable { id: 3, span },
1326 Expr::Placeholder { id: 4, span },
1327 ];
1328 for e in &exprs {
1329 assert_eq!(e.span(), span);
1330 }
1331 }
1332}