Skip to main content

lisette_syntax/
ast.rs

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