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