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