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 BitwiseNot,
1760 Deref,
1761}
1762
1763#[derive(Debug, Clone, Copy, PartialEq)]
1764pub enum BinaryOperator {
1765 Addition,
1766 Subtraction,
1767 Multiplication,
1768 Division,
1769 BitwiseAnd,
1770 BitwiseOr,
1771 BitwiseXor,
1772 BitwiseAndNot,
1773 ShiftLeft,
1774 ShiftRight,
1775 LessThan,
1776 LessThanOrEqual,
1777 GreaterThan,
1778 GreaterThanOrEqual,
1779 Remainder,
1780 Equal,
1781 NotEqual,
1782 And,
1783 Or,
1784 Pipeline,
1785}
1786
1787impl std::fmt::Display for BinaryOperator {
1788 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1789 let symbol = match self {
1790 BinaryOperator::Addition => "+",
1791 BinaryOperator::Subtraction => "-",
1792 BinaryOperator::Multiplication => "*",
1793 BinaryOperator::Division => "/",
1794 BinaryOperator::Remainder => "%",
1795 BinaryOperator::BitwiseAnd => "&",
1796 BinaryOperator::BitwiseOr => "|",
1797 BinaryOperator::BitwiseXor => "^",
1798 BinaryOperator::BitwiseAndNot => "&^",
1799 BinaryOperator::ShiftLeft => "<<",
1800 BinaryOperator::ShiftRight => ">>",
1801 BinaryOperator::Equal => "==",
1802 BinaryOperator::NotEqual => "!=",
1803 BinaryOperator::LessThan => "<",
1804 BinaryOperator::LessThanOrEqual => "<=",
1805 BinaryOperator::GreaterThan => ">",
1806 BinaryOperator::GreaterThanOrEqual => ">=",
1807 BinaryOperator::And => "&&",
1808 BinaryOperator::Or => "||",
1809 BinaryOperator::Pipeline => "|>",
1810 };
1811 write!(f, "{}", symbol)
1812 }
1813}
1814
1815#[derive(Debug, Clone, PartialEq)]
1816pub struct ParentInterface {
1817 pub annotation: Annotation,
1818 pub ty: Type,
1819 pub span: Span,
1820}
1821
1822#[derive(Debug, Clone, Copy, PartialEq)]
1823#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1824pub enum Visibility {
1825 Public,
1826 Private,
1827}
1828
1829impl Visibility {
1830 pub fn is_public(&self) -> bool {
1831 matches!(self, Visibility::Public)
1832 }
1833}
1834
1835#[derive(Debug, Clone, PartialEq)]
1836pub enum ImportAlias {
1837 Named(EcoString, Span),
1838 Blank(Span),
1839}