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