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#[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 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 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 Flag(String),
524 NegatedFlag(String),
526 String(String),
528 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#[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 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 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 #[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(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 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}