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