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