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