swamp_analyzer/
def.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::Analyzer;
6use crate::to_string::{
7    ExpressionGenerator, internal_generate_to_pretty_string_function_for_type,
8    internal_generate_to_short_string_function_for_type,
9    internal_generate_to_string_function_for_type,
10};
11use seq_map::SeqMap;
12use std::rc::Rc;
13use swamp_ast::Node;
14use swamp_attributes::Attributes;
15use swamp_modules::symtbl::AliasType;
16use swamp_semantic::err::ErrorKind;
17use swamp_semantic::{
18    ExternalFunctionDefinition, ExternalFunctionId, Function, InternalFunctionDefinition,
19    InternalFunctionId, LocalIdentifier, UseItem,
20};
21use swamp_types::prelude::*;
22use tracing::debug;
23
24impl Analyzer<'_> {
25    fn general_import(
26        &mut self,
27        path: &[String],
28        import_items: &swamp_ast::ImportItems,
29        node: &swamp_ast::Node,
30    ) {
31        let found_module = if let Some(module) = self.shared.get_module(path) {
32            module.clone()
33        } else {
34            self.add_err(ErrorKind::UnknownModule, node);
35            return;
36        };
37
38        match import_items {
39            swamp_ast::ImportItems::Nothing => {
40                let last_name = path.last().unwrap();
41                if self
42                    .shared
43                    .lookup_table
44                    .get_module_link(last_name)
45                    .is_none()
46                {
47                    match self
48                        .shared
49                        .lookup_table
50                        .add_module_link(last_name, found_module.clone())
51                    {
52                        Ok(_x) => {}
53                        Err(err) => {
54                            self.add_err(ErrorKind::SemanticError(err), node);
55                        }
56                    }
57                }
58            }
59            swamp_ast::ImportItems::Items(items) => {
60                for ast_items in items {
61                    match ast_items {
62                        swamp_ast::ImportItem::Identifier(node) => {
63                            let ident_resolved_node = self.to_node(&node.0);
64                            let ident = UseItem::Identifier(ident_resolved_node.clone());
65                            let ident_text =
66                                self.get_text_resolved(&ident_resolved_node).to_string();
67                            if let Some(found_symbol) =
68                                found_module.symbol_table.get_symbol(&ident_text)
69                            {
70                                if let Err(sem_err) = self
71                                    .shared
72                                    .lookup_table
73                                    .add_symbol(&ident_text, found_symbol.clone())
74                                {
75                                    self.add_err(ErrorKind::SemanticError(sem_err), &node.0);
76                                    return;
77                                }
78                            } else {
79                                return self.add_err_resolved(
80                                    ErrorKind::UnknownTypeReference,
81                                    &ident_resolved_node,
82                                );
83                            }
84                            ident
85                        }
86                        swamp_ast::ImportItem::Type(node) => {
87                            let ident_resolved_node = self.to_node(&node.0);
88                            let ident_text =
89                                self.get_text_resolved(&ident_resolved_node).to_string();
90                            if let Some(found_symbol) =
91                                found_module.symbol_table.get_symbol(&ident_text)
92                            {
93                                if let Err(sem_err) = self
94                                    .shared
95                                    .lookup_table
96                                    .add_symbol(&ident_text, found_symbol.clone())
97                                {
98                                    self.add_err(ErrorKind::SemanticError(sem_err), &node.0);
99                                    return;
100                                }
101                            } else {
102                                return self.add_err_resolved(
103                                    ErrorKind::UnknownTypeReference,
104                                    &ident_resolved_node,
105                                );
106                            }
107                            UseItem::TypeIdentifier(self.to_node(&node.0))
108                        }
109                    };
110                }
111            }
112            swamp_ast::ImportItems::All => {
113                if let Err(sem_err) = self
114                    .shared
115                    .lookup_table
116                    .extend_from(&found_module.symbol_table)
117                {
118                    self.add_err(ErrorKind::SemanticError(sem_err), node);
119                }
120            }
121        }
122    }
123
124    fn analyze_mod_definition(&mut self, mod_definition: &swamp_ast::Mod) {
125        let mut path = Vec::new();
126        for ast_node in &mod_definition.module_path.0 {
127            path.push(self.get_text(ast_node).to_string());
128        }
129
130        let mut nodes_copy = path.clone();
131        nodes_copy.insert(0, "crate".to_string());
132
133        self.general_import(
134            &nodes_copy,
135            &mod_definition.items,
136            &mod_definition.module_path.0[0],
137        );
138    }
139
140    fn analyze_use_definition(&mut self, use_definition: &swamp_ast::Use) {
141        let mut nodes = Vec::new();
142        for ast_node in &use_definition.module_path.0 {
143            nodes.push(self.to_node(ast_node));
144        }
145
146        let path: Vec<String> = nodes
147            .iter()
148            .map(|node| {
149                let text = self.get_text_resolved(node);
150                text.to_string()
151            })
152            .collect();
153
154        self.general_import(
155            &path,
156            &use_definition.items,
157            &use_definition.module_path.0[0],
158        );
159    }
160
161    fn analyze_enum_type_definition(
162        &mut self,
163        enum_type_name: &swamp_ast::LocalTypeIdentifierWithOptionalTypeVariables,
164        ast_variants: &[swamp_ast::EnumVariantType],
165    ) {
166        let mut resolved_variants = SeqMap::new();
167
168        let mut new_enum_type = EnumType {
169            name: self.to_node(&enum_type_name.name),
170            assigned_name: self.get_text(&enum_type_name.name).to_string(),
171            module_path: vec![],
172            variants: SeqMap::default(),
173            instantiated_type_parameters: Vec::default(),
174        };
175
176        for (container_index_usize, ast_variant_type) in ast_variants.iter().enumerate() {
177            let variant_name_node = match ast_variant_type {
178                swamp_ast::EnumVariantType::Simple(name) => name,
179                swamp_ast::EnumVariantType::Direct(name, _) => name,
180                swamp_ast::EnumVariantType::Tuple(name, _) => name,
181                swamp_ast::EnumVariantType::Struct(name, _) => name,
182            };
183
184            let common = EnumVariantCommon {
185                name: self.to_node(variant_name_node),
186                assigned_name: self.get_text(variant_name_node).to_string(),
187                container_index: container_index_usize as u8,
188            };
189
190            let payload_type = match ast_variant_type {
191                swamp_ast::EnumVariantType::Simple(_variant_name_node) => self.types().unit(),
192                swamp_ast::EnumVariantType::Direct(_variant_name_node, direct_type) => {
193                    let analyzed_type = self.analyze_type(direct_type);
194                    // If the direct_type is actually a single-element tuple, unwrap it
195                    match &*analyzed_type.kind {
196                        TypeKind::Tuple(elements) if elements.len() == 1 => elements[0].clone(),
197                        _ => analyzed_type,
198                    }
199                }
200                swamp_ast::EnumVariantType::Tuple(_variant_name_node, types) => {
201                    let mut vec = Vec::new();
202                    for tuple_type in types {
203                        let resolved_type = self.analyze_type(tuple_type);
204                        vec.push(resolved_type);
205                    }
206
207                    // Single-element tuples should be treated as direct types
208                    if vec.len() == 1 {
209                        vec.into_iter().next().unwrap()
210                    } else {
211                        self.types().tuple(vec)
212                    }
213                }
214                swamp_ast::EnumVariantType::Struct(_variant_name_node, ast_struct_fields) => {
215                    let mut fields = SeqMap::new();
216
217                    for field_with_type in &ast_struct_fields.fields {
218                        let resolved_type = self.analyze_type(&field_with_type.field_type);
219                        let field_name_str =
220                            self.get_text(&field_with_type.field_name.0).to_string();
221
222                        let resolved_field = StructTypeField {
223                            identifier: Some(self.to_node(&field_with_type.field_name.0)),
224                            field_type: resolved_type,
225                        };
226
227                        if let Err(_seq_map_err) = fields.insert(field_name_str, resolved_field) {
228                            return self.add_err(
229                                ErrorKind::DuplicateFieldName,
230                                &field_with_type.field_name.0,
231                            );
232                        }
233                    }
234
235                    let anonymous_struct_type = AnonymousStructType {
236                        field_name_sorted_fields: fields,
237                    };
238
239                    self.types().anonymous_struct(anonymous_struct_type)
240                }
241            };
242
243            let enum_variant_type = swamp_types::prelude::EnumVariantType {
244                common,
245                payload_type,
246            };
247
248            let variant_name_str = self.get_text(variant_name_node).to_string();
249
250            if let Err(_seq_map_err) = resolved_variants.insert(variant_name_str, enum_variant_type)
251            {
252                return self.add_err(ErrorKind::DuplicateFieldName, variant_name_node);
253            }
254        }
255
256        new_enum_type.variants = resolved_variants;
257
258        let enum_type_ref = self.shared.state.types.enum_type(new_enum_type);
259
260        if let Err(sem_err) = self
261            .shared
262            .definition_table
263            .add_named_type(enum_type_ref.clone())
264        {
265            return self.add_err(ErrorKind::SemanticError(sem_err), &enum_type_name.name);
266        }
267
268        if let Err(sem_err) = self
269            .shared
270            .lookup_table
271            .add_named_type(enum_type_ref.clone())
272        {
273            return self.add_err(ErrorKind::SemanticError(sem_err), &enum_type_name.name);
274        }
275
276        self.add_default_functions(&enum_type_ref, &enum_type_name.name);
277    }
278
279    /// # Errors
280    ///
281    pub fn analyze_alias_type_definition(&mut self, ast_alias: &swamp_ast::AliasType) -> AliasType {
282        let resolved_type = self.analyze_type(&ast_alias.referenced_type);
283
284        let alias_name_str = self.get_text(&ast_alias.identifier.0).to_string();
285        let resolved_alias = AliasType {
286            name: None,
287            ty: resolved_type,
288            assigned_name: alias_name_str,
289        };
290
291        let resolved_alias_ref = match self.shared.definition_table.add_alias(resolved_alias) {
292            Ok(re) => re,
293
294            Err(err) => {
295                self.add_err(ErrorKind::SemanticError(err), &ast_alias.identifier.0);
296                AliasType {
297                    name: None,
298                    assigned_name: "err".to_string(),
299                    ty: self.types().unit(),
300                }
301            }
302        };
303
304        if let Err(sem_err) = self
305            .shared
306            .lookup_table
307            .add_alias_link(resolved_alias_ref.clone())
308        {
309            self.add_err(ErrorKind::SemanticError(sem_err), &ast_alias.identifier.0);
310            AliasType {
311                name: None,
312                assigned_name: "err".to_string(),
313                ty: self.types().unit(),
314            }
315        } else {
316            resolved_alias_ref
317        }
318    }
319
320    /// # Errors
321    ///
322    pub fn analyze_anonymous_struct_type(
323        &mut self,
324        ast_struct: &swamp_ast::AnonymousStructType,
325    ) -> AnonymousStructType {
326        let resolved_fields = self.analyze_anonymous_struct_type_fields(&ast_struct.fields);
327
328        AnonymousStructType::new_and_sort_fields(&resolved_fields)
329    }
330
331    /// # Errors
332    ///
333    pub fn analyze_anonymous_struct_type_fields(
334        &mut self,
335        ast_struct_fields: &[swamp_ast::StructTypeField],
336    ) -> SeqMap<String, StructTypeField> {
337        let mut resolved_fields = SeqMap::new();
338
339        for field_name_and_type in ast_struct_fields {
340            let resolved_type = self.analyze_type(&field_name_and_type.field_type);
341            let name_string = self.get_text(&field_name_and_type.field_name.0).to_string();
342
343            if !resolved_type.can_be_stored_in_transient_field() {
344                self.add_err(ErrorKind::NeedStorage, &field_name_and_type.field_name.0);
345                return resolved_fields;
346            }
347
348            if !resolved_type.can_be_stored_in_field() {
349                self.add_hint(ErrorKind::NeedStorage, &field_name_and_type.field_name.0);
350            }
351
352            let field_type = StructTypeField {
353                identifier: Some(self.to_node(&field_name_and_type.field_name.0)),
354                field_type: resolved_type,
355            };
356
357            if let Err(_seq_map_err) = resolved_fields.insert(name_string, field_type) {
358                self.add_err(
359                    ErrorKind::DuplicateFieldName,
360                    &field_name_and_type.field_name.0,
361                );
362            }
363        }
364
365        resolved_fields
366    }
367
368    /// # Errors
369    ///
370    pub fn analyze_named_struct_type_definition(
371        &mut self,
372        ast_struct_def: &swamp_ast::NamedStructDef,
373    ) {
374        let struct_name_str = self.get_text(&ast_struct_def.identifier.name).to_string();
375
376        let fields = self.analyze_anonymous_struct_type_fields(&ast_struct_def.struct_type.fields);
377
378        let analyzed_anonymous_struct = AnonymousStructType::new(fields);
379
380        let anon_struct_type_ref = self
381            .shared
382            .state
383            .types
384            .anonymous_struct(analyzed_anonymous_struct);
385
386        let named_struct_type = NamedStructType {
387            name: self.to_node(&ast_struct_def.identifier.name),
388            anon_struct_type: anon_struct_type_ref,
389            assigned_name: struct_name_str,
390            module_path: self.shared.definition_table.module_path(),
391            instantiated_type_parameters: Vec::default(),
392        };
393
394        let named_struct_type_ref = self.shared.state.types.named_struct(named_struct_type);
395
396        match self
397            .shared
398            .definition_table
399            .add_named_type(named_struct_type_ref.clone())
400        {
401            Ok(()) => {}
402            Err(sem_err) => {
403                return self.add_err(
404                    ErrorKind::SemanticError(sem_err),
405                    &ast_struct_def.identifier.name,
406                );
407            }
408        }
409
410        match self
411            .shared
412            .lookup_table
413            .add_named_type(named_struct_type_ref.clone())
414        {
415            Ok(()) => {}
416            Err(sem_err) => {
417                return self.add_err(
418                    ErrorKind::SemanticError(sem_err),
419                    &ast_struct_def.identifier.name,
420                );
421            }
422        }
423
424        self.add_default_functions(&named_struct_type_ref, &ast_struct_def.identifier.name);
425    }
426
427    #[allow(clippy::too_many_lines)]
428    pub(crate) fn analyze_function_definition(
429        &mut self,
430        function: &swamp_ast::Function,
431        attributes: &Attributes,
432    ) -> Option<Function> {
433        let func = match &function {
434            swamp_ast::Function::Internal(function_data) => {
435                let parameters = self.analyze_parameters(&function_data.declaration.params);
436                let return_type = if let Some(found) = &function_data.declaration.return_type {
437                    let analyzed_return_type = self.analyze_type(found);
438                    if !analyzed_return_type.allowed_as_return_type() {
439                        self.add_err(
440                            ErrorKind::NotAllowedAsReturnType(analyzed_return_type),
441                            function.node(),
442                        );
443                        return None;
444                    }
445                    analyzed_return_type
446                } else {
447                    self.shared.state.types.unit()
448                };
449
450                for param in &parameters {
451                    let param_type = &param.resolved_type;
452                    let actual_type = param_type.clone();
453                    self.create_parameter_resolved(
454                        &param.node.as_ref().unwrap().name,
455                        param.node.as_ref().unwrap().is_mutable.as_ref(),
456                        &actual_type,
457                    );
458                }
459                let function_name = self
460                    .get_text(&function_data.declaration.name)
461                    .trim()
462                    .to_string();
463                let statements =
464                    self.analyze_function_body_expression(&function_data.body, &return_type);
465
466                let internal = InternalFunctionDefinition {
467                    signature: Signature {
468                        parameters,
469                        return_type,
470                    },
471                    body: statements,
472                    name: LocalIdentifier(self.to_node(&function_data.declaration.name)),
473                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
474                    associated_with_type: None,
475                    defined_in_module_path: self.module_path.clone(),
476                    function_variables: self.scope.total_scopes.clone(),
477                    program_unique_id: self.shared.state.allocate_internal_function_id(),
478                    attributes: attributes.clone(),
479                };
480
481                let function_ref = match self
482                    .shared
483                    .definition_table
484                    .add_internal_function(&function_name, internal)
485                {
486                    Ok(func_def) => func_def,
487                    Err(sem_err) => {
488                        self.add_err(
489                            ErrorKind::SemanticError(sem_err),
490                            &function_data.declaration.name,
491                        );
492                        return None;
493                    }
494                };
495
496                match self
497                    .shared
498                    .lookup_table
499                    .add_internal_function_link(&function_name, function_ref.clone())
500                {
501                    Ok(()) => {}
502                    Err(sem_err) => {
503                        self.add_err(
504                            ErrorKind::SemanticError(sem_err),
505                            &function_data.declaration.name,
506                        );
507                        return None;
508                    }
509                }
510
511                Function::Internal(function_ref)
512            }
513            swamp_ast::Function::External(int_node, ast_signature) => {
514                let parameters = self.analyze_parameters(&ast_signature.params);
515                let external_return_type = if let Some(found) = &ast_signature.return_type {
516                    self.analyze_type(found)
517                } else {
518                    self.shared.state.types.unit()
519                };
520
521                let return_type = external_return_type;
522
523                let int_string = self.get_text(int_node);
524                let external_function_id_int = Self::str_to_int(int_string).unwrap() as u32;
525
526                let external_function_id = external_function_id_int as ExternalFunctionId;
527
528                let external = ExternalFunctionDefinition {
529                    assigned_name: self.get_text(&ast_signature.name).to_string(),
530                    signature: Signature {
531                        parameters,
532                        return_type,
533                    },
534                    name: Some(self.to_node(&ast_signature.name)),
535                    id: external_function_id,
536                };
537
538                let function_ref = match self
539                    .shared
540                    .definition_table
541                    .add_external_function_declaration(external)
542                {
543                    Ok(func_ref) => func_ref,
544                    Err(sem_err) => {
545                        self.add_err(ErrorKind::SemanticError(sem_err), &ast_signature.name);
546                        return None;
547                    }
548                };
549
550                if let Err(sem_err) = self
551                    .shared
552                    .lookup_table
553                    .add_external_function_declaration_link(function_ref.clone())
554                {
555                    self.add_err(ErrorKind::SemanticError(sem_err), &ast_signature.name);
556                    return None;
557                }
558
559                Function::External(function_ref)
560            }
561        };
562
563        Some(func)
564    }
565
566    pub fn debug_definition(&self, definition: &swamp_ast::Definition) {
567        let (line, col) = self
568            .shared
569            .source_map
570            .get_span_location_utf8(self.shared.file_id, definition.node.span.offset as usize);
571        let source_line = self
572            .shared
573            .source_map
574            .get_source_line(self.shared.file_id, line)
575            .unwrap();
576        debug!(?line, ?col, ?source_line);
577    }
578
579    /// # Errors
580    ///
581    pub fn analyze_definition(&mut self, ast_def: &swamp_ast::Definition) {
582        //self.debug_definition(ast_def);
583
584        let analyzed_attributes = self.analyze_attributes(&ast_def.attributes);
585
586        match &ast_def.kind {
587            swamp_ast::DefinitionKind::NamedStructDef(ast_struct) => {
588                self.analyze_named_struct_type_definition(ast_struct);
589            }
590            swamp_ast::DefinitionKind::AliasDef(alias_def) => {
591                self.analyze_alias_type_definition(alias_def);
592            }
593            swamp_ast::DefinitionKind::EnumDef(identifier, variants) => {
594                self.analyze_enum_type_definition(identifier, variants);
595            }
596            swamp_ast::DefinitionKind::FunctionDef(function) => {
597                let _resolved_return_type = self.analyze_return_type(function);
598                self.start_function();
599                self.analyze_function_definition(function, &analyzed_attributes);
600                self.stop_function();
601            }
602            swamp_ast::DefinitionKind::ImplDef(type_identifier, functions) => {
603                self.analyze_impl_definition(type_identifier, functions);
604            }
605            swamp_ast::DefinitionKind::Mod(mod_info) => self.analyze_mod_definition(mod_info),
606            swamp_ast::DefinitionKind::Use(use_info) => self.analyze_use_definition(use_info),
607            swamp_ast::DefinitionKind::Constant(const_info) => {
608                self.analyze_constant_definition(const_info);
609            }
610        }
611    }
612
613    fn analyze_impl_definition(
614        &mut self,
615        attached_to_type: &swamp_ast::LocalTypeIdentifierWithOptionalTypeVariables,
616        functions: &[swamp_ast::Function],
617    ) {
618        let converted_type_variables_to_ast_types = attached_to_type
619            .type_variables
620            .iter()
621            .map(|x| {
622                swamp_ast::GenericParameter::Type(swamp_ast::Type::Named(
623                    swamp_ast::QualifiedTypeIdentifier {
624                        name: swamp_ast::LocalTypeIdentifier(x.0.clone()),
625                        module_path: None,
626                        generic_params: vec![],
627                    },
628                ))
629            })
630            .collect();
631
632        let qualified = swamp_ast::QualifiedTypeIdentifier {
633            name: swamp_ast::LocalTypeIdentifier(attached_to_type.name.clone()),
634            module_path: None,
635            generic_params: converted_type_variables_to_ast_types,
636        };
637
638        let maybe_type_to_attach_to = Some(self.analyze_named_type(&qualified));
639        if let Some(type_to_attach_to) = maybe_type_to_attach_to {
640            let function_refs: Vec<&swamp_ast::Function> = functions.iter().collect();
641            self.analyze_impl_functions(&type_to_attach_to, &function_refs);
642        } else {
643            self.add_err(
644                ErrorKind::CanNotAttachFunctionsToType,
645                &attached_to_type.name,
646            );
647        }
648    }
649
650    /// # Errors
651    ///
652    pub fn analyze_impl_functions(
653        &mut self,
654        attach_to_type: &TypeRef,
655        functions: &[&swamp_ast::Function],
656    ) {
657        if !self
658            .shared
659            .state
660            .associated_impls
661            .is_prepared(attach_to_type)
662        {
663            self.shared.state.associated_impls.prepare(attach_to_type);
664        }
665
666        for function in functions {
667            self.start_function();
668
669            let function_name = match function {
670                swamp_ast::Function::Internal(function_with_body) => {
671                    &function_with_body.declaration
672                }
673                swamp_ast::Function::External(_, external_declaration) => external_declaration,
674            };
675
676            let function_name_str = self.get_text(&function_name.name).to_string();
677
678            let existing_function_id = if matches!(
679                function_name_str.as_str(),
680                "to_string" | "to_short_string" | "to_pretty_string" | "default"
681            ) {
682                self.shared
683                    .state
684                    .associated_impls
685                    .get_internal_member_function(attach_to_type, &function_name_str)
686                    .map(|existing_fn| existing_fn.program_unique_id)
687            } else {
688                None
689            };
690
691            let resolved_function =
692                self.analyze_impl_func(function, attach_to_type, existing_function_id);
693
694            let resolved_function_ref = Rc::new(resolved_function);
695
696            self.stop_function();
697
698            let is_built_in = matches!(
699                function_name_str.as_str(),
700                "to_string" | "to_short_string" | "to_pretty_string" | "default"
701            );
702            if is_built_in {
703                self.shared
704                    .state
705                    .associated_impls
706                    .remove_internal_function_if_exists(attach_to_type, &function_name_str);
707            }
708
709            if let Err(sem_err) = self.shared.state.associated_impls.add_member_function(
710                attach_to_type,
711                &function_name_str,
712                resolved_function_ref,
713            ) {
714                return self.add_err(ErrorKind::SemanticError(sem_err), &function_name.name);
715            }
716        }
717    }
718
719    #[allow(clippy::too_many_lines)]
720    fn analyze_impl_func(
721        &mut self,
722        function: &swamp_ast::Function,
723        self_type: &TypeRef,
724        existing_function_id: Option<InternalFunctionId>,
725    ) -> Function {
726        match function {
727            swamp_ast::Function::Internal(function_data) => {
728                let mut parameters = Vec::new();
729
730                if let Some(found_self) = &function_data.declaration.self_parameter {
731                    let actual_self_type = self_type.clone();
732                    parameters.push(TypeForParameter {
733                        name: self.get_text(&found_self.self_node).to_string(),
734                        resolved_type: actual_self_type,
735                        is_mutable: found_self.is_mutable.is_some(),
736                        node: Option::from(ParameterNode {
737                            name: self.to_node(&found_self.self_node),
738                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
739                        }),
740                    });
741                }
742
743                for param in &function_data.declaration.params {
744                    let resolved_type = self.analyze_type(&param.param_type);
745
746                    let resolved_param = TypeForParameter {
747                        name: self.get_text(&param.variable.name).to_string(),
748                        resolved_type,
749                        is_mutable: param.variable.is_mutable.is_some(),
750                        node: Option::from(ParameterNode {
751                            name: self.to_node(&param.variable.name),
752                            is_mutable: self
753                                .to_node_option(Option::from(&param.variable.is_mutable)),
754                        }),
755                    };
756
757                    parameters.push(resolved_param);
758                }
759
760                let return_type =
761                    if let Some(ast_return_type) = &function_data.declaration.return_type {
762                        self.analyze_type(ast_return_type)
763                    } else {
764                        self.shared.state.types.unit()
765                    };
766
767                for param in &parameters {
768                    self.create_parameter_resolved(
769                        &param.node.as_ref().unwrap().name,
770                        param.node.as_ref().unwrap().is_mutable.as_ref(),
771                        &param.resolved_type.clone(),
772                    );
773                }
774
775                let statements =
776                    self.analyze_function_body_expression(&function_data.body, &return_type);
777
778                let attributes = self.analyze_attributes(&function_data.attributes);
779
780                let internal = InternalFunctionDefinition {
781                    signature: Signature {
782                        parameters,
783                        return_type,
784                    },
785                    body: statements,
786                    name: LocalIdentifier(self.to_node(&function_data.declaration.name)),
787                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
788                    defined_in_module_path: self.module_path.clone(),
789                    associated_with_type: Some(self_type.clone()),
790                    function_variables: self.scope.total_scopes.clone(),
791                    program_unique_id: existing_function_id
792                        .unwrap_or_else(|| self.shared.state.allocate_internal_function_id()),
793                    attributes,
794                };
795
796                let internal_ref = Rc::new(internal);
797
798                Function::Internal(internal_ref)
799            }
800
801            swamp_ast::Function::External(int_node, signature) => {
802                let mut parameters = Vec::new();
803
804                if let Some(found_self) = &signature.self_parameter {
805                    let param = TypeForParameter {
806                        name: self.get_text(&found_self.self_node).to_string(),
807                        resolved_type: self_type.clone(),
808                        is_mutable: found_self.is_mutable.is_some(),
809                        node: Option::from(ParameterNode {
810                            name: self.to_node(&found_self.self_node),
811                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
812                        }),
813                    };
814
815                    parameters.push(param);
816                }
817
818                for param in &signature.params {
819                    let resolved_type = self.analyze_type(&param.param_type);
820
821                    parameters.push(TypeForParameter {
822                        name: self.get_text(&param.variable.name).to_string(),
823                        resolved_type,
824                        is_mutable: param.variable.is_mutable.is_some(),
825                        node: Option::from(ParameterNode {
826                            name: self.to_node(&param.variable.name),
827                            is_mutable: self
828                                .to_node_option(Option::from(&param.variable.is_mutable)),
829                        }),
830                    });
831                }
832
833                let return_type = self.analyze_maybe_type(Option::from(&signature.return_type));
834
835                let int_string = self.get_text(int_node);
836                let external_function_id_int = Self::str_to_int(int_string).unwrap() as u32;
837
838                let external_function_id = external_function_id_int as ExternalFunctionId;
839
840                let external = ExternalFunctionDefinition {
841                    assigned_name: self.get_text(&signature.name).to_string(),
842                    name: Some(self.to_node(&signature.name)),
843                    signature: Signature {
844                        parameters,
845                        return_type,
846                    },
847                    id: external_function_id,
848                };
849
850                let external_ref = Rc::new(external);
851
852                Function::External(external_ref)
853            }
854        }
855    }
856
857    // Helper method to check if a type needs any string functions
858    fn needs_any_string_functions(&self, ty: &TypeRef) -> bool {
859        // TODO: Maybe reverse the check, it is basically primitives that should
860        // not need string functions.
861        let should_have_string_functions = matches!(
862            &*ty.kind,
863            TypeKind::Enum(_)
864                | TypeKind::NamedStruct(_)
865                | TypeKind::AnonymousStruct(_)
866                | TypeKind::Tuple(_)
867                | TypeKind::FixedCapacityAndLengthArray(_, _)
868                | TypeKind::SliceView(_)
869                | TypeKind::DynamicLengthVecView(_)
870                | TypeKind::VecStorage(_, _)
871                | TypeKind::StackView(_)
872                | TypeKind::QueueView(_)
873                | TypeKind::StringStorage(_, _, _)
874                | TypeKind::StackStorage(_, _)
875                | TypeKind::QueueStorage(_, _)
876                | TypeKind::SparseView(_)
877                | TypeKind::SparseStorage(_, _)
878                | TypeKind::GridView(_)
879                | TypeKind::GridStorage(_, _, _)
880                | TypeKind::MapStorage(_, _, _)
881                | TypeKind::DynamicLengthMapView(_, _)
882                | TypeKind::Optional(_)
883        );
884
885        if !should_have_string_functions {
886            return false;
887        }
888
889        if !self.shared.state.associated_impls.is_prepared(ty) {
890            return true;
891        }
892
893        let has_to_string = self
894            .shared
895            .state
896            .associated_impls
897            .get_internal_member_function(ty, "to_string")
898            .is_some();
899
900        let has_to_short_string = self
901            .shared
902            .state
903            .associated_impls
904            .get_internal_member_function(ty, "to_short_string")
905            .is_some();
906
907        let has_to_pretty_string = self
908            .shared
909            .state
910            .associated_impls
911            .get_internal_member_function(ty, "to_pretty_string")
912            .is_some();
913
914        !has_to_string || !has_to_short_string || !has_to_pretty_string
915    }
916
917    pub fn add_default_functions(&mut self, type_to_attach_to: &TypeRef, node: &swamp_ast::Node) {
918        if let TypeKind::Enum(enum_type) = &*type_to_attach_to.kind {
919            for (_, variant) in &enum_type.variants {
920                if !matches!(&*variant.payload_type.kind, TypeKind::Unit)
921                    && !TypeRef::ptr_eq(&variant.payload_type, type_to_attach_to)
922                {
923                    let needs_string_functions =
924                        self.needs_any_string_functions(&variant.payload_type);
925
926                    if needs_string_functions {
927                        self.add_default_functions(&variant.payload_type, node);
928                    }
929                }
930            }
931        }
932
933        let underlying = type_to_attach_to;
934
935        if self.needs_any_string_functions(underlying) {
936            if !self
937                .shared
938                .state
939                .associated_impls
940                .is_prepared(type_to_attach_to)
941            {
942                self.shared
943                    .state
944                    .associated_impls
945                    .prepare(type_to_attach_to);
946            }
947
948            if self
949                .shared
950                .state
951                .associated_impls
952                .get_internal_member_function(underlying, "to_string")
953                .is_none()
954            {
955                let to_string_function =
956                    self.generate_to_string_function_for_type(type_to_attach_to, node);
957                self.shared
958                    .state
959                    .associated_impls
960                    .add_internal_function(type_to_attach_to, to_string_function)
961                    .unwrap();
962            }
963
964            if self
965                .shared
966                .state
967                .associated_impls
968                .get_internal_member_function(underlying, "to_short_string")
969                .is_none()
970            {
971                let to_short_string_function =
972                    self.generate_to_short_string_function_for_type(type_to_attach_to, node);
973                self.shared
974                    .state
975                    .associated_impls
976                    .add_internal_function(type_to_attach_to, to_short_string_function)
977                    .unwrap();
978            }
979
980            if self
981                .shared
982                .state
983                .associated_impls
984                .get_internal_member_function(underlying, "to_pretty_string")
985                .is_none()
986            {
987                let to_pretty_string_function =
988                    self.generate_to_pretty_string_function_for_type(type_to_attach_to, node);
989                self.shared
990                    .state
991                    .associated_impls
992                    .add_internal_function(type_to_attach_to, to_pretty_string_function)
993                    .unwrap();
994            }
995        }
996    }
997
998    fn generate_to_string_function_for_type(
999        &mut self,
1000        ty: &TypeRef,
1001        ast_node: &Node,
1002    ) -> InternalFunctionDefinition {
1003        let node = self.to_node(ast_node);
1004        let mut generator = ExpressionGenerator::new(
1005            &mut self.shared.state.types,
1006            &self.shared.state.associated_impls,
1007        );
1008        internal_generate_to_string_function_for_type(
1009            &mut generator,
1010            &mut self.shared.state.internal_function_id_allocator,
1011            &self.module_path,
1012            ty,
1013            &node,
1014            false,
1015        )
1016    }
1017
1018    fn generate_to_short_string_function_for_type(
1019        &mut self,
1020        ty: &TypeRef,
1021        ast_node: &Node,
1022    ) -> InternalFunctionDefinition {
1023        let node = self.to_node(ast_node);
1024        let mut generator = ExpressionGenerator::new(
1025            &mut self.shared.state.types,
1026            &self.shared.state.associated_impls,
1027        );
1028        internal_generate_to_short_string_function_for_type(
1029            &mut generator,
1030            &mut self.shared.state.internal_function_id_allocator,
1031            &self.module_path,
1032            ty,
1033            &node,
1034        )
1035    }
1036
1037    fn generate_to_pretty_string_function_for_type(
1038        &mut self,
1039        ty: &TypeRef,
1040        ast_node: &Node,
1041    ) -> InternalFunctionDefinition {
1042        let node = self.to_node(ast_node);
1043        let mut generator = ExpressionGenerator::new(
1044            &mut self.shared.state.types,
1045            &self.shared.state.associated_impls,
1046        );
1047        internal_generate_to_pretty_string_function_for_type(
1048            &mut generator,
1049            &mut self.shared.state.internal_function_id_allocator,
1050            &self.module_path,
1051            ty,
1052            &node,
1053        )
1054    }
1055}