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
539#[derive(Debug, Clone, PartialEq)]
540#[allow(clippy::large_enum_variant)]
541pub enum Expression {
542 Literal {
543 literal: Literal,
544 ty: Type,
545 span: Span,
546 },
547 Function {
548 doc: Option<String>,
549 attributes: Vec<Attribute>,
550 name: EcoString,
551 name_span: Span,
552 generics: Vec<Generic>,
553 params: Vec<Binding>,
554 return_annotation: Annotation,
555 return_type: Type,
556 visibility: Visibility,
557 body: Box<Expression>,
558 ty: Type,
559 span: Span,
560 },
561 Lambda {
562 params: Vec<Binding>,
563 return_annotation: Annotation,
564 body: Box<Expression>,
565 ty: Type,
566 span: Span,
567 },
568 Block {
569 items: Vec<Expression>,
570 ty: Type,
571 span: Span,
572 },
573 Let {
574 binding: Box<Binding>,
575 value: Box<Expression>,
576 mutable: bool,
577 mut_span: Option<Span>,
578 else_block: Option<Box<Expression>>,
579 else_span: Option<Span>,
580 typed_pattern: Option<TypedPattern>,
581 ty: Type,
582 span: Span,
583 },
584 Identifier {
585 value: EcoString,
586 ty: Type,
587 span: Span,
588 binding_id: Option<BindingId>,
589 qualified: Option<EcoString>,
590 },
591 Call {
592 expression: Box<Expression>,
593 args: Vec<Expression>,
594 spread: Box<Option<Expression>>,
595 type_args: Vec<Annotation>,
596 ty: Type,
597 span: Span,
598 call_kind: Option<CallKind>,
599 },
600 If {
601 condition: Box<Expression>,
602 consequence: Box<Expression>,
603 alternative: Box<Expression>,
604 ty: Type,
605 span: Span,
606 },
607 IfLet {
608 pattern: Pattern,
609 scrutinee: Box<Expression>,
610 consequence: Box<Expression>,
611 alternative: Box<Expression>,
612 typed_pattern: Option<TypedPattern>,
613 else_span: Option<Span>,
614 ty: Type,
615 span: Span,
616 },
617 Match {
618 subject: Box<Expression>,
619 arms: Vec<MatchArm>,
620 origin: MatchOrigin,
621 ty: Type,
622 span: Span,
623 },
624 Tuple {
625 elements: Vec<Expression>,
626 ty: Type,
627 span: Span,
628 },
629 StructCall {
630 name: EcoString,
631 field_assignments: Vec<StructFieldAssignment>,
632 spread: StructSpread,
633 ty: Type,
634 span: Span,
635 },
636 DotAccess {
637 expression: Box<Expression>,
638 member: EcoString,
639 ty: Type,
640 span: Span,
641 dot_access_kind: Option<DotAccessKind>,
642 receiver_coercion: Option<ReceiverCoercion>,
643 },
644 Assignment {
645 target: Box<Expression>,
646 value: Box<Expression>,
647 compound_operator: Option<BinaryOperator>,
648 span: Span,
649 },
650 Return {
651 expression: Box<Expression>,
652 ty: Type,
653 span: Span,
654 },
655 Propagate {
656 expression: Box<Expression>,
657 ty: Type,
658 span: Span,
659 },
660 TryBlock {
661 items: Vec<Expression>,
662 ty: Type,
663 try_keyword_span: Span,
664 span: Span,
665 },
666 RecoverBlock {
667 items: Vec<Expression>,
668 ty: Type,
669 recover_keyword_span: Span,
670 span: Span,
671 },
672 ImplBlock {
673 annotation: Annotation,
674 receiver_name: EcoString,
675 methods: Vec<Expression>,
676 generics: Vec<Generic>,
677 ty: Type,
678 span: Span,
679 },
680 Binary {
681 operator: BinaryOperator,
682 left: Box<Expression>,
683 right: Box<Expression>,
684 ty: Type,
685 span: Span,
686 },
687 Unary {
688 operator: UnaryOperator,
689 expression: Box<Expression>,
690 ty: Type,
691 span: Span,
692 },
693 Paren {
694 expression: Box<Expression>,
695 ty: Type,
696 span: Span,
697 },
698 Const {
699 doc: Option<String>,
700 identifier: EcoString,
701 identifier_span: Span,
702 annotation: Option<Annotation>,
703 expression: Box<Expression>,
704 visibility: Visibility,
705 ty: Type,
706 span: Span,
707 },
708 VariableDeclaration {
709 doc: Option<String>,
710 name: EcoString,
711 name_span: Span,
712 annotation: Annotation,
713 visibility: Visibility,
714 ty: Type,
715 span: Span,
716 },
717 RawGo {
718 text: String,
719 },
720 Loop {
721 body: Box<Expression>,
722 ty: Type,
723 span: Span,
724 needs_label: bool,
725 },
726 While {
727 condition: Box<Expression>,
728 body: Box<Expression>,
729 span: Span,
730 needs_label: bool,
731 },
732 WhileLet {
733 pattern: Pattern,
734 scrutinee: Box<Expression>,
735 body: Box<Expression>,
736 typed_pattern: Option<TypedPattern>,
737 span: Span,
738 needs_label: bool,
739 },
740 For {
741 binding: Box<Binding>,
742 iterable: Box<Expression>,
743 body: Box<Expression>,
744 span: Span,
745 needs_label: bool,
746 },
747 Break {
748 value: Option<Box<Expression>>,
749 span: Span,
750 },
751 Continue {
752 span: Span,
753 },
754 Enum {
755 doc: Option<String>,
756 attributes: Vec<Attribute>,
757 name: EcoString,
758 name_span: Span,
759 generics: Vec<Generic>,
760 variants: Vec<EnumVariant>,
761 visibility: Visibility,
762 span: Span,
763 },
764 ValueEnum {
765 doc: Option<String>,
766 name: EcoString,
767 name_span: Span,
768 underlying_ty: Option<Annotation>,
769 variants: Vec<ValueEnumVariant>,
770 visibility: Visibility,
771 span: Span,
772 },
773 Struct {
774 doc: Option<String>,
775 attributes: Vec<Attribute>,
776 name: EcoString,
777 name_span: Span,
778 generics: Vec<Generic>,
779 fields: Vec<StructFieldDefinition>,
780 kind: StructKind,
781 visibility: Visibility,
782 span: Span,
783 },
784 TypeAlias {
785 doc: Option<String>,
786 name: EcoString,
787 name_span: Span,
788 generics: Vec<Generic>,
789 annotation: Annotation,
790 ty: Type,
791 visibility: Visibility,
792 span: Span,
793 },
794 ModuleImport {
795 name: EcoString,
796 name_span: Span,
797 alias: Option<ImportAlias>,
798 span: Span,
799 },
800 Reference {
801 expression: Box<Expression>,
802 ty: Type,
803 span: Span,
804 },
805 Interface {
806 doc: Option<String>,
807 name: EcoString,
808 name_span: Span,
809 generics: Vec<Generic>,
810 parents: Vec<ParentInterface>,
811 method_signatures: Vec<Expression>,
812 visibility: Visibility,
813 span: Span,
814 },
815 IndexedAccess {
816 expression: Box<Expression>,
817 index: Box<Expression>,
818 ty: Type,
819 span: Span,
820 },
821 Task {
822 expression: Box<Expression>,
823 ty: Type,
824 span: Span,
825 },
826 Defer {
827 expression: Box<Expression>,
828 ty: Type,
829 span: Span,
830 },
831 Select {
832 arms: Vec<SelectArm>,
833 ty: Type,
834 span: Span,
835 },
836 Unit {
837 ty: Type,
838 span: Span,
839 },
840 Range {
841 start: Option<Box<Expression>>,
842 end: Option<Box<Expression>>,
843 inclusive: bool,
844 ty: Type,
845 span: Span,
846 },
847 Cast {
848 expression: Box<Expression>,
849 target_type: Annotation,
850 ty: Type,
851 span: Span,
852 },
853 NoOp,
854}
855
856impl Expression {
857 pub fn is_noop(&self) -> bool {
858 matches!(self, Expression::NoOp)
859 }
860
861 pub fn is_range(&self) -> bool {
862 matches!(self, Expression::Range { .. })
863 }
864
865 pub fn is_conditional(&self) -> bool {
866 matches!(
867 self,
868 Expression::If { .. }
869 | Expression::IfLet { .. }
870 | Expression::Match {
871 origin: MatchOrigin::IfLet { .. },
872 ..
873 }
874 )
875 }
876
877 pub fn is_control_flow(&self) -> bool {
878 matches!(
879 self,
880 Expression::If { .. }
881 | Expression::Match { .. }
882 | Expression::Select { .. }
883 | Expression::For { .. }
884 | Expression::While { .. }
885 | Expression::WhileLet { .. }
886 | Expression::Loop { .. }
887 )
888 }
889
890 pub fn callee_name(&self) -> Option<String> {
891 let Expression::Call { expression, .. } = self else {
892 return None;
893 };
894 match expression.as_ref() {
895 Expression::Identifier { value, .. } => Some(value.to_string()),
896 Expression::DotAccess {
897 expression: base,
898 member,
899 ..
900 } => {
901 if let Expression::Identifier { value, .. } = base.as_ref() {
902 Some(format!("{}.{}", value, member))
903 } else {
904 None
905 }
906 }
907 _ => None,
908 }
909 }
910
911 pub fn to_function_signature(&self) -> FunctionDefinition {
912 match self {
913 Expression::Function {
914 name,
915 name_span,
916 generics,
917 params,
918 return_annotation,
919 return_type,
920 ty,
921 ..
922 } => FunctionDefinition {
923 name: name.clone(),
924 name_span: *name_span,
925 generics: generics.clone(),
926 params: params.clone(),
927 body: Box::new(Expression::NoOp),
928 return_type: return_type.clone(),
929 annotation: return_annotation.clone(),
930 ty: ty.clone(),
931 },
932 _ => panic!("to_function_signature called on non-Function expression"),
933 }
934 }
935
936 pub fn to_function_definition(&self) -> FunctionDefinition {
937 match self {
938 Expression::Function {
939 name,
940 name_span,
941 generics,
942 params,
943 return_annotation,
944 return_type,
945 body,
946 ty,
947 ..
948 } => FunctionDefinition {
949 name: name.clone(),
950 name_span: *name_span,
951 generics: generics.clone(),
952 params: params.clone(),
953 body: body.clone(),
954 return_type: return_type.clone(),
955 annotation: return_annotation.clone(),
956 ty: ty.clone(),
957 },
958 _ => panic!("to_function_definition called on non-Function expression"),
959 }
960 }
961
962 pub fn as_option_constructor(&self) -> Option<std::result::Result<(), ()>> {
963 let variant = match self {
964 Expression::Identifier { value, .. } => Some(value.as_str()),
965 _ => None,
966 }?;
967
968 match variant {
969 "Option.Some" | "Some" => Some(Ok(())),
970 "Option.None" | "None" => Some(Err(())),
971 _ => None,
972 }
973 }
974
975 pub fn as_result_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 "Result.Ok" | "Ok" => Some(Ok(())),
983 "Result.Err" | "Err" => Some(Err(())),
984 _ => None,
985 }
986 }
987
988 pub fn as_partial_constructor(&self) -> Option<&'static str> {
989 let variant = match self {
990 Expression::Identifier { value, .. } => Some(value.as_str()),
991 _ => None,
992 }?;
993
994 match variant {
995 "Partial.Ok" => Some("Ok"),
996 "Partial.Err" => Some("Err"),
997 "Partial.Both" => Some("Both"),
998 _ => None,
999 }
1000 }
1001
1002 pub fn get_type(&self) -> Type {
1003 match self {
1004 Self::Literal { ty, .. }
1005 | Self::Function { ty, .. }
1006 | Self::Lambda { ty, .. }
1007 | Self::Block { ty, .. }
1008 | Self::Let { ty, .. }
1009 | Self::Identifier { ty, .. }
1010 | Self::Call { ty, .. }
1011 | Self::If { ty, .. }
1012 | Self::IfLet { ty, .. }
1013 | Self::Match { ty, .. }
1014 | Self::Tuple { ty, .. }
1015 | Self::StructCall { ty, .. }
1016 | Self::DotAccess { ty, .. }
1017 | Self::Return { ty, .. }
1018 | Self::Propagate { ty, .. }
1019 | Self::TryBlock { ty, .. }
1020 | Self::RecoverBlock { ty, .. }
1021 | Self::Binary { ty, .. }
1022 | Self::Paren { ty, .. }
1023 | Self::Unary { ty, .. }
1024 | Self::Const { ty, .. }
1025 | Self::VariableDeclaration { ty, .. }
1026 | Self::Defer { ty, .. }
1027 | Self::Reference { ty, .. }
1028 | Self::IndexedAccess { ty, .. }
1029 | Self::Task { ty, .. }
1030 | Self::Select { ty, .. }
1031 | Self::Unit { ty, .. }
1032 | Self::Loop { ty, .. }
1033 | Self::Range { ty, .. }
1034 | Self::Cast { ty, .. } => ty.clone(),
1035 Self::Enum { .. }
1036 | Self::ValueEnum { .. }
1037 | Self::Struct { .. }
1038 | Self::Assignment { .. }
1039 | Self::ImplBlock { .. }
1040 | Self::TypeAlias { .. }
1041 | Self::ModuleImport { .. }
1042 | Self::Interface { .. }
1043 | Self::NoOp
1044 | Self::RawGo { .. }
1045 | Self::While { .. }
1046 | Self::WhileLet { .. }
1047 | Self::For { .. } => Type::ignored(),
1048 Self::Break { .. } | Self::Continue { .. } => Type::Never,
1049 }
1050 }
1051
1052 pub fn get_span(&self) -> Span {
1053 match self {
1054 Self::Literal { span, .. }
1055 | Self::Function { span, .. }
1056 | Self::Lambda { span, .. }
1057 | Self::Block { span, .. }
1058 | Self::Let { span, .. }
1059 | Self::Identifier { span, .. }
1060 | Self::Call { span, .. }
1061 | Self::If { span, .. }
1062 | Self::IfLet { span, .. }
1063 | Self::Match { span, .. }
1064 | Self::Tuple { span, .. }
1065 | Self::Enum { span, .. }
1066 | Self::ValueEnum { span, .. }
1067 | Self::Struct { span, .. }
1068 | Self::StructCall { span, .. }
1069 | Self::DotAccess { span, .. }
1070 | Self::Assignment { span, .. }
1071 | Self::Return { span, .. }
1072 | Self::Propagate { span, .. }
1073 | Self::TryBlock { span, .. }
1074 | Self::RecoverBlock { span, .. }
1075 | Self::ImplBlock { span, .. }
1076 | Self::Binary { span, .. }
1077 | Self::Paren { span, .. }
1078 | Self::Unary { span, .. }
1079 | Self::Const { span, .. }
1080 | Self::VariableDeclaration { span, .. }
1081 | Self::Defer { span, .. }
1082 | Self::Reference { span, .. }
1083 | Self::IndexedAccess { span, .. }
1084 | Self::Task { span, .. }
1085 | Self::Select { span, .. }
1086 | Self::Loop { span, .. }
1087 | Self::TypeAlias { span, .. }
1088 | Self::ModuleImport { span, .. }
1089 | Self::Interface { span, .. }
1090 | Self::Unit { span, .. }
1091 | Self::While { span, .. }
1092 | Self::WhileLet { span, .. }
1093 | Self::For { span, .. }
1094 | Self::Break { span, .. }
1095 | Self::Continue { span, .. }
1096 | Self::Range { span, .. }
1097 | Self::Cast { span, .. } => *span,
1098 Self::NoOp | Self::RawGo { .. } => Span::dummy(),
1099 }
1100 }
1101
1102 pub fn contains_break(&self) -> bool {
1103 match self {
1104 Expression::Break { .. } => true,
1105
1106 Expression::Loop { .. }
1107 | Expression::While { .. }
1108 | Expression::WhileLet { .. }
1109 | Expression::For { .. } => false,
1110
1111 Expression::Block { items, .. } => items.iter().any(Self::contains_break),
1112
1113 Expression::TryBlock { items, .. } => items.iter().any(Self::contains_break),
1114 Expression::RecoverBlock { items, .. } => items.iter().any(Self::contains_break),
1115
1116 Expression::If {
1117 condition,
1118 consequence,
1119 alternative,
1120 ..
1121 } => {
1122 condition.contains_break()
1123 || consequence.contains_break()
1124 || alternative.contains_break()
1125 }
1126
1127 Expression::IfLet {
1128 scrutinee,
1129 consequence,
1130 alternative,
1131 ..
1132 } => {
1133 scrutinee.contains_break()
1134 || consequence.contains_break()
1135 || alternative.contains_break()
1136 }
1137
1138 Expression::Match { subject, arms, .. } => {
1139 subject.contains_break() || arms.iter().any(|arm| arm.expression.contains_break())
1140 }
1141
1142 Expression::Paren { expression, .. } => expression.contains_break(),
1143
1144 Expression::Binary { left, right, .. } => {
1145 left.contains_break() || right.contains_break()
1146 }
1147
1148 Expression::Unary { expression, .. } => expression.contains_break(),
1149
1150 Expression::Call {
1151 expression,
1152 args,
1153 spread,
1154 ..
1155 } => {
1156 expression.contains_break()
1157 || args.iter().any(Self::contains_break)
1158 || spread.as_ref().as_ref().is_some_and(Self::contains_break)
1159 }
1160
1161 Expression::Function { .. } | Expression::Lambda { .. } => false,
1162
1163 Expression::Select { arms, .. } => arms.iter().any(|arm| match &arm.pattern {
1164 SelectArmPattern::Receive { body, .. } => body.contains_break(),
1165 SelectArmPattern::Send { body, .. } => body.contains_break(),
1166 SelectArmPattern::MatchReceive { arms, .. } => {
1167 arms.iter().any(|a| a.expression.contains_break())
1168 }
1169 SelectArmPattern::WildCard { body } => body.contains_break(),
1170 }),
1171
1172 Expression::Cast { expression, .. } => expression.contains_break(),
1173
1174 Expression::Let {
1175 value, else_block, ..
1176 } => value.contains_break() || else_block.as_ref().is_some_and(|e| e.contains_break()),
1177
1178 Expression::Assignment { value, .. } => value.contains_break(),
1179
1180 _ => false,
1181 }
1182 }
1183
1184 pub fn diverges(&self) -> Option<DeadCodeCause> {
1185 match self {
1186 Expression::Return { .. } => Some(DeadCodeCause::Return),
1187 Expression::Break { .. } => Some(DeadCodeCause::Break),
1188 Expression::Continue { .. } => Some(DeadCodeCause::Continue),
1189
1190 Expression::If {
1191 consequence,
1192 alternative,
1193 ..
1194 } => {
1195 if consequence.diverges().is_some() && alternative.diverges().is_some() {
1196 Some(DeadCodeCause::DivergingIf)
1197 } else {
1198 None
1199 }
1200 }
1201
1202 Expression::IfLet {
1203 consequence,
1204 alternative,
1205 ..
1206 } => {
1207 if consequence.diverges().is_some() && alternative.diverges().is_some() {
1208 Some(DeadCodeCause::DivergingIf)
1209 } else {
1210 None
1211 }
1212 }
1213
1214 Expression::Match { arms, .. } => {
1215 if !arms.is_empty() && arms.iter().all(|arm| arm.expression.diverges().is_some()) {
1216 Some(DeadCodeCause::DivergingMatch)
1217 } else {
1218 None
1219 }
1220 }
1221
1222 Expression::Block { items, .. } => {
1223 for item in items {
1224 if let Some(cause) = item.diverges() {
1225 return Some(cause);
1226 }
1227 }
1228 None
1229 }
1230
1231 Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1232 for item in items {
1233 if let Some(cause) = item.diverges() {
1234 return Some(cause);
1235 }
1236 }
1237 None
1238 }
1239
1240 Expression::Paren { expression, .. } | Expression::Cast { expression, .. } => {
1241 expression.diverges()
1242 }
1243
1244 Expression::Loop { body, .. } => {
1245 if !body.contains_break() {
1246 Some(DeadCodeCause::InfiniteLoop)
1247 } else {
1248 None
1249 }
1250 }
1251
1252 Expression::Call { ty, .. } if ty.is_never() => Some(DeadCodeCause::DivergingCall),
1253
1254 _ => None,
1255 }
1256 }
1257
1258 pub fn children(&self) -> Vec<&Expression> {
1263 match self {
1264 Expression::Literal { literal, .. } => match literal {
1265 Literal::Slice(elements) => elements.iter().collect(),
1266 Literal::FormatString(parts) => parts
1267 .iter()
1268 .filter_map(|p| match p {
1269 FormatStringPart::Expression(e) => Some(e.as_ref()),
1270 FormatStringPart::Text(_) => None,
1271 })
1272 .collect(),
1273 _ => vec![],
1274 },
1275 Expression::Function { body, .. } => vec![body],
1276 Expression::Lambda { body, .. } => vec![body],
1277 Expression::Block { items, .. } => items.iter().collect(),
1278 Expression::Let {
1279 value, else_block, ..
1280 } => {
1281 let mut c = vec![value.as_ref()];
1282 if let Some(eb) = else_block {
1283 c.push(eb);
1284 }
1285 c
1286 }
1287 Expression::Identifier { .. } => vec![],
1288 Expression::Call {
1289 expression,
1290 args,
1291 spread,
1292 ..
1293 } => {
1294 let mut c = vec![expression.as_ref()];
1295 c.extend(args);
1296 if let Some(s) = spread.as_ref() {
1297 c.push(s);
1298 }
1299 c
1300 }
1301 Expression::If {
1302 condition,
1303 consequence,
1304 alternative,
1305 ..
1306 } => vec![condition, consequence, alternative],
1307 Expression::IfLet {
1308 scrutinee,
1309 consequence,
1310 alternative,
1311 ..
1312 } => vec![scrutinee, consequence, alternative],
1313 Expression::Match { subject, arms, .. } => {
1314 let mut c = vec![subject.as_ref()];
1315 for arm in arms {
1316 if let Some(guard) = &arm.guard {
1317 c.push(guard);
1318 }
1319 c.push(&arm.expression);
1320 }
1321 c
1322 }
1323 Expression::Tuple { elements, .. } => elements.iter().collect(),
1324 Expression::StructCall {
1325 field_assignments,
1326 spread,
1327 ..
1328 } => {
1329 let mut c: Vec<&Expression> =
1330 field_assignments.iter().map(|f| f.value.as_ref()).collect();
1331 if let Some(s) = spread.as_expression() {
1332 c.push(s);
1333 }
1334 c
1335 }
1336 Expression::DotAccess { expression, .. } => vec![expression],
1337 Expression::Assignment { target, value, .. } => vec![target, value],
1338 Expression::Return { expression, .. } => vec![expression],
1339 Expression::Propagate { expression, .. } => vec![expression],
1340 Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1341 items.iter().collect()
1342 }
1343 Expression::ImplBlock { methods, .. } => methods.iter().collect(),
1344 Expression::Binary { left, right, .. } => vec![left, right],
1345 Expression::Unary { expression, .. } => vec![expression],
1346 Expression::Paren { expression, .. } => vec![expression],
1347 Expression::Const { expression, .. } => vec![expression],
1348 Expression::Loop { body, .. } => vec![body],
1349 Expression::While {
1350 condition, body, ..
1351 } => vec![condition, body],
1352 Expression::WhileLet {
1353 scrutinee, body, ..
1354 } => vec![scrutinee, body],
1355 Expression::For { iterable, body, .. } => vec![iterable, body],
1356 Expression::Break { value, .. } => {
1357 value.as_ref().map(|v| vec![v.as_ref()]).unwrap_or_default()
1358 }
1359 Expression::Reference { expression, .. } => vec![expression],
1360 Expression::IndexedAccess {
1361 expression, index, ..
1362 } => vec![expression, index],
1363 Expression::Task { expression, .. } => vec![expression],
1364 Expression::Defer { expression, .. } => vec![expression],
1365 Expression::Select { arms, .. } => {
1366 let mut c = vec![];
1367 for arm in arms {
1368 match &arm.pattern {
1369 SelectArmPattern::Receive {
1370 receive_expression,
1371 body,
1372 ..
1373 } => {
1374 c.push(receive_expression.as_ref());
1375 c.push(body.as_ref());
1376 }
1377 SelectArmPattern::Send {
1378 send_expression,
1379 body,
1380 } => {
1381 c.push(send_expression.as_ref());
1382 c.push(body.as_ref());
1383 }
1384 SelectArmPattern::MatchReceive {
1385 receive_expression,
1386 arms: match_arms,
1387 } => {
1388 c.push(receive_expression.as_ref());
1389 for ma in match_arms {
1390 if let Some(guard) = &ma.guard {
1391 c.push(guard);
1392 }
1393 c.push(&ma.expression);
1394 }
1395 }
1396 SelectArmPattern::WildCard { body } => {
1397 c.push(body.as_ref());
1398 }
1399 }
1400 }
1401 c
1402 }
1403 Expression::Range { start, end, .. } => {
1404 let mut c = vec![];
1405 if let Some(s) = start {
1406 c.push(s.as_ref());
1407 }
1408 if let Some(e) = end {
1409 c.push(e.as_ref());
1410 }
1411 c
1412 }
1413 Expression::Cast { expression, .. } => vec![expression],
1414 Expression::Interface {
1415 method_signatures, ..
1416 } => method_signatures.iter().collect(),
1417 Expression::Unit { .. }
1418 | Expression::Continue { .. }
1419 | Expression::Enum { .. }
1420 | Expression::ValueEnum { .. }
1421 | Expression::Struct { .. }
1422 | Expression::TypeAlias { .. }
1423 | Expression::VariableDeclaration { .. }
1424 | Expression::ModuleImport { .. }
1425 | Expression::RawGo { .. }
1426 | Expression::NoOp => vec![],
1427 }
1428 }
1429
1430 pub fn unwrap_parens(&self) -> &Expression {
1431 match self {
1432 Expression::Paren { expression, .. } => expression.unwrap_parens(),
1433 other => other,
1434 }
1435 }
1436
1437 pub fn as_dotted_path(&self) -> Option<String> {
1438 match self {
1439 Expression::Identifier { value, .. } => Some(value.to_string()),
1440 Expression::DotAccess {
1441 expression, member, ..
1442 } => Some(format!("{}.{}", expression.as_dotted_path()?, member)),
1443 _ => None,
1444 }
1445 }
1446
1447 pub fn root_identifier(&self) -> Option<&str> {
1448 match self {
1449 Expression::Identifier { value, .. } => Some(value),
1450 Expression::DotAccess { expression, .. } => expression.root_identifier(),
1451 _ => None,
1452 }
1453 }
1454
1455 pub fn is_empty_collection(&self) -> bool {
1456 matches!(
1457 self,
1458 Expression::Literal {
1459 literal: Literal::Slice(elements),
1460 ..
1461 } if elements.is_empty()
1462 )
1463 }
1464
1465 pub fn is_all_literals(&self) -> bool {
1466 match self.unwrap_parens() {
1467 Expression::Literal { literal, .. } => match literal {
1468 Literal::Slice(elements) => elements.iter().all(|e| e.is_all_literals()),
1469 Literal::FormatString(parts) => parts.iter().all(|p| match p {
1470 FormatStringPart::Text(_) => true,
1471 FormatStringPart::Expression(e) => e.is_all_literals(),
1472 }),
1473 _ => true,
1474 },
1475 Expression::Tuple { elements, .. } => elements.iter().all(|e| e.is_all_literals()),
1476 Expression::Unit { .. } => true,
1477 _ => false,
1478 }
1479 }
1480
1481 pub fn get_var_name(&self) -> Option<String> {
1482 match self {
1483 Expression::Identifier { value, .. } => Some(value.to_string()),
1484 Expression::DotAccess { expression, .. } => expression.get_var_name(),
1485 Expression::Assignment { target, .. } => target.get_var_name(),
1486 Expression::IndexedAccess { expression, .. } => expression.get_var_name(),
1487 Expression::Paren { expression, .. } => expression.get_var_name(),
1488 Expression::Reference { expression, .. } => expression.get_var_name(),
1489 Expression::Unary {
1490 operator,
1491 expression,
1492 ..
1493 } => {
1494 if operator == &UnaryOperator::Deref {
1495 expression.get_var_name()
1496 } else {
1497 None
1498 }
1499 }
1500 _ => None,
1501 }
1502 }
1503
1504 pub fn is_function(&self) -> bool {
1505 matches!(self, Expression::Function { .. })
1506 }
1507
1508 pub fn set_public(self) -> Self {
1509 match self {
1510 Expression::Enum {
1511 doc,
1512 attributes,
1513 name,
1514 name_span,
1515 generics,
1516 variants,
1517 span,
1518 ..
1519 } => Expression::Enum {
1520 doc,
1521 attributes,
1522 name,
1523 name_span,
1524 generics,
1525 variants,
1526 visibility: Visibility::Public,
1527 span,
1528 },
1529 Expression::ValueEnum {
1530 doc,
1531 name,
1532 name_span,
1533 underlying_ty,
1534 variants,
1535 span,
1536 ..
1537 } => Expression::ValueEnum {
1538 doc,
1539 name,
1540 name_span,
1541 underlying_ty,
1542 variants,
1543 visibility: Visibility::Public,
1544 span,
1545 },
1546 Expression::Struct {
1547 doc,
1548 attributes,
1549 name,
1550 name_span,
1551 generics,
1552 fields,
1553 kind,
1554 span,
1555 ..
1556 } => {
1557 let fields = if kind == StructKind::Tuple {
1558 fields
1559 .into_iter()
1560 .map(|f| StructFieldDefinition {
1561 visibility: Visibility::Public,
1562 ..f
1563 })
1564 .collect()
1565 } else {
1566 fields
1567 };
1568 Expression::Struct {
1569 doc,
1570 attributes,
1571 name,
1572 name_span,
1573 generics,
1574 fields,
1575 kind,
1576 visibility: Visibility::Public,
1577 span,
1578 }
1579 }
1580 Expression::Function {
1581 doc,
1582 attributes,
1583 name,
1584 name_span,
1585 generics,
1586 params,
1587 return_annotation,
1588 return_type,
1589 body,
1590 ty,
1591 span,
1592 ..
1593 } => Expression::Function {
1594 doc,
1595 attributes,
1596 name,
1597 name_span,
1598 generics,
1599 params,
1600 return_annotation,
1601 return_type,
1602 visibility: Visibility::Public,
1603 body,
1604 ty,
1605 span,
1606 },
1607 Expression::Const {
1608 doc,
1609 identifier,
1610 identifier_span,
1611 annotation,
1612 expression,
1613 ty,
1614 span,
1615 ..
1616 } => Expression::Const {
1617 doc,
1618 identifier,
1619 identifier_span,
1620 annotation,
1621 expression,
1622 visibility: Visibility::Public,
1623 ty,
1624 span,
1625 },
1626 Expression::VariableDeclaration {
1627 doc,
1628 name,
1629 name_span,
1630 annotation,
1631 ty,
1632 span,
1633 ..
1634 } => Expression::VariableDeclaration {
1635 doc,
1636 name,
1637 name_span,
1638 annotation,
1639 visibility: Visibility::Public,
1640 ty,
1641 span,
1642 },
1643 Expression::TypeAlias {
1644 doc,
1645 name,
1646 name_span,
1647 generics,
1648 annotation,
1649 ty,
1650 span,
1651 ..
1652 } => Expression::TypeAlias {
1653 doc,
1654 name,
1655 name_span,
1656 generics,
1657 annotation,
1658 ty,
1659 visibility: Visibility::Public,
1660 span,
1661 },
1662 Expression::Interface {
1663 doc,
1664 name,
1665 name_span,
1666 generics,
1667 parents,
1668 method_signatures,
1669 span,
1670 ..
1671 } => Expression::Interface {
1672 doc,
1673 name,
1674 name_span,
1675 generics,
1676 parents,
1677 method_signatures,
1678 visibility: Visibility::Public,
1679 span,
1680 },
1681 expression => expression,
1682 }
1683 }
1684
1685 pub fn has_else(&self) -> bool {
1686 match self {
1687 Self::Block { items, .. } if items.is_empty() => false,
1688 Self::Unit { .. } => false,
1689 Self::If { alternative, .. } | Self::IfLet { alternative, .. } => {
1690 alternative.has_else()
1691 }
1692 _ => true,
1693 }
1694 }
1695}
1696
1697#[derive(Debug, Clone, PartialEq)]
1698pub enum Literal {
1699 Integer {
1700 value: u64,
1701 text: Option<String>,
1702 },
1703 Float {
1704 value: f64,
1705 text: Option<String>,
1706 },
1707 Imaginary(f64),
1709 Boolean(bool),
1710 String {
1711 value: String,
1712 raw: bool,
1713 },
1714 FormatString(Vec<FormatStringPart>),
1715 Char(String),
1716 Slice(Vec<Expression>),
1717}
1718
1719#[derive(Debug, Clone, PartialEq)]
1720pub enum FormatStringPart {
1721 Text(String),
1722 Expression(Box<Expression>),
1723}
1724
1725#[derive(Debug, Clone, PartialEq)]
1726pub enum UnaryOperator {
1727 Negative,
1728 Not,
1729 Deref,
1730}
1731
1732#[derive(Debug, Clone, Copy, PartialEq)]
1733pub enum BinaryOperator {
1734 Addition,
1735 Subtraction,
1736 Multiplication,
1737 Division,
1738 LessThan,
1739 LessThanOrEqual,
1740 GreaterThan,
1741 GreaterThanOrEqual,
1742 Remainder,
1743 Equal,
1744 NotEqual,
1745 And,
1746 Or,
1747 Pipeline,
1748}
1749
1750impl std::fmt::Display for BinaryOperator {
1751 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1752 let symbol = match self {
1753 BinaryOperator::Addition => "+",
1754 BinaryOperator::Subtraction => "-",
1755 BinaryOperator::Multiplication => "*",
1756 BinaryOperator::Division => "/",
1757 BinaryOperator::Remainder => "%",
1758 BinaryOperator::Equal => "==",
1759 BinaryOperator::NotEqual => "!=",
1760 BinaryOperator::LessThan => "<",
1761 BinaryOperator::LessThanOrEqual => "<=",
1762 BinaryOperator::GreaterThan => ">",
1763 BinaryOperator::GreaterThanOrEqual => ">=",
1764 BinaryOperator::And => "&&",
1765 BinaryOperator::Or => "||",
1766 BinaryOperator::Pipeline => "|>",
1767 };
1768 write!(f, "{}", symbol)
1769 }
1770}
1771
1772#[derive(Debug, Clone, PartialEq)]
1773pub struct ParentInterface {
1774 pub annotation: Annotation,
1775 pub ty: Type,
1776 pub span: Span,
1777}
1778
1779#[derive(Debug, Clone, Copy, PartialEq)]
1780#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1781pub enum Visibility {
1782 Public,
1783 Private,
1784}
1785
1786impl Visibility {
1787 pub fn is_public(&self) -> bool {
1788 matches!(self, Visibility::Public)
1789 }
1790}
1791
1792#[derive(Debug, Clone, PartialEq)]
1793pub enum ImportAlias {
1794 Named(EcoString, Span),
1795 Blank(Span),
1796}