Skip to main content

lisette_syntax/
ast.rs

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    /// A flag option, e.g., `omitempty`, `skip`, `snake_case`
370    Flag(String),
371    /// A negated flag, e.g., `!omitempty`
372    NegatedFlag(String),
373    /// A quoted string, e.g., `"custom_name"` (name override)
374    String(String),
375    /// A raw backtick literal, e.g., `json:"name,string"`
376    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    /// Returns references to all direct child expressions.
1259    ///
1260    /// This is the single source of truth for expression tree recursion. Use this
1261    /// instead of writing per-variant match arms when you need to walk an expression tree.
1262    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 coefficient, e.g. `4i` stores `4.0`
1708    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}