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 is_none_literal(&self) -> bool {
989 matches!(self.as_option_constructor(), Some(Err(())))
990 }
991
992 pub fn as_result_constructor(&self) -> Option<std::result::Result<(), ()>> {
993 let variant = match self {
994 Expression::Identifier { value, .. } => Some(value.as_str()),
995 _ => None,
996 }?;
997
998 match variant {
999 "Result.Ok" | "Ok" => Some(Ok(())),
1000 "Result.Err" | "Err" => Some(Err(())),
1001 _ => None,
1002 }
1003 }
1004
1005 pub fn as_partial_constructor(&self) -> Option<&'static str> {
1006 let variant = match self {
1007 Expression::Identifier { value, .. } => Some(value.as_str()),
1008 _ => None,
1009 }?;
1010
1011 match variant {
1012 "Partial.Ok" => Some("Ok"),
1013 "Partial.Err" => Some("Err"),
1014 "Partial.Both" => Some("Both"),
1015 _ => None,
1016 }
1017 }
1018
1019 pub fn get_type(&self) -> Type {
1020 match self {
1021 Self::Literal { ty, .. }
1022 | Self::Function { ty, .. }
1023 | Self::Lambda { ty, .. }
1024 | Self::Block { ty, .. }
1025 | Self::Let { ty, .. }
1026 | Self::Identifier { ty, .. }
1027 | Self::Call { ty, .. }
1028 | Self::If { ty, .. }
1029 | Self::IfLet { ty, .. }
1030 | Self::Match { ty, .. }
1031 | Self::Tuple { ty, .. }
1032 | Self::StructCall { ty, .. }
1033 | Self::DotAccess { ty, .. }
1034 | Self::Return { ty, .. }
1035 | Self::Propagate { ty, .. }
1036 | Self::TryBlock { ty, .. }
1037 | Self::RecoverBlock { ty, .. }
1038 | Self::Binary { ty, .. }
1039 | Self::Paren { ty, .. }
1040 | Self::Unary { ty, .. }
1041 | Self::Const { ty, .. }
1042 | Self::VariableDeclaration { ty, .. }
1043 | Self::Defer { ty, .. }
1044 | Self::Reference { ty, .. }
1045 | Self::IndexedAccess { ty, .. }
1046 | Self::Task { ty, .. }
1047 | Self::Select { ty, .. }
1048 | Self::Unit { ty, .. }
1049 | Self::Loop { ty, .. }
1050 | Self::Range { ty, .. }
1051 | Self::Cast { ty, .. } => ty.clone(),
1052 Self::Enum { .. }
1053 | Self::ValueEnum { .. }
1054 | Self::Struct { .. }
1055 | Self::Assignment { .. }
1056 | Self::ImplBlock { .. }
1057 | Self::TypeAlias { .. }
1058 | Self::ModuleImport { .. }
1059 | Self::Interface { .. }
1060 | Self::NoOp
1061 | Self::RawGo { .. }
1062 | Self::While { .. }
1063 | Self::WhileLet { .. }
1064 | Self::For { .. } => Type::ignored(),
1065 Self::Break { .. } | Self::Continue { .. } => Type::Never,
1066 }
1067 }
1068
1069 pub fn get_span(&self) -> Span {
1070 match self {
1071 Self::Literal { span, .. }
1072 | Self::Function { span, .. }
1073 | Self::Lambda { span, .. }
1074 | Self::Block { span, .. }
1075 | Self::Let { span, .. }
1076 | Self::Identifier { span, .. }
1077 | Self::Call { span, .. }
1078 | Self::If { span, .. }
1079 | Self::IfLet { span, .. }
1080 | Self::Match { span, .. }
1081 | Self::Tuple { span, .. }
1082 | Self::Enum { span, .. }
1083 | Self::ValueEnum { span, .. }
1084 | Self::Struct { span, .. }
1085 | Self::StructCall { span, .. }
1086 | Self::DotAccess { span, .. }
1087 | Self::Assignment { span, .. }
1088 | Self::Return { span, .. }
1089 | Self::Propagate { span, .. }
1090 | Self::TryBlock { span, .. }
1091 | Self::RecoverBlock { span, .. }
1092 | Self::ImplBlock { span, .. }
1093 | Self::Binary { span, .. }
1094 | Self::Paren { span, .. }
1095 | Self::Unary { span, .. }
1096 | Self::Const { span, .. }
1097 | Self::VariableDeclaration { span, .. }
1098 | Self::Defer { span, .. }
1099 | Self::Reference { span, .. }
1100 | Self::IndexedAccess { span, .. }
1101 | Self::Task { span, .. }
1102 | Self::Select { span, .. }
1103 | Self::Loop { span, .. }
1104 | Self::TypeAlias { span, .. }
1105 | Self::ModuleImport { span, .. }
1106 | Self::Interface { span, .. }
1107 | Self::Unit { span, .. }
1108 | Self::While { span, .. }
1109 | Self::WhileLet { span, .. }
1110 | Self::For { span, .. }
1111 | Self::Break { span, .. }
1112 | Self::Continue { span, .. }
1113 | Self::Range { span, .. }
1114 | Self::Cast { span, .. } => *span,
1115 Self::NoOp | Self::RawGo { .. } => Span::dummy(),
1116 }
1117 }
1118
1119 pub fn contains_break(&self) -> bool {
1120 match self {
1121 Expression::Break { .. } => true,
1122
1123 Expression::Loop { .. }
1124 | Expression::While { .. }
1125 | Expression::WhileLet { .. }
1126 | Expression::For { .. } => false,
1127
1128 Expression::Block { items, .. } => items.iter().any(Self::contains_break),
1129
1130 Expression::TryBlock { items, .. } => items.iter().any(Self::contains_break),
1131 Expression::RecoverBlock { items, .. } => items.iter().any(Self::contains_break),
1132
1133 Expression::If {
1134 condition,
1135 consequence,
1136 alternative,
1137 ..
1138 } => {
1139 condition.contains_break()
1140 || consequence.contains_break()
1141 || alternative.contains_break()
1142 }
1143
1144 Expression::IfLet {
1145 scrutinee,
1146 consequence,
1147 alternative,
1148 ..
1149 } => {
1150 scrutinee.contains_break()
1151 || consequence.contains_break()
1152 || alternative.contains_break()
1153 }
1154
1155 Expression::Match { subject, arms, .. } => {
1156 subject.contains_break() || arms.iter().any(|arm| arm.expression.contains_break())
1157 }
1158
1159 Expression::Paren { expression, .. } => expression.contains_break(),
1160
1161 Expression::Binary { left, right, .. } => {
1162 left.contains_break() || right.contains_break()
1163 }
1164
1165 Expression::Unary { expression, .. } => expression.contains_break(),
1166
1167 Expression::Call {
1168 expression,
1169 args,
1170 spread,
1171 ..
1172 } => {
1173 expression.contains_break()
1174 || args.iter().any(Self::contains_break)
1175 || spread.as_ref().as_ref().is_some_and(Self::contains_break)
1176 }
1177
1178 Expression::Function { .. } | Expression::Lambda { .. } => false,
1179
1180 Expression::Select { arms, .. } => arms.iter().any(|arm| match &arm.pattern {
1181 SelectArmPattern::Receive { body, .. } => body.contains_break(),
1182 SelectArmPattern::Send { body, .. } => body.contains_break(),
1183 SelectArmPattern::MatchReceive { arms, .. } => {
1184 arms.iter().any(|a| a.expression.contains_break())
1185 }
1186 SelectArmPattern::WildCard { body } => body.contains_break(),
1187 }),
1188
1189 Expression::Cast { expression, .. } => expression.contains_break(),
1190
1191 Expression::Let {
1192 value, else_block, ..
1193 } => value.contains_break() || else_block.as_ref().is_some_and(|e| e.contains_break()),
1194
1195 Expression::Assignment { value, .. } => value.contains_break(),
1196
1197 _ => false,
1198 }
1199 }
1200
1201 pub fn diverges(&self) -> Option<DeadCodeCause> {
1202 match self {
1203 Expression::Return { .. } => Some(DeadCodeCause::Return),
1204 Expression::Break { .. } => Some(DeadCodeCause::Break),
1205 Expression::Continue { .. } => Some(DeadCodeCause::Continue),
1206
1207 Expression::If {
1208 consequence,
1209 alternative,
1210 ..
1211 } => {
1212 if consequence.diverges().is_some() && alternative.diverges().is_some() {
1213 Some(DeadCodeCause::DivergingIf)
1214 } else {
1215 None
1216 }
1217 }
1218
1219 Expression::IfLet {
1220 consequence,
1221 alternative,
1222 ..
1223 } => {
1224 if consequence.diverges().is_some() && alternative.diverges().is_some() {
1225 Some(DeadCodeCause::DivergingIf)
1226 } else {
1227 None
1228 }
1229 }
1230
1231 Expression::Match { arms, .. } => {
1232 if !arms.is_empty() && arms.iter().all(|arm| arm.expression.diverges().is_some()) {
1233 Some(DeadCodeCause::DivergingMatch)
1234 } else {
1235 None
1236 }
1237 }
1238
1239 Expression::Block { items, .. } => {
1240 for item in items {
1241 if let Some(cause) = item.diverges() {
1242 return Some(cause);
1243 }
1244 }
1245 None
1246 }
1247
1248 Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1249 for item in items {
1250 if let Some(cause) = item.diverges() {
1251 return Some(cause);
1252 }
1253 }
1254 None
1255 }
1256
1257 Expression::Paren { expression, .. } | Expression::Cast { expression, .. } => {
1258 expression.diverges()
1259 }
1260
1261 Expression::Loop { body, .. } => {
1262 if !body.contains_break() {
1263 Some(DeadCodeCause::InfiniteLoop)
1264 } else {
1265 None
1266 }
1267 }
1268
1269 Expression::Call { ty, .. } if ty.is_never() => Some(DeadCodeCause::DivergingCall),
1270
1271 _ => None,
1272 }
1273 }
1274
1275 pub fn children(&self) -> Vec<&Expression> {
1280 match self {
1281 Expression::Literal { literal, .. } => match literal {
1282 Literal::Slice(elements) => elements.iter().collect(),
1283 Literal::FormatString(parts) => parts
1284 .iter()
1285 .filter_map(|p| match p {
1286 FormatStringPart::Expression(e) => Some(e.as_ref()),
1287 FormatStringPart::Text(_) => None,
1288 })
1289 .collect(),
1290 _ => vec![],
1291 },
1292 Expression::Function { body, .. } => vec![body],
1293 Expression::Lambda { body, .. } => vec![body],
1294 Expression::Block { items, .. } => items.iter().collect(),
1295 Expression::Let {
1296 value, else_block, ..
1297 } => {
1298 let mut c = vec![value.as_ref()];
1299 if let Some(eb) = else_block {
1300 c.push(eb);
1301 }
1302 c
1303 }
1304 Expression::Identifier { .. } => vec![],
1305 Expression::Call {
1306 expression,
1307 args,
1308 spread,
1309 ..
1310 } => {
1311 let mut c = vec![expression.as_ref()];
1312 c.extend(args);
1313 if let Some(s) = spread.as_ref() {
1314 c.push(s);
1315 }
1316 c
1317 }
1318 Expression::If {
1319 condition,
1320 consequence,
1321 alternative,
1322 ..
1323 } => vec![condition, consequence, alternative],
1324 Expression::IfLet {
1325 scrutinee,
1326 consequence,
1327 alternative,
1328 ..
1329 } => vec![scrutinee, consequence, alternative],
1330 Expression::Match { subject, arms, .. } => {
1331 let mut c = vec![subject.as_ref()];
1332 for arm in arms {
1333 if let Some(guard) = &arm.guard {
1334 c.push(guard);
1335 }
1336 c.push(&arm.expression);
1337 }
1338 c
1339 }
1340 Expression::Tuple { elements, .. } => elements.iter().collect(),
1341 Expression::StructCall {
1342 field_assignments,
1343 spread,
1344 ..
1345 } => {
1346 let mut c: Vec<&Expression> =
1347 field_assignments.iter().map(|f| f.value.as_ref()).collect();
1348 if let Some(s) = spread.as_expression() {
1349 c.push(s);
1350 }
1351 c
1352 }
1353 Expression::DotAccess { expression, .. } => vec![expression],
1354 Expression::Assignment { target, value, .. } => vec![target, value],
1355 Expression::Return { expression, .. } => vec![expression],
1356 Expression::Propagate { expression, .. } => vec![expression],
1357 Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1358 items.iter().collect()
1359 }
1360 Expression::ImplBlock { methods, .. } => methods.iter().collect(),
1361 Expression::Binary { left, right, .. } => vec![left, right],
1362 Expression::Unary { expression, .. } => vec![expression],
1363 Expression::Paren { expression, .. } => vec![expression],
1364 Expression::Const { expression, .. } => vec![expression],
1365 Expression::Loop { body, .. } => vec![body],
1366 Expression::While {
1367 condition, body, ..
1368 } => vec![condition, body],
1369 Expression::WhileLet {
1370 scrutinee, body, ..
1371 } => vec![scrutinee, body],
1372 Expression::For { iterable, body, .. } => vec![iterable, body],
1373 Expression::Break { value, .. } => {
1374 value.as_ref().map(|v| vec![v.as_ref()]).unwrap_or_default()
1375 }
1376 Expression::Reference { expression, .. } => vec![expression],
1377 Expression::IndexedAccess {
1378 expression, index, ..
1379 } => vec![expression, index],
1380 Expression::Task { expression, .. } => vec![expression],
1381 Expression::Defer { expression, .. } => vec![expression],
1382 Expression::Select { arms, .. } => {
1383 let mut c = vec![];
1384 for arm in arms {
1385 match &arm.pattern {
1386 SelectArmPattern::Receive {
1387 receive_expression,
1388 body,
1389 ..
1390 } => {
1391 c.push(receive_expression.as_ref());
1392 c.push(body.as_ref());
1393 }
1394 SelectArmPattern::Send {
1395 send_expression,
1396 body,
1397 } => {
1398 c.push(send_expression.as_ref());
1399 c.push(body.as_ref());
1400 }
1401 SelectArmPattern::MatchReceive {
1402 receive_expression,
1403 arms: match_arms,
1404 } => {
1405 c.push(receive_expression.as_ref());
1406 for ma in match_arms {
1407 if let Some(guard) = &ma.guard {
1408 c.push(guard);
1409 }
1410 c.push(&ma.expression);
1411 }
1412 }
1413 SelectArmPattern::WildCard { body } => {
1414 c.push(body.as_ref());
1415 }
1416 }
1417 }
1418 c
1419 }
1420 Expression::Range { start, end, .. } => {
1421 let mut c = vec![];
1422 if let Some(s) = start {
1423 c.push(s.as_ref());
1424 }
1425 if let Some(e) = end {
1426 c.push(e.as_ref());
1427 }
1428 c
1429 }
1430 Expression::Cast { expression, .. } => vec![expression],
1431 Expression::Interface {
1432 method_signatures, ..
1433 } => method_signatures.iter().collect(),
1434 Expression::Unit { .. }
1435 | Expression::Continue { .. }
1436 | Expression::Enum { .. }
1437 | Expression::ValueEnum { .. }
1438 | Expression::Struct { .. }
1439 | Expression::TypeAlias { .. }
1440 | Expression::VariableDeclaration { .. }
1441 | Expression::ModuleImport { .. }
1442 | Expression::RawGo { .. }
1443 | Expression::NoOp => vec![],
1444 }
1445 }
1446
1447 pub fn unwrap_parens(&self) -> &Expression {
1448 match self {
1449 Expression::Paren { expression, .. } => expression.unwrap_parens(),
1450 other => other,
1451 }
1452 }
1453
1454 #[inline]
1456 pub fn deref_inner(&self) -> Option<&Expression> {
1457 match self {
1458 Expression::Unary {
1459 operator: UnaryOperator::Deref,
1460 expression,
1461 ..
1462 } => Some(expression),
1463 _ => None,
1464 }
1465 }
1466
1467 pub fn as_dotted_path(&self) -> Option<String> {
1468 match self {
1469 Expression::Identifier { value, .. } => Some(value.to_string()),
1470 Expression::DotAccess {
1471 expression, member, ..
1472 } => Some(format!("{}.{}", expression.as_dotted_path()?, member)),
1473 _ => None,
1474 }
1475 }
1476
1477 pub fn root_identifier(&self) -> Option<&str> {
1478 match self {
1479 Expression::Identifier { value, .. } => Some(value),
1480 Expression::DotAccess { expression, .. } => expression.root_identifier(),
1481 _ => None,
1482 }
1483 }
1484
1485 pub fn is_empty_collection(&self) -> bool {
1486 matches!(
1487 self,
1488 Expression::Literal {
1489 literal: Literal::Slice(elements),
1490 ..
1491 } if elements.is_empty()
1492 )
1493 }
1494
1495 pub fn is_all_literals(&self) -> bool {
1496 match self.unwrap_parens() {
1497 Expression::Literal { literal, .. } => match literal {
1498 Literal::Slice(elements) => elements.iter().all(|e| e.is_all_literals()),
1499 Literal::FormatString(parts) => parts.iter().all(|p| match p {
1500 FormatStringPart::Text(_) => true,
1501 FormatStringPart::Expression(e) => e.is_all_literals(),
1502 }),
1503 _ => true,
1504 },
1505 Expression::Tuple { elements, .. } => elements.iter().all(|e| e.is_all_literals()),
1506 Expression::Unit { .. } => true,
1507 _ => false,
1508 }
1509 }
1510
1511 pub fn get_var_name(&self) -> Option<String> {
1512 match self {
1513 Expression::Identifier { value, .. } => Some(value.to_string()),
1514 Expression::DotAccess { expression, .. } => expression.get_var_name(),
1515 Expression::Assignment { target, .. } => target.get_var_name(),
1516 Expression::IndexedAccess { expression, .. } => expression.get_var_name(),
1517 Expression::Paren { expression, .. } => expression.get_var_name(),
1518 Expression::Reference { expression, .. } => expression.get_var_name(),
1519 Expression::Unary {
1520 operator,
1521 expression,
1522 ..
1523 } => {
1524 if operator == &UnaryOperator::Deref {
1525 expression.get_var_name()
1526 } else {
1527 None
1528 }
1529 }
1530 _ => None,
1531 }
1532 }
1533
1534 pub fn is_function(&self) -> bool {
1535 matches!(self, Expression::Function { .. })
1536 }
1537
1538 pub fn set_public(self) -> Self {
1539 match self {
1540 Expression::Enum {
1541 doc,
1542 attributes,
1543 name,
1544 name_span,
1545 generics,
1546 variants,
1547 span,
1548 ..
1549 } => Expression::Enum {
1550 doc,
1551 attributes,
1552 name,
1553 name_span,
1554 generics,
1555 variants,
1556 visibility: Visibility::Public,
1557 span,
1558 },
1559 Expression::ValueEnum {
1560 doc,
1561 name,
1562 name_span,
1563 underlying_ty,
1564 variants,
1565 span,
1566 ..
1567 } => Expression::ValueEnum {
1568 doc,
1569 name,
1570 name_span,
1571 underlying_ty,
1572 variants,
1573 visibility: Visibility::Public,
1574 span,
1575 },
1576 Expression::Struct {
1577 doc,
1578 attributes,
1579 name,
1580 name_span,
1581 generics,
1582 fields,
1583 kind,
1584 span,
1585 ..
1586 } => {
1587 let fields = if kind == StructKind::Tuple {
1588 fields
1589 .into_iter()
1590 .map(|f| StructFieldDefinition {
1591 visibility: Visibility::Public,
1592 ..f
1593 })
1594 .collect()
1595 } else {
1596 fields
1597 };
1598 Expression::Struct {
1599 doc,
1600 attributes,
1601 name,
1602 name_span,
1603 generics,
1604 fields,
1605 kind,
1606 visibility: Visibility::Public,
1607 span,
1608 }
1609 }
1610 Expression::Function {
1611 doc,
1612 attributes,
1613 name,
1614 name_span,
1615 generics,
1616 params,
1617 return_annotation,
1618 return_type,
1619 body,
1620 ty,
1621 span,
1622 ..
1623 } => Expression::Function {
1624 doc,
1625 attributes,
1626 name,
1627 name_span,
1628 generics,
1629 params,
1630 return_annotation,
1631 return_type,
1632 visibility: Visibility::Public,
1633 body,
1634 ty,
1635 span,
1636 },
1637 Expression::Const {
1638 doc,
1639 identifier,
1640 identifier_span,
1641 annotation,
1642 expression,
1643 ty,
1644 span,
1645 ..
1646 } => Expression::Const {
1647 doc,
1648 identifier,
1649 identifier_span,
1650 annotation,
1651 expression,
1652 visibility: Visibility::Public,
1653 ty,
1654 span,
1655 },
1656 Expression::VariableDeclaration {
1657 doc,
1658 name,
1659 name_span,
1660 annotation,
1661 ty,
1662 span,
1663 ..
1664 } => Expression::VariableDeclaration {
1665 doc,
1666 name,
1667 name_span,
1668 annotation,
1669 visibility: Visibility::Public,
1670 ty,
1671 span,
1672 },
1673 Expression::TypeAlias {
1674 doc,
1675 name,
1676 name_span,
1677 generics,
1678 annotation,
1679 ty,
1680 span,
1681 ..
1682 } => Expression::TypeAlias {
1683 doc,
1684 name,
1685 name_span,
1686 generics,
1687 annotation,
1688 ty,
1689 visibility: Visibility::Public,
1690 span,
1691 },
1692 Expression::Interface {
1693 doc,
1694 name,
1695 name_span,
1696 generics,
1697 parents,
1698 method_signatures,
1699 span,
1700 ..
1701 } => Expression::Interface {
1702 doc,
1703 name,
1704 name_span,
1705 generics,
1706 parents,
1707 method_signatures,
1708 visibility: Visibility::Public,
1709 span,
1710 },
1711 expression => expression,
1712 }
1713 }
1714
1715 pub fn has_else(&self) -> bool {
1716 match self {
1717 Self::Block { items, .. } if items.is_empty() => false,
1718 Self::Unit { .. } => false,
1719 Self::If { alternative, .. } | Self::IfLet { alternative, .. } => {
1720 alternative.has_else()
1721 }
1722 _ => true,
1723 }
1724 }
1725}
1726
1727#[derive(Debug, Clone, PartialEq)]
1728pub enum Literal {
1729 Integer {
1730 value: u64,
1731 text: Option<String>,
1732 },
1733 Float {
1734 value: f64,
1735 text: Option<String>,
1736 },
1737 Imaginary(f64),
1739 Boolean(bool),
1740 String {
1741 value: String,
1742 raw: bool,
1743 },
1744 FormatString(Vec<FormatStringPart>),
1745 Char(String),
1746 Slice(Vec<Expression>),
1747}
1748
1749#[derive(Debug, Clone, PartialEq)]
1750pub enum FormatStringPart {
1751 Text(String),
1752 Expression(Box<Expression>),
1753}
1754
1755#[derive(Debug, Clone, PartialEq)]
1756pub enum UnaryOperator {
1757 Negative,
1758 Not,
1759 Deref,
1760}
1761
1762#[derive(Debug, Clone, Copy, PartialEq)]
1763pub enum BinaryOperator {
1764 Addition,
1765 Subtraction,
1766 Multiplication,
1767 Division,
1768 LessThan,
1769 LessThanOrEqual,
1770 GreaterThan,
1771 GreaterThanOrEqual,
1772 Remainder,
1773 Equal,
1774 NotEqual,
1775 And,
1776 Or,
1777 Pipeline,
1778}
1779
1780impl std::fmt::Display for BinaryOperator {
1781 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1782 let symbol = match self {
1783 BinaryOperator::Addition => "+",
1784 BinaryOperator::Subtraction => "-",
1785 BinaryOperator::Multiplication => "*",
1786 BinaryOperator::Division => "/",
1787 BinaryOperator::Remainder => "%",
1788 BinaryOperator::Equal => "==",
1789 BinaryOperator::NotEqual => "!=",
1790 BinaryOperator::LessThan => "<",
1791 BinaryOperator::LessThanOrEqual => "<=",
1792 BinaryOperator::GreaterThan => ">",
1793 BinaryOperator::GreaterThanOrEqual => ">=",
1794 BinaryOperator::And => "&&",
1795 BinaryOperator::Or => "||",
1796 BinaryOperator::Pipeline => "|>",
1797 };
1798 write!(f, "{}", symbol)
1799 }
1800}
1801
1802#[derive(Debug, Clone, PartialEq)]
1803pub struct ParentInterface {
1804 pub annotation: Annotation,
1805 pub ty: Type,
1806 pub span: Span,
1807}
1808
1809#[derive(Debug, Clone, Copy, PartialEq)]
1810#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1811pub enum Visibility {
1812 Public,
1813 Private,
1814}
1815
1816impl Visibility {
1817 pub fn is_public(&self) -> bool {
1818 matches!(self, Visibility::Public)
1819 }
1820}
1821
1822#[derive(Debug, Clone, PartialEq)]
1823pub enum ImportAlias {
1824 Named(EcoString, Span),
1825 Blank(Span),
1826}