1use ecow::EcoString;
2
3use crate::program::{CallKind, DotAccessKind, ReceiverCoercion};
4use crate::types::Type;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum DeadCodeCause {
8 Return,
9 Break,
10 Continue,
11 DivergingIf,
12 DivergingMatch,
13 InfiniteLoop,
14 DivergingCall,
15}
16
17#[derive(Clone, PartialEq)]
18pub struct Binding {
19 pub pattern: Pattern,
20 pub annotation: Option<Annotation>,
21 pub typed_pattern: Option<TypedPattern>,
22 pub ty: Type,
23 pub mutable: bool,
24}
25
26impl std::fmt::Debug for Binding {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 let mut s = f.debug_struct("Binding");
29 s.field("pattern", &self.pattern);
30 s.field("annotation", &self.annotation);
31 s.field("typed_pattern", &self.typed_pattern);
32 s.field("ty", &self.ty);
33 if self.mutable {
34 s.field("mutable", &self.mutable);
35 }
36 s.finish()
37 }
38}
39
40pub type BindingId = u32;
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum BindingKind {
44 Let { mutable: bool },
45 Parameter { mutable: bool },
46 MatchArm,
47}
48
49impl BindingKind {
50 pub fn is_mutable(&self) -> bool {
51 matches!(
52 self,
53 BindingKind::Let { mutable: true } | BindingKind::Parameter { mutable: true }
54 )
55 }
56
57 pub fn is_param(&self) -> bool {
58 matches!(self, BindingKind::Parameter { .. })
59 }
60
61 pub fn is_match_arm(&self) -> bool {
62 matches!(self, BindingKind::MatchArm)
63 }
64}
65
66#[derive(Clone, PartialEq)]
67pub struct MatchArm {
68 pub pattern: Pattern,
69 pub guard: Option<Box<Expression>>,
70 pub typed_pattern: Option<TypedPattern>,
71 pub expression: Box<Expression>,
72}
73
74impl MatchArm {
75 pub fn has_guard(&self) -> bool {
76 self.guard.is_some()
77 }
78}
79
80impl std::fmt::Debug for MatchArm {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 let mut s = f.debug_struct("MatchArm");
83 s.field("pattern", &self.pattern);
84 if self.guard.is_some() {
85 s.field("guard", &self.guard);
86 }
87 s.field("expression", &self.expression);
88 s.finish()
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum MatchOrigin {
94 Explicit,
95 IfLet { else_span: Option<Span> },
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub struct SelectArm {
100 pub pattern: SelectArmPattern,
101}
102
103#[derive(Debug, Clone, PartialEq)]
104pub enum SelectArmPattern {
105 Receive {
106 binding: Box<Pattern>,
107 typed_pattern: Option<TypedPattern>,
108 receive_expression: Box<Expression>,
109 body: Box<Expression>,
110 },
111 Send {
112 send_expression: Box<Expression>,
113 body: Box<Expression>,
114 },
115 MatchReceive {
116 receive_expression: Box<Expression>,
117 arms: Vec<MatchArm>,
118 },
119 WildCard {
120 body: Box<Expression>,
121 },
122}
123
124#[derive(Debug, Clone, PartialEq)]
125pub enum RestPattern {
126 Absent,
127 Discard(Span),
128 Bind { name: EcoString, span: Span },
129}
130
131impl RestPattern {
132 pub fn is_present(&self) -> bool {
133 !matches!(self, RestPattern::Absent)
134 }
135}
136
137#[derive(Debug, Clone, PartialEq)]
138pub enum Pattern {
139 Literal {
140 literal: Literal,
141 ty: Type,
142 span: Span,
143 },
144 Unit {
145 ty: Type,
146 span: Span,
147 },
148 EnumVariant {
149 identifier: EcoString,
150 fields: Vec<Self>,
151 rest: bool,
152 ty: Type,
153 span: Span,
154 },
155 Struct {
156 identifier: EcoString,
157 fields: Vec<StructFieldPattern>,
158 rest: bool,
159 ty: Type,
160 span: Span,
161 },
162 Tuple {
163 elements: Vec<Self>,
164 span: Span,
165 },
166 WildCard {
167 span: Span,
168 },
169 Identifier {
170 identifier: EcoString,
171 span: Span,
172 },
173 Slice {
174 prefix: Vec<Self>,
175 rest: RestPattern,
176 element_ty: Type,
177 span: Span,
178 },
179 Or {
180 patterns: Vec<Self>,
181 span: Span,
182 },
183 AsBinding {
184 pattern: Box<Self>,
185 name: EcoString,
186 span: Span,
187 },
188}
189
190impl Pattern {
191 pub fn get_span(&self) -> Span {
192 match self {
193 Pattern::Identifier { span, .. } => *span,
194 Pattern::Literal { span, .. } => *span,
195 Pattern::EnumVariant { span, .. } => *span,
196 Pattern::Struct { span, .. } => *span,
197 Pattern::WildCard { span } => *span,
198 Pattern::Unit { span, .. } => *span,
199 Pattern::Tuple { span, .. } => *span,
200 Pattern::Slice { span, .. } => *span,
201 Pattern::Or { span, .. } => *span,
202 Pattern::AsBinding { span, .. } => *span,
203 }
204 }
205
206 pub fn get_type(&self) -> Option<Type> {
207 match self {
208 Pattern::Identifier { .. } => None,
209 Pattern::Literal { ty, .. } => Some(ty.clone()),
210 Pattern::EnumVariant { ty, .. } => Some(ty.clone()),
211 Pattern::Struct { ty, .. } => Some(ty.clone()),
212 Pattern::WildCard { .. } => None,
213 Pattern::Unit { ty, .. } => Some(ty.clone()),
214 Pattern::Tuple { .. } => None,
215 Pattern::Slice { .. } => None,
216 Pattern::Or { .. } => None,
217 Pattern::AsBinding { pattern, .. } => pattern.get_type(),
218 }
219 }
220
221 pub fn is_identifier(&self) -> bool {
222 matches!(self, Pattern::Identifier { .. } | Pattern::AsBinding { .. })
223 }
224
225 pub fn get_identifier(&self) -> Option<EcoString> {
226 match self {
227 Pattern::Identifier { identifier, .. } => Some(identifier.clone()),
228 Pattern::AsBinding { name, .. } => Some(name.clone()),
229 _ => None,
230 }
231 }
232}
233
234#[derive(Debug, Clone, PartialEq)]
235pub struct StructFieldPattern {
236 pub name: EcoString,
237 pub value: Pattern,
238}
239
240#[derive(Debug, Clone, PartialEq)]
241pub enum TypedPattern {
242 Wildcard,
243 Literal(Literal),
244 EnumVariant {
245 enum_name: EcoString,
246 variant_name: EcoString,
247 variant_fields: Vec<EnumFieldDefinition>,
248 fields: Vec<TypedPattern>,
249 type_args: Vec<Type>,
250 field_types: Box<[Type]>,
251 },
252 EnumStructVariant {
253 enum_name: EcoString,
254 variant_name: EcoString,
255 variant_fields: Vec<EnumFieldDefinition>,
256 pattern_fields: Vec<(EcoString, TypedPattern)>,
257 type_args: Vec<Type>,
258 },
259 Struct {
260 struct_name: EcoString,
261 struct_fields: Vec<StructFieldDefinition>,
262 pattern_fields: Vec<(EcoString, TypedPattern)>,
263 type_args: Vec<Type>,
264 },
265 Slice {
266 prefix: Vec<TypedPattern>,
267 has_rest: bool,
268 element_type: Type,
269 },
270 Tuple {
271 arity: usize,
272 elements: Vec<TypedPattern>,
273 },
274 Or {
275 alternatives: Vec<TypedPattern>,
276 },
277}
278
279#[derive(Debug, Clone, PartialEq)]
280pub struct FunctionDefinition {
281 pub name: EcoString,
282 pub name_span: Span,
283 pub generics: Vec<Generic>,
284 pub params: Vec<Binding>,
285 pub body: Box<Expression>,
286 pub return_type: Type,
287 pub annotation: Annotation,
288 pub ty: Type,
289}
290
291#[derive(Debug, Clone, PartialEq)]
292pub enum VariantFields {
293 Unit,
294 Tuple(Vec<EnumFieldDefinition>),
295 Struct(Vec<EnumFieldDefinition>),
296}
297
298impl VariantFields {
299 pub fn is_empty(&self) -> bool {
300 match self {
301 VariantFields::Unit => true,
302 VariantFields::Tuple(fields) | VariantFields::Struct(fields) => fields.is_empty(),
303 }
304 }
305
306 pub fn len(&self) -> usize {
307 match self {
308 VariantFields::Unit => 0,
309 VariantFields::Tuple(fields) | VariantFields::Struct(fields) => fields.len(),
310 }
311 }
312
313 pub fn iter(&self) -> std::slice::Iter<'_, EnumFieldDefinition> {
314 match self {
315 VariantFields::Unit => [].iter(),
316 VariantFields::Tuple(fields) | VariantFields::Struct(fields) => fields.iter(),
317 }
318 }
319
320 pub fn is_struct(&self) -> bool {
321 matches!(self, VariantFields::Struct(_))
322 }
323}
324
325impl<'a> IntoIterator for &'a VariantFields {
326 type Item = &'a EnumFieldDefinition;
327 type IntoIter = std::slice::Iter<'a, EnumFieldDefinition>;
328
329 fn into_iter(self) -> Self::IntoIter {
330 self.iter()
331 }
332}
333
334#[derive(Debug, Clone, PartialEq)]
335pub struct EnumVariant {
336 pub doc: Option<String>,
337 pub name: EcoString,
338 pub name_span: Span,
339 pub fields: VariantFields,
340}
341
342#[derive(Debug, Clone, PartialEq)]
343pub struct ValueEnumVariant {
344 pub doc: Option<String>,
345 pub name: EcoString,
346 pub name_span: Span,
347 pub value: Literal,
348 pub value_span: Span,
349}
350
351#[derive(Debug, Clone, PartialEq)]
352pub struct EnumFieldDefinition {
353 pub name: EcoString,
354 pub name_span: Span,
355 pub annotation: Annotation,
356 pub ty: Type,
357}
358
359#[derive(Debug, Clone, PartialEq)]
360pub struct Attribute {
361 pub name: String,
362 pub args: Vec<AttributeArg>,
363 pub span: Span,
364}
365
366#[derive(Debug, Clone, PartialEq)]
367#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
368pub enum AttributeArg {
369 Flag(String),
371 NegatedFlag(String),
373 String(String),
375 Raw(String),
377}
378
379#[derive(Debug, Clone, Copy, PartialEq)]
380#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
381pub enum StructKind {
382 Record,
383 Tuple,
384}
385
386#[derive(Debug, Clone, PartialEq)]
387pub struct StructFieldDefinition {
388 pub doc: Option<String>,
389 pub attributes: Vec<Attribute>,
390 pub name: EcoString,
391 pub name_span: Span,
392 pub annotation: Annotation,
393 pub visibility: Visibility,
394 pub ty: Type,
395}
396
397#[derive(Debug, Clone, PartialEq)]
398pub struct StructFieldAssignment {
399 pub name: EcoString,
400 pub name_span: Span,
401 pub value: Box<Expression>,
402}
403
404#[derive(Debug, Clone, PartialEq)]
405pub enum StructSpread {
406 None,
407 From(Box<Expression>),
408 ZeroFill { span: Span },
409}
410
411impl StructSpread {
412 pub fn is_none(&self) -> bool {
413 matches!(self, Self::None)
414 }
415
416 pub fn is_some(&self) -> bool {
417 !self.is_none()
418 }
419
420 pub fn span(&self) -> Option<Span> {
421 match self {
422 Self::None => None,
423 Self::From(e) => Some(e.get_span()),
424 Self::ZeroFill { span } => Some(*span),
425 }
426 }
427
428 pub fn as_expression(&self) -> Option<&Expression> {
429 match self {
430 Self::From(e) => Some(e),
431 Self::None | Self::ZeroFill { .. } => None,
432 }
433 }
434}
435
436#[derive(Debug, Clone, PartialEq)]
437#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
438pub enum Annotation {
439 Constructor {
440 name: EcoString,
441 params: Vec<Self>,
442 span: Span,
443 },
444 Function {
445 params: Vec<Self>,
446 return_type: Box<Self>,
447 span: Span,
448 },
449 Tuple {
450 elements: Vec<Self>,
451 span: Span,
452 },
453 Unknown,
454 Opaque {
455 span: Span,
456 },
457}
458
459impl Annotation {
460 pub fn unit() -> Self {
461 Self::Constructor {
462 name: "Unit".into(),
463 params: vec![],
464 span: Span::dummy(),
465 }
466 }
467
468 pub fn get_span(&self) -> Span {
469 match self {
470 Self::Constructor { span, .. } => *span,
471 Self::Function { span, .. } => *span,
472 Self::Tuple { span, .. } => *span,
473 Self::Opaque { span } => *span,
474 Self::Unknown => Span::dummy(),
475 }
476 }
477
478 pub fn get_name(&self) -> Option<String> {
479 match self {
480 Self::Constructor { name, .. } => Some(name.to_string()),
481 _ => None,
482 }
483 }
484
485 pub fn is_unit(&self) -> bool {
486 matches!(self, Self::Constructor { name, params, .. } if name == "Unit" && params.is_empty())
487 }
488
489 pub fn is_unknown(&self) -> bool {
490 matches!(self, Self::Unknown)
491 }
492
493 pub fn is_opaque(&self) -> bool {
494 matches!(self, Self::Opaque { .. })
495 }
496}
497
498#[derive(Debug, Clone, PartialEq)]
499pub struct Generic {
500 pub name: EcoString,
501 pub bounds: Vec<Annotation>,
502 pub span: Span,
503}
504
505#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
506#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
507pub struct Span {
508 pub file_id: u32,
509 pub byte_offset: u32,
510 pub byte_length: u32,
511}
512
513impl Span {
514 pub fn new(file_id: u32, byte_offset: u32, byte_length: u32) -> Self {
515 Span {
516 file_id,
517 byte_offset,
518 byte_length,
519 }
520 }
521
522 pub fn dummy() -> Self {
523 Span {
524 file_id: 0,
525 byte_offset: 0,
526 byte_length: 0,
527 }
528 }
529
530 pub fn is_dummy(&self) -> bool {
531 self.byte_length == 0
532 }
533
534 pub fn end(&self) -> u32 {
535 self.byte_offset + self.byte_length
536 }
537
538 pub fn merge(self, other: Span) -> Span {
539 Span::new(
540 self.file_id,
541 self.byte_offset,
542 other.end() - self.byte_offset,
543 )
544 }
545}
546
547#[derive(Debug, Clone, PartialEq)]
548#[allow(clippy::large_enum_variant)]
549pub enum Expression {
550 Literal {
551 literal: Literal,
552 ty: Type,
553 span: Span,
554 },
555 Function {
556 doc: Option<String>,
557 attributes: Vec<Attribute>,
558 name: EcoString,
559 name_span: Span,
560 generics: Vec<Generic>,
561 params: Vec<Binding>,
562 return_annotation: Annotation,
563 return_type: Type,
564 visibility: Visibility,
565 body: Box<Expression>,
566 ty: Type,
567 span: Span,
568 },
569 Lambda {
570 params: Vec<Binding>,
571 return_annotation: Annotation,
572 body: Box<Expression>,
573 ty: Type,
574 span: Span,
575 },
576 Block {
577 items: Vec<Expression>,
578 ty: Type,
579 span: Span,
580 },
581 Let {
582 binding: Box<Binding>,
583 value: Box<Expression>,
584 mutable: bool,
585 mut_span: Option<Span>,
586 else_block: Option<Box<Expression>>,
587 else_span: Option<Span>,
588 typed_pattern: Option<TypedPattern>,
589 ty: Type,
590 span: Span,
591 },
592 Identifier {
593 value: EcoString,
594 ty: Type,
595 span: Span,
596 binding_id: Option<BindingId>,
597 qualified: Option<EcoString>,
598 },
599 Call {
600 expression: Box<Expression>,
601 args: Vec<Expression>,
602 spread: Box<Option<Expression>>,
603 type_args: Vec<Annotation>,
604 ty: Type,
605 span: Span,
606 call_kind: Option<CallKind>,
607 },
608 If {
609 condition: Box<Expression>,
610 consequence: Box<Expression>,
611 alternative: Box<Expression>,
612 ty: Type,
613 span: Span,
614 },
615 IfLet {
616 pattern: Pattern,
617 scrutinee: Box<Expression>,
618 consequence: Box<Expression>,
619 alternative: Box<Expression>,
620 typed_pattern: Option<TypedPattern>,
621 else_span: Option<Span>,
622 ty: Type,
623 span: Span,
624 },
625 Match {
626 subject: Box<Expression>,
627 arms: Vec<MatchArm>,
628 origin: MatchOrigin,
629 ty: Type,
630 span: Span,
631 },
632 Tuple {
633 elements: Vec<Expression>,
634 ty: Type,
635 span: Span,
636 },
637 StructCall {
638 name: EcoString,
639 field_assignments: Vec<StructFieldAssignment>,
640 spread: StructSpread,
641 ty: Type,
642 span: Span,
643 },
644 DotAccess {
645 expression: Box<Expression>,
646 member: EcoString,
647 ty: Type,
648 span: Span,
649 dot_access_kind: Option<DotAccessKind>,
650 receiver_coercion: Option<ReceiverCoercion>,
651 },
652 Assignment {
653 target: Box<Expression>,
654 value: Box<Expression>,
655 compound_operator: Option<BinaryOperator>,
656 span: Span,
657 },
658 Return {
659 expression: Box<Expression>,
660 ty: Type,
661 span: Span,
662 },
663 Propagate {
664 expression: Box<Expression>,
665 ty: Type,
666 span: Span,
667 },
668 TryBlock {
669 items: Vec<Expression>,
670 ty: Type,
671 try_keyword_span: Span,
672 span: Span,
673 },
674 RecoverBlock {
675 items: Vec<Expression>,
676 ty: Type,
677 recover_keyword_span: Span,
678 span: Span,
679 },
680 ImplBlock {
681 annotation: Annotation,
682 receiver_name: EcoString,
683 methods: Vec<Expression>,
684 generics: Vec<Generic>,
685 ty: Type,
686 span: Span,
687 },
688 Binary {
689 operator: BinaryOperator,
690 left: Box<Expression>,
691 right: Box<Expression>,
692 ty: Type,
693 span: Span,
694 },
695 Unary {
696 operator: UnaryOperator,
697 expression: Box<Expression>,
698 ty: Type,
699 span: Span,
700 },
701 Paren {
702 expression: Box<Expression>,
703 ty: Type,
704 span: Span,
705 },
706 Const {
707 doc: Option<String>,
708 identifier: EcoString,
709 identifier_span: Span,
710 annotation: Option<Annotation>,
711 expression: Box<Expression>,
712 visibility: Visibility,
713 ty: Type,
714 span: Span,
715 },
716 VariableDeclaration {
717 doc: Option<String>,
718 name: EcoString,
719 name_span: Span,
720 annotation: Annotation,
721 visibility: Visibility,
722 ty: Type,
723 span: Span,
724 },
725 RawGo {
726 text: String,
727 },
728 Loop {
729 body: Box<Expression>,
730 ty: Type,
731 span: Span,
732 needs_label: bool,
733 },
734 While {
735 condition: Box<Expression>,
736 body: Box<Expression>,
737 span: Span,
738 needs_label: bool,
739 },
740 WhileLet {
741 pattern: Pattern,
742 scrutinee: Box<Expression>,
743 body: Box<Expression>,
744 typed_pattern: Option<TypedPattern>,
745 span: Span,
746 needs_label: bool,
747 },
748 For {
749 binding: Box<Binding>,
750 iterable: Box<Expression>,
751 body: Box<Expression>,
752 span: Span,
753 needs_label: bool,
754 },
755 Break {
756 value: Option<Box<Expression>>,
757 span: Span,
758 },
759 Continue {
760 span: Span,
761 },
762 Enum {
763 doc: Option<String>,
764 attributes: Vec<Attribute>,
765 name: EcoString,
766 name_span: Span,
767 generics: Vec<Generic>,
768 variants: Vec<EnumVariant>,
769 visibility: Visibility,
770 span: Span,
771 },
772 ValueEnum {
773 doc: Option<String>,
774 name: EcoString,
775 name_span: Span,
776 underlying_ty: Option<Annotation>,
777 variants: Vec<ValueEnumVariant>,
778 visibility: Visibility,
779 span: Span,
780 },
781 Struct {
782 doc: Option<String>,
783 attributes: Vec<Attribute>,
784 name: EcoString,
785 name_span: Span,
786 generics: Vec<Generic>,
787 fields: Vec<StructFieldDefinition>,
788 kind: StructKind,
789 visibility: Visibility,
790 span: Span,
791 },
792 TypeAlias {
793 doc: Option<String>,
794 name: EcoString,
795 name_span: Span,
796 generics: Vec<Generic>,
797 annotation: Annotation,
798 ty: Type,
799 visibility: Visibility,
800 span: Span,
801 },
802 ModuleImport {
803 name: EcoString,
804 name_span: Span,
805 alias: Option<ImportAlias>,
806 span: Span,
807 },
808 Reference {
809 expression: Box<Expression>,
810 ty: Type,
811 span: Span,
812 },
813 Interface {
814 doc: Option<String>,
815 name: EcoString,
816 name_span: Span,
817 generics: Vec<Generic>,
818 parents: Vec<ParentInterface>,
819 method_signatures: Vec<Expression>,
820 visibility: Visibility,
821 span: Span,
822 },
823 IndexedAccess {
824 expression: Box<Expression>,
825 index: Box<Expression>,
826 ty: Type,
827 span: Span,
828 from_colon_syntax: bool,
829 },
830 Task {
831 expression: Box<Expression>,
832 ty: Type,
833 span: Span,
834 },
835 Defer {
836 expression: Box<Expression>,
837 ty: Type,
838 span: Span,
839 },
840 Select {
841 arms: Vec<SelectArm>,
842 ty: Type,
843 span: Span,
844 },
845 Unit {
846 ty: Type,
847 span: Span,
848 },
849 Range {
850 start: Option<Box<Expression>>,
851 end: Option<Box<Expression>>,
852 inclusive: bool,
853 ty: Type,
854 span: Span,
855 },
856 Cast {
857 expression: Box<Expression>,
858 target_type: Annotation,
859 ty: Type,
860 span: Span,
861 },
862 NoOp,
863}
864
865impl Expression {
866 pub fn is_noop(&self) -> bool {
867 matches!(self, Expression::NoOp)
868 }
869
870 pub fn is_block(&self) -> bool {
871 matches!(self, Expression::Block { .. })
872 }
873
874 pub fn is_range(&self) -> bool {
875 matches!(self, Expression::Range { .. })
876 }
877
878 pub fn is_conditional(&self) -> bool {
879 matches!(
880 self,
881 Expression::If { .. }
882 | Expression::IfLet { .. }
883 | Expression::Match {
884 origin: MatchOrigin::IfLet { .. },
885 ..
886 }
887 )
888 }
889
890 pub fn is_control_flow(&self) -> bool {
891 matches!(
892 self,
893 Expression::If { .. }
894 | Expression::Match { .. }
895 | Expression::Select { .. }
896 | Expression::For { .. }
897 | Expression::While { .. }
898 | Expression::WhileLet { .. }
899 | Expression::Loop { .. }
900 )
901 }
902
903 pub fn callee_name(&self) -> Option<String> {
904 let Expression::Call { expression, .. } = self else {
905 return None;
906 };
907 match expression.as_ref() {
908 Expression::Identifier { value, .. } => Some(value.to_string()),
909 Expression::DotAccess {
910 expression: base,
911 member,
912 ..
913 } => {
914 if let Expression::Identifier { value, .. } = base.as_ref() {
915 Some(format!("{}.{}", value, member))
916 } else {
917 None
918 }
919 }
920 _ => None,
921 }
922 }
923
924 pub fn to_function_signature(&self) -> FunctionDefinition {
925 match self {
926 Expression::Function {
927 name,
928 name_span,
929 generics,
930 params,
931 return_annotation,
932 return_type,
933 ty,
934 ..
935 } => FunctionDefinition {
936 name: name.clone(),
937 name_span: *name_span,
938 generics: generics.clone(),
939 params: params.clone(),
940 body: Box::new(Expression::NoOp),
941 return_type: return_type.clone(),
942 annotation: return_annotation.clone(),
943 ty: ty.clone(),
944 },
945 _ => panic!("to_function_signature called on non-Function expression"),
946 }
947 }
948
949 pub fn to_function_definition(&self) -> FunctionDefinition {
950 match self {
951 Expression::Function {
952 name,
953 name_span,
954 generics,
955 params,
956 return_annotation,
957 return_type,
958 body,
959 ty,
960 ..
961 } => FunctionDefinition {
962 name: name.clone(),
963 name_span: *name_span,
964 generics: generics.clone(),
965 params: params.clone(),
966 body: body.clone(),
967 return_type: return_type.clone(),
968 annotation: return_annotation.clone(),
969 ty: ty.clone(),
970 },
971 _ => panic!("to_function_definition called on non-Function expression"),
972 }
973 }
974
975 pub fn as_option_constructor(&self) -> Option<std::result::Result<(), ()>> {
976 let variant = match self {
977 Expression::Identifier { value, .. } => Some(value.as_str()),
978 _ => None,
979 }?;
980
981 match variant {
982 "Option.Some" | "Some" => Some(Ok(())),
983 "Option.None" | "None" => Some(Err(())),
984 _ => None,
985 }
986 }
987
988 pub fn as_result_constructor(&self) -> Option<std::result::Result<(), ()>> {
989 let variant = match self {
990 Expression::Identifier { value, .. } => Some(value.as_str()),
991 _ => None,
992 }?;
993
994 match variant {
995 "Result.Ok" | "Ok" => Some(Ok(())),
996 "Result.Err" | "Err" => Some(Err(())),
997 _ => None,
998 }
999 }
1000
1001 pub fn as_partial_constructor(&self) -> Option<&'static str> {
1002 let variant = match self {
1003 Expression::Identifier { value, .. } => Some(value.as_str()),
1004 _ => None,
1005 }?;
1006
1007 match variant {
1008 "Partial.Ok" => Some("Ok"),
1009 "Partial.Err" => Some("Err"),
1010 "Partial.Both" => Some("Both"),
1011 _ => None,
1012 }
1013 }
1014
1015 pub fn get_type(&self) -> Type {
1016 match self {
1017 Self::Literal { ty, .. }
1018 | Self::Function { ty, .. }
1019 | Self::Lambda { ty, .. }
1020 | Self::Block { ty, .. }
1021 | Self::Let { ty, .. }
1022 | Self::Identifier { ty, .. }
1023 | Self::Call { ty, .. }
1024 | Self::If { ty, .. }
1025 | Self::IfLet { ty, .. }
1026 | Self::Match { ty, .. }
1027 | Self::Tuple { ty, .. }
1028 | Self::StructCall { ty, .. }
1029 | Self::DotAccess { ty, .. }
1030 | Self::Return { ty, .. }
1031 | Self::Propagate { ty, .. }
1032 | Self::TryBlock { ty, .. }
1033 | Self::RecoverBlock { ty, .. }
1034 | Self::Binary { ty, .. }
1035 | Self::Paren { ty, .. }
1036 | Self::Unary { ty, .. }
1037 | Self::Const { ty, .. }
1038 | Self::VariableDeclaration { ty, .. }
1039 | Self::Defer { ty, .. }
1040 | Self::Reference { ty, .. }
1041 | Self::IndexedAccess { ty, .. }
1042 | Self::Task { ty, .. }
1043 | Self::Select { ty, .. }
1044 | Self::Unit { ty, .. }
1045 | Self::Loop { ty, .. }
1046 | Self::Range { ty, .. }
1047 | Self::Cast { ty, .. } => ty.clone(),
1048 Self::Enum { .. }
1049 | Self::ValueEnum { .. }
1050 | Self::Struct { .. }
1051 | Self::Assignment { .. }
1052 | Self::ImplBlock { .. }
1053 | Self::TypeAlias { .. }
1054 | Self::ModuleImport { .. }
1055 | Self::Interface { .. }
1056 | Self::NoOp
1057 | Self::RawGo { .. }
1058 | Self::While { .. }
1059 | Self::WhileLet { .. }
1060 | Self::For { .. } => Type::ignored(),
1061 Self::Break { .. } | Self::Continue { .. } => Type::Never,
1062 }
1063 }
1064
1065 pub fn get_span(&self) -> Span {
1066 match self {
1067 Self::Literal { span, .. }
1068 | Self::Function { span, .. }
1069 | Self::Lambda { span, .. }
1070 | Self::Block { span, .. }
1071 | Self::Let { span, .. }
1072 | Self::Identifier { span, .. }
1073 | Self::Call { span, .. }
1074 | Self::If { span, .. }
1075 | Self::IfLet { span, .. }
1076 | Self::Match { span, .. }
1077 | Self::Tuple { span, .. }
1078 | Self::Enum { span, .. }
1079 | Self::ValueEnum { span, .. }
1080 | Self::Struct { span, .. }
1081 | Self::StructCall { span, .. }
1082 | Self::DotAccess { span, .. }
1083 | Self::Assignment { span, .. }
1084 | Self::Return { span, .. }
1085 | Self::Propagate { span, .. }
1086 | Self::TryBlock { span, .. }
1087 | Self::RecoverBlock { span, .. }
1088 | Self::ImplBlock { span, .. }
1089 | Self::Binary { span, .. }
1090 | Self::Paren { span, .. }
1091 | Self::Unary { span, .. }
1092 | Self::Const { span, .. }
1093 | Self::VariableDeclaration { span, .. }
1094 | Self::Defer { span, .. }
1095 | Self::Reference { span, .. }
1096 | Self::IndexedAccess { span, .. }
1097 | Self::Task { span, .. }
1098 | Self::Select { span, .. }
1099 | Self::Loop { span, .. }
1100 | Self::TypeAlias { span, .. }
1101 | Self::ModuleImport { span, .. }
1102 | Self::Interface { span, .. }
1103 | Self::Unit { span, .. }
1104 | Self::While { span, .. }
1105 | Self::WhileLet { span, .. }
1106 | Self::For { span, .. }
1107 | Self::Break { span, .. }
1108 | Self::Continue { span, .. }
1109 | Self::Range { span, .. }
1110 | Self::Cast { span, .. } => *span,
1111 Self::NoOp | Self::RawGo { .. } => Span::dummy(),
1112 }
1113 }
1114
1115 pub fn contains_break(&self) -> bool {
1116 match self {
1117 Expression::Break { .. } => true,
1118
1119 Expression::Loop { .. }
1120 | Expression::While { .. }
1121 | Expression::WhileLet { .. }
1122 | Expression::For { .. } => false,
1123
1124 Expression::Block { items, .. } => items.iter().any(Self::contains_break),
1125
1126 Expression::TryBlock { items, .. } => items.iter().any(Self::contains_break),
1127 Expression::RecoverBlock { items, .. } => items.iter().any(Self::contains_break),
1128
1129 Expression::If {
1130 condition,
1131 consequence,
1132 alternative,
1133 ..
1134 } => {
1135 condition.contains_break()
1136 || consequence.contains_break()
1137 || alternative.contains_break()
1138 }
1139
1140 Expression::IfLet {
1141 scrutinee,
1142 consequence,
1143 alternative,
1144 ..
1145 } => {
1146 scrutinee.contains_break()
1147 || consequence.contains_break()
1148 || alternative.contains_break()
1149 }
1150
1151 Expression::Match { subject, arms, .. } => {
1152 subject.contains_break() || arms.iter().any(|arm| arm.expression.contains_break())
1153 }
1154
1155 Expression::Paren { expression, .. } => expression.contains_break(),
1156
1157 Expression::Binary { left, right, .. } => {
1158 left.contains_break() || right.contains_break()
1159 }
1160
1161 Expression::Unary { expression, .. } => expression.contains_break(),
1162
1163 Expression::Call {
1164 expression,
1165 args,
1166 spread,
1167 ..
1168 } => {
1169 expression.contains_break()
1170 || args.iter().any(Self::contains_break)
1171 || spread.as_ref().as_ref().is_some_and(Self::contains_break)
1172 }
1173
1174 Expression::Function { .. } | Expression::Lambda { .. } => false,
1175
1176 Expression::Select { arms, .. } => arms.iter().any(|arm| match &arm.pattern {
1177 SelectArmPattern::Receive { body, .. } => body.contains_break(),
1178 SelectArmPattern::Send { body, .. } => body.contains_break(),
1179 SelectArmPattern::MatchReceive { arms, .. } => {
1180 arms.iter().any(|a| a.expression.contains_break())
1181 }
1182 SelectArmPattern::WildCard { body } => body.contains_break(),
1183 }),
1184
1185 Expression::Cast { expression, .. } => expression.contains_break(),
1186
1187 Expression::Let {
1188 value, else_block, ..
1189 } => value.contains_break() || else_block.as_ref().is_some_and(|e| e.contains_break()),
1190
1191 Expression::Assignment { value, .. } => value.contains_break(),
1192
1193 _ => false,
1194 }
1195 }
1196
1197 pub fn diverges(&self) -> Option<DeadCodeCause> {
1198 match self {
1199 Expression::Return { .. } => Some(DeadCodeCause::Return),
1200 Expression::Break { .. } => Some(DeadCodeCause::Break),
1201 Expression::Continue { .. } => Some(DeadCodeCause::Continue),
1202
1203 Expression::If {
1204 consequence,
1205 alternative,
1206 ..
1207 } => {
1208 if consequence.diverges().is_some() && alternative.diverges().is_some() {
1209 Some(DeadCodeCause::DivergingIf)
1210 } else {
1211 None
1212 }
1213 }
1214
1215 Expression::IfLet {
1216 consequence,
1217 alternative,
1218 ..
1219 } => {
1220 if consequence.diverges().is_some() && alternative.diverges().is_some() {
1221 Some(DeadCodeCause::DivergingIf)
1222 } else {
1223 None
1224 }
1225 }
1226
1227 Expression::Match { arms, .. } => {
1228 if !arms.is_empty() && arms.iter().all(|arm| arm.expression.diverges().is_some()) {
1229 Some(DeadCodeCause::DivergingMatch)
1230 } else {
1231 None
1232 }
1233 }
1234
1235 Expression::Block { items, .. } => {
1236 for item in items {
1237 if let Some(cause) = item.diverges() {
1238 return Some(cause);
1239 }
1240 }
1241 None
1242 }
1243
1244 Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1245 for item in items {
1246 if let Some(cause) = item.diverges() {
1247 return Some(cause);
1248 }
1249 }
1250 None
1251 }
1252
1253 Expression::Paren { expression, .. } | Expression::Cast { expression, .. } => {
1254 expression.diverges()
1255 }
1256
1257 Expression::Loop { body, .. } => {
1258 if !body.contains_break() {
1259 Some(DeadCodeCause::InfiniteLoop)
1260 } else {
1261 None
1262 }
1263 }
1264
1265 Expression::Call { ty, .. } if ty.is_never() => Some(DeadCodeCause::DivergingCall),
1266
1267 _ => None,
1268 }
1269 }
1270
1271 pub fn children(&self) -> Vec<&Expression> {
1276 match self {
1277 Expression::Literal { literal, .. } => match literal {
1278 Literal::Slice(elements) => elements.iter().collect(),
1279 Literal::FormatString(parts) => parts
1280 .iter()
1281 .filter_map(|p| match p {
1282 FormatStringPart::Expression(e) => Some(e.as_ref()),
1283 FormatStringPart::Text(_) => None,
1284 })
1285 .collect(),
1286 _ => vec![],
1287 },
1288 Expression::Function { body, .. } => vec![body],
1289 Expression::Lambda { body, .. } => vec![body],
1290 Expression::Block { items, .. } => items.iter().collect(),
1291 Expression::Let {
1292 value, else_block, ..
1293 } => {
1294 let mut c = vec![value.as_ref()];
1295 if let Some(eb) = else_block {
1296 c.push(eb);
1297 }
1298 c
1299 }
1300 Expression::Identifier { .. } => vec![],
1301 Expression::Call {
1302 expression,
1303 args,
1304 spread,
1305 ..
1306 } => {
1307 let mut c = vec![expression.as_ref()];
1308 c.extend(args);
1309 if let Some(s) = spread.as_ref() {
1310 c.push(s);
1311 }
1312 c
1313 }
1314 Expression::If {
1315 condition,
1316 consequence,
1317 alternative,
1318 ..
1319 } => vec![condition, consequence, alternative],
1320 Expression::IfLet {
1321 scrutinee,
1322 consequence,
1323 alternative,
1324 ..
1325 } => vec![scrutinee, consequence, alternative],
1326 Expression::Match { subject, arms, .. } => {
1327 let mut c = vec![subject.as_ref()];
1328 for arm in arms {
1329 if let Some(guard) = &arm.guard {
1330 c.push(guard);
1331 }
1332 c.push(&arm.expression);
1333 }
1334 c
1335 }
1336 Expression::Tuple { elements, .. } => elements.iter().collect(),
1337 Expression::StructCall {
1338 field_assignments,
1339 spread,
1340 ..
1341 } => {
1342 let mut c: Vec<&Expression> =
1343 field_assignments.iter().map(|f| f.value.as_ref()).collect();
1344 if let Some(s) = spread.as_expression() {
1345 c.push(s);
1346 }
1347 c
1348 }
1349 Expression::DotAccess { expression, .. } => vec![expression],
1350 Expression::Assignment { target, value, .. } => vec![target, value],
1351 Expression::Return { expression, .. } => vec![expression],
1352 Expression::Propagate { expression, .. } => vec![expression],
1353 Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1354 items.iter().collect()
1355 }
1356 Expression::ImplBlock { methods, .. } => methods.iter().collect(),
1357 Expression::Binary { left, right, .. } => vec![left, right],
1358 Expression::Unary { expression, .. } => vec![expression],
1359 Expression::Paren { expression, .. } => vec![expression],
1360 Expression::Const { expression, .. } => vec![expression],
1361 Expression::Loop { body, .. } => vec![body],
1362 Expression::While {
1363 condition, body, ..
1364 } => vec![condition, body],
1365 Expression::WhileLet {
1366 scrutinee, body, ..
1367 } => vec![scrutinee, body],
1368 Expression::For { iterable, body, .. } => vec![iterable, body],
1369 Expression::Break { value, .. } => {
1370 value.as_ref().map(|v| vec![v.as_ref()]).unwrap_or_default()
1371 }
1372 Expression::Reference { expression, .. } => vec![expression],
1373 Expression::IndexedAccess {
1374 expression, index, ..
1375 } => vec![expression, index],
1376 Expression::Task { expression, .. } => vec![expression],
1377 Expression::Defer { expression, .. } => vec![expression],
1378 Expression::Select { arms, .. } => {
1379 let mut c = vec![];
1380 for arm in arms {
1381 match &arm.pattern {
1382 SelectArmPattern::Receive {
1383 receive_expression,
1384 body,
1385 ..
1386 } => {
1387 c.push(receive_expression.as_ref());
1388 c.push(body.as_ref());
1389 }
1390 SelectArmPattern::Send {
1391 send_expression,
1392 body,
1393 } => {
1394 c.push(send_expression.as_ref());
1395 c.push(body.as_ref());
1396 }
1397 SelectArmPattern::MatchReceive {
1398 receive_expression,
1399 arms: match_arms,
1400 } => {
1401 c.push(receive_expression.as_ref());
1402 for ma in match_arms {
1403 if let Some(guard) = &ma.guard {
1404 c.push(guard);
1405 }
1406 c.push(&ma.expression);
1407 }
1408 }
1409 SelectArmPattern::WildCard { body } => {
1410 c.push(body.as_ref());
1411 }
1412 }
1413 }
1414 c
1415 }
1416 Expression::Range { start, end, .. } => {
1417 let mut c = vec![];
1418 if let Some(s) = start {
1419 c.push(s.as_ref());
1420 }
1421 if let Some(e) = end {
1422 c.push(e.as_ref());
1423 }
1424 c
1425 }
1426 Expression::Cast { expression, .. } => vec![expression],
1427 Expression::Interface {
1428 method_signatures, ..
1429 } => method_signatures.iter().collect(),
1430 Expression::Unit { .. }
1431 | Expression::Continue { .. }
1432 | Expression::Enum { .. }
1433 | Expression::ValueEnum { .. }
1434 | Expression::Struct { .. }
1435 | Expression::TypeAlias { .. }
1436 | Expression::VariableDeclaration { .. }
1437 | Expression::ModuleImport { .. }
1438 | Expression::RawGo { .. }
1439 | Expression::NoOp => vec![],
1440 }
1441 }
1442
1443 pub fn unwrap_parens(&self) -> &Expression {
1444 match self {
1445 Expression::Paren { expression, .. } => expression.unwrap_parens(),
1446 other => other,
1447 }
1448 }
1449
1450 pub fn as_dotted_path(&self) -> Option<String> {
1451 match self {
1452 Expression::Identifier { value, .. } => Some(value.to_string()),
1453 Expression::DotAccess {
1454 expression, member, ..
1455 } => Some(format!("{}.{}", expression.as_dotted_path()?, member)),
1456 _ => None,
1457 }
1458 }
1459
1460 pub fn root_identifier(&self) -> Option<&str> {
1461 match self {
1462 Expression::Identifier { value, .. } => Some(value),
1463 Expression::DotAccess { expression, .. } => expression.root_identifier(),
1464 _ => None,
1465 }
1466 }
1467
1468 pub fn is_empty_collection(&self) -> bool {
1469 matches!(
1470 self,
1471 Expression::Literal {
1472 literal: Literal::Slice(elements),
1473 ..
1474 } if elements.is_empty()
1475 )
1476 }
1477
1478 pub fn is_all_literals(&self) -> bool {
1479 match self.unwrap_parens() {
1480 Expression::Literal { literal, .. } => match literal {
1481 Literal::Slice(elements) => elements.iter().all(|e| e.is_all_literals()),
1482 Literal::FormatString(parts) => parts.iter().all(|p| match p {
1483 FormatStringPart::Text(_) => true,
1484 FormatStringPart::Expression(e) => e.is_all_literals(),
1485 }),
1486 _ => true,
1487 },
1488 Expression::Tuple { elements, .. } => elements.iter().all(|e| e.is_all_literals()),
1489 Expression::Unit { .. } => true,
1490 _ => false,
1491 }
1492 }
1493
1494 pub fn get_var_name(&self) -> Option<String> {
1495 match self {
1496 Expression::Identifier { value, .. } => Some(value.to_string()),
1497 Expression::DotAccess { expression, .. } => expression.get_var_name(),
1498 Expression::Assignment { target, .. } => target.get_var_name(),
1499 Expression::IndexedAccess { expression, .. } => expression.get_var_name(),
1500 Expression::Paren { expression, .. } => expression.get_var_name(),
1501 Expression::Reference { expression, .. } => expression.get_var_name(),
1502 Expression::Unary {
1503 operator,
1504 expression,
1505 ..
1506 } => {
1507 if operator == &UnaryOperator::Deref {
1508 expression.get_var_name()
1509 } else {
1510 None
1511 }
1512 }
1513 _ => None,
1514 }
1515 }
1516
1517 pub fn is_function(&self) -> bool {
1518 matches!(self, Expression::Function { .. })
1519 }
1520
1521 pub fn set_public(self) -> Self {
1522 match self {
1523 Expression::Enum {
1524 doc,
1525 attributes,
1526 name,
1527 name_span,
1528 generics,
1529 variants,
1530 span,
1531 ..
1532 } => Expression::Enum {
1533 doc,
1534 attributes,
1535 name,
1536 name_span,
1537 generics,
1538 variants,
1539 visibility: Visibility::Public,
1540 span,
1541 },
1542 Expression::ValueEnum {
1543 doc,
1544 name,
1545 name_span,
1546 underlying_ty,
1547 variants,
1548 span,
1549 ..
1550 } => Expression::ValueEnum {
1551 doc,
1552 name,
1553 name_span,
1554 underlying_ty,
1555 variants,
1556 visibility: Visibility::Public,
1557 span,
1558 },
1559 Expression::Struct {
1560 doc,
1561 attributes,
1562 name,
1563 name_span,
1564 generics,
1565 fields,
1566 kind,
1567 span,
1568 ..
1569 } => {
1570 let fields = if kind == StructKind::Tuple {
1571 fields
1572 .into_iter()
1573 .map(|f| StructFieldDefinition {
1574 visibility: Visibility::Public,
1575 ..f
1576 })
1577 .collect()
1578 } else {
1579 fields
1580 };
1581 Expression::Struct {
1582 doc,
1583 attributes,
1584 name,
1585 name_span,
1586 generics,
1587 fields,
1588 kind,
1589 visibility: Visibility::Public,
1590 span,
1591 }
1592 }
1593 Expression::Function {
1594 doc,
1595 attributes,
1596 name,
1597 name_span,
1598 generics,
1599 params,
1600 return_annotation,
1601 return_type,
1602 body,
1603 ty,
1604 span,
1605 ..
1606 } => Expression::Function {
1607 doc,
1608 attributes,
1609 name,
1610 name_span,
1611 generics,
1612 params,
1613 return_annotation,
1614 return_type,
1615 visibility: Visibility::Public,
1616 body,
1617 ty,
1618 span,
1619 },
1620 Expression::Const {
1621 doc,
1622 identifier,
1623 identifier_span,
1624 annotation,
1625 expression,
1626 ty,
1627 span,
1628 ..
1629 } => Expression::Const {
1630 doc,
1631 identifier,
1632 identifier_span,
1633 annotation,
1634 expression,
1635 visibility: Visibility::Public,
1636 ty,
1637 span,
1638 },
1639 Expression::VariableDeclaration {
1640 doc,
1641 name,
1642 name_span,
1643 annotation,
1644 ty,
1645 span,
1646 ..
1647 } => Expression::VariableDeclaration {
1648 doc,
1649 name,
1650 name_span,
1651 annotation,
1652 visibility: Visibility::Public,
1653 ty,
1654 span,
1655 },
1656 Expression::TypeAlias {
1657 doc,
1658 name,
1659 name_span,
1660 generics,
1661 annotation,
1662 ty,
1663 span,
1664 ..
1665 } => Expression::TypeAlias {
1666 doc,
1667 name,
1668 name_span,
1669 generics,
1670 annotation,
1671 ty,
1672 visibility: Visibility::Public,
1673 span,
1674 },
1675 Expression::Interface {
1676 doc,
1677 name,
1678 name_span,
1679 generics,
1680 parents,
1681 method_signatures,
1682 span,
1683 ..
1684 } => Expression::Interface {
1685 doc,
1686 name,
1687 name_span,
1688 generics,
1689 parents,
1690 method_signatures,
1691 visibility: Visibility::Public,
1692 span,
1693 },
1694 expression => expression,
1695 }
1696 }
1697
1698 pub fn has_else(&self) -> bool {
1699 match self {
1700 Self::Block { items, .. } if items.is_empty() => false,
1701 Self::Unit { .. } => false,
1702 Self::If { alternative, .. } | Self::IfLet { alternative, .. } => {
1703 alternative.has_else()
1704 }
1705 _ => true,
1706 }
1707 }
1708}
1709
1710#[derive(Debug, Clone, PartialEq)]
1711pub enum Literal {
1712 Integer {
1713 value: u64,
1714 text: Option<String>,
1715 },
1716 Float {
1717 value: f64,
1718 text: Option<String>,
1719 },
1720 Imaginary(f64),
1722 Boolean(bool),
1723 String {
1724 value: String,
1725 raw: bool,
1726 },
1727 FormatString(Vec<FormatStringPart>),
1728 Char(String),
1729 Slice(Vec<Expression>),
1730}
1731
1732#[derive(Debug, Clone, PartialEq)]
1733pub enum FormatStringPart {
1734 Text(String),
1735 Expression(Box<Expression>),
1736}
1737
1738#[derive(Debug, Clone, PartialEq)]
1739pub enum UnaryOperator {
1740 Negative,
1741 Not,
1742 Deref,
1743}
1744
1745#[derive(Debug, Clone, Copy, PartialEq)]
1746pub enum BinaryOperator {
1747 Addition,
1748 Subtraction,
1749 Multiplication,
1750 Division,
1751 LessThan,
1752 LessThanOrEqual,
1753 GreaterThan,
1754 GreaterThanOrEqual,
1755 Remainder,
1756 Equal,
1757 NotEqual,
1758 And,
1759 Or,
1760 Pipeline,
1761}
1762
1763impl std::fmt::Display for BinaryOperator {
1764 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1765 let symbol = match self {
1766 BinaryOperator::Addition => "+",
1767 BinaryOperator::Subtraction => "-",
1768 BinaryOperator::Multiplication => "*",
1769 BinaryOperator::Division => "/",
1770 BinaryOperator::Remainder => "%",
1771 BinaryOperator::Equal => "==",
1772 BinaryOperator::NotEqual => "!=",
1773 BinaryOperator::LessThan => "<",
1774 BinaryOperator::LessThanOrEqual => "<=",
1775 BinaryOperator::GreaterThan => ">",
1776 BinaryOperator::GreaterThanOrEqual => ">=",
1777 BinaryOperator::And => "&&",
1778 BinaryOperator::Or => "||",
1779 BinaryOperator::Pipeline => "|>",
1780 };
1781 write!(f, "{}", symbol)
1782 }
1783}
1784
1785#[derive(Debug, Clone, PartialEq)]
1786pub struct ParentInterface {
1787 pub annotation: Annotation,
1788 pub ty: Type,
1789 pub span: Span,
1790}
1791
1792#[derive(Debug, Clone, Copy, PartialEq)]
1793#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1794pub enum Visibility {
1795 Public,
1796 Private,
1797}
1798
1799impl Visibility {
1800 pub fn is_public(&self) -> bool {
1801 matches!(self, Visibility::Public)
1802 }
1803}
1804
1805#[derive(Debug, Clone, PartialEq)]
1806pub enum ImportAlias {
1807 Named(EcoString, Span),
1808 Blank(Span),
1809}