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