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