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_pretty_string_parameterless_function_for_type,
9    internal_generate_to_short_string_function_for_type,
10    internal_generate_to_string_function_for_type,
11};
12use crate::types::TypeAnalyzeContext;
13use seq_map::SeqMap;
14use std::rc::Rc;
15use swamp_ast::Node;
16use swamp_attributes::Attributes;
17use swamp_modules::symtbl::AliasType;
18use swamp_semantic::err::ErrorKind;
19use swamp_semantic::{
20    ExternalFunctionDefinition, ExternalFunctionId, Function, InternalFunctionDefinition,
21    InternalFunctionId, LocalIdentifier, UseItem,
22};
23use swamp_symbol::{Symbol, SymbolKind, TopLevelSymbolId};
24use swamp_types::prelude::*;
25use tracing::debug;
26
27impl Analyzer<'_> {
28    fn general_import(
29        &mut self,
30        path: &[String],
31        import_items: &swamp_ast::ImportItems,
32        node: &swamp_ast::Node,
33    ) {
34        let found_module = if let Some(module) = self.shared.get_module(path) {
35            module.clone()
36        } else {
37            self.add_err(ErrorKind::UnknownModule, node);
38            return;
39        };
40
41        let name_node = self.to_node(node);
42
43        match import_items {
44            swamp_ast::ImportItems::Nothing => {
45                let last_name = path.last().unwrap();
46                if self
47                    .shared
48                    .lookup_table
49                    .get_module_link(last_name)
50                    .is_none()
51                {
52                    match self.shared.lookup_table.add_module_link(
53                        last_name,
54                        &name_node,
55                        found_module.clone(),
56                    ) {
57                        Ok(_x) => {}
58                        Err(err) => {
59                            self.add_err(ErrorKind::SemanticError(err), node);
60                        }
61                    }
62                }
63            }
64            swamp_ast::ImportItems::Items(items) => {
65                for ast_items in items {
66                    match ast_items {
67                        swamp_ast::ImportItem::Identifier(node) => {
68                            let ident_resolved_node = self.to_node(&node.0);
69                            let ident = UseItem::Identifier(ident_resolved_node.clone());
70                            let ident_text =
71                                self.get_text_resolved(&ident_resolved_node).to_string();
72                            if let Some(found_symbol) =
73                                found_module.definition_table.get_symbol(&ident_text)
74                            {
75                                if let Err(sem_err) = self
76                                    .shared
77                                    .lookup_table
78                                    .add_symbol(&ident_text, found_symbol.clone())
79                                {
80                                    self.add_err(ErrorKind::SemanticError(sem_err), &node.0);
81                                    return;
82                                }
83                            } else {
84                                return self.add_err_resolved(
85                                    ErrorKind::UnknownTypeReference,
86                                    &ident_resolved_node,
87                                );
88                            }
89                            ident
90                        }
91                        swamp_ast::ImportItem::Type(node) => {
92                            let ident_resolved_node = self.to_node(&node.0);
93                            let ident_text =
94                                self.get_text_resolved(&ident_resolved_node).to_string();
95                            if let Some(found_symbol) =
96                                found_module.definition_table.get_symbol(&ident_text)
97                            {
98                                if let Err(sem_err) = self
99                                    .shared
100                                    .lookup_table
101                                    .add_symbol(&ident_text, found_symbol.clone())
102                                {
103                                    self.add_err(ErrorKind::SemanticError(sem_err), &node.0);
104                                    return;
105                                }
106                            } else {
107                                return self.add_err_resolved(
108                                    ErrorKind::UnknownTypeReference,
109                                    &ident_resolved_node,
110                                );
111                            }
112                            UseItem::TypeIdentifier(self.to_node(&node.0))
113                        }
114                    };
115                }
116            }
117            swamp_ast::ImportItems::All => {
118                if let Err(sem_err) = self
119                    .shared
120                    .lookup_table
121                    .extend_from(&found_module.definition_table)
122                {
123                    self.add_err(ErrorKind::SemanticError(sem_err), node);
124                }
125            }
126        }
127    }
128
129    fn analyze_mod_definition(&mut self, mod_definition: &swamp_ast::Mod) {
130        let mut path = Vec::new();
131        for ast_node in &mod_definition.module_path.0 {
132            path.push(self.get_text(ast_node).to_string());
133        }
134
135        let mut nodes_copy = path.clone();
136        nodes_copy.insert(0, "crate".to_string());
137
138        self.general_import(
139            &nodes_copy,
140            &mod_definition.items,
141            &mod_definition.module_path.0[0],
142        );
143    }
144
145    fn analyze_use_definition(&mut self, use_definition: &swamp_ast::Use) {
146        let mut nodes = Vec::new();
147        for ast_node in &use_definition.module_path.0 {
148            nodes.push(self.to_node(ast_node));
149        }
150
151        let path: Vec<String> = nodes
152            .iter()
153            .map(|node| {
154                let text = self.get_text_resolved(node);
155                text.to_string()
156            })
157            .collect();
158
159        self.general_import(
160            &path,
161            &use_definition.items,
162            &use_definition.module_path.0[0],
163        );
164    }
165
166    fn analyze_enum_type_definition(
167        &mut self,
168        enum_type_name: &swamp_ast::LocalTypeIdentifierWithOptionalTypeVariables,
169        ast_variants: &[swamp_ast::EnumVariantType],
170    ) {
171        let mut resolved_variants = SeqMap::new();
172
173        let name_node = self.to_node(&enum_type_name.name);
174
175        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
176        self.shared.state.symbols.insert_top(
177            symbol_id,
178            Symbol {
179                id: symbol_id.into(),
180                kind: SymbolKind::Enum,
181                source_map_node: name_node.clone(),
182                name: name_node.clone(),
183            },
184        );
185
186        let mut new_enum_type = EnumType {
187            symbol_id,
188            name: name_node,
189            assigned_name: self.get_text(&enum_type_name.name).to_string(),
190            module_path: vec![],
191            variants: SeqMap::default(),
192            instantiated_type_parameters: Vec::default(),
193        };
194
195        for (container_index_usize, ast_variant_type) in ast_variants.iter().enumerate() {
196            let variant_name_node = match ast_variant_type {
197                swamp_ast::EnumVariantType::Simple(name) => name,
198                swamp_ast::EnumVariantType::Direct(name, _) => name,
199                swamp_ast::EnumVariantType::Tuple(name, _) => name,
200                swamp_ast::EnumVariantType::Struct(name, _) => name,
201            };
202
203            let name_node_for_variant = self.to_node(variant_name_node);
204
205            let variant_symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
206            self.shared.state.symbols.insert_top(
207                variant_symbol_id,
208                Symbol {
209                    id: variant_symbol_id.into(),
210                    kind: SymbolKind::EnumVariant,
211                    source_map_node: name_node_for_variant.clone(),
212                    name: name_node_for_variant.clone(),
213                },
214            );
215
216            let common = EnumVariantCommon {
217                symbol_id: variant_symbol_id,
218                name: name_node_for_variant,
219                assigned_name: self.get_text(variant_name_node).to_string(),
220                container_index: container_index_usize as u8,
221            };
222
223            let payload_type = match ast_variant_type {
224                swamp_ast::EnumVariantType::Simple(_variant_name_node) => self.types().unit(),
225                swamp_ast::EnumVariantType::Direct(variant_name_node, direct_type) => {
226                    let analyzed_type =
227                        self.analyze_type(direct_type, &TypeAnalyzeContext::default());
228                    // If the direct_type is actually a single-element tuple, unwrap it
229                    let final_type = match &*analyzed_type.kind {
230                        TypeKind::Tuple(elements) if elements.len() == 1 => elements[0].clone(),
231                        _ => analyzed_type,
232                    };
233
234                    if !final_type.is_storage() {
235                        self.add_err(ErrorKind::NeedStorage, variant_name_node);
236                    }
237
238                    final_type
239                }
240                swamp_ast::EnumVariantType::Tuple(variant_name_node, types) => {
241                    let mut vec = Vec::new();
242                    for tuple_type in types {
243                        let resolved_type =
244                            self.analyze_type(tuple_type, &TypeAnalyzeContext::default());
245                        vec.push(resolved_type);
246                    }
247
248                    // Single-element tuples should be treated as direct types
249                    let tuple_type = if vec.len() == 1 {
250                        vec.into_iter().next().unwrap()
251                    } else {
252                        self.types().tuple(vec)
253                    };
254
255                    if !tuple_type.is_storage() {
256                        self.add_err(ErrorKind::NeedStorage, variant_name_node);
257                    }
258
259                    tuple_type
260                }
261                swamp_ast::EnumVariantType::Struct(variant_name_node, ast_struct_fields) => {
262                    let mut fields = SeqMap::new();
263
264                    for field_with_type in &ast_struct_fields.fields {
265                        let resolved_type = self.analyze_type(
266                            &field_with_type.field_type,
267                            &TypeAnalyzeContext::default(),
268                        );
269                        let field_name_str =
270                            self.get_text(&field_with_type.field_name.0).to_string();
271
272                        let name_node = self.to_node(&field_with_type.field_name.0);
273
274                        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
275                        self.shared.state.symbols.insert_top(
276                            symbol_id,
277                            Symbol {
278                                id: symbol_id.into(),
279                                kind: SymbolKind::EnumPayloadStructField,
280                                source_map_node: name_node.clone(),
281                                name: name_node.clone(),
282                            },
283                        );
284
285                        let resolved_field = StructTypeField {
286                            symbol_id,
287                            identifier: Some(name_node),
288                            field_type: resolved_type,
289                        };
290
291                        if let Err(_seq_map_err) = fields.insert(field_name_str, resolved_field) {
292                            return self.add_err(
293                                ErrorKind::DuplicateFieldName,
294                                &field_with_type.field_name.0,
295                            );
296                        }
297                    }
298
299                    let anonymous_struct_type = AnonymousStructType {
300                        field_name_sorted_fields: fields,
301                    };
302
303                    self.types().anonymous_struct(anonymous_struct_type)
304                }
305            };
306
307            let enum_variant_type = swamp_types::prelude::EnumVariantType {
308                common,
309                payload_type,
310            };
311
312            let variant_name_str = self.get_text(variant_name_node).to_string();
313
314            if let Err(_seq_map_err) = resolved_variants.insert(variant_name_str, enum_variant_type)
315            {
316                return self.add_err(ErrorKind::DuplicateFieldName, variant_name_node);
317            }
318        }
319
320        new_enum_type.variants = resolved_variants;
321
322        let enum_type_ref = self.shared.state.types.enum_type(new_enum_type);
323
324        if let Err(sem_err) = self
325            .shared
326            .definition_table
327            .add_named_type(enum_type_ref.clone())
328        {
329            return self.add_err(ErrorKind::SemanticError(sem_err), &enum_type_name.name);
330        }
331
332        if let Err(sem_err) = self
333            .shared
334            .lookup_table
335            .add_named_type(enum_type_ref.clone())
336        {
337            return self.add_err(ErrorKind::SemanticError(sem_err), &enum_type_name.name);
338        }
339
340        if !enum_type_ref.is_storage() {
341            self.add_err(ErrorKind::NeedStorage, &enum_type_name.name);
342        }
343
344        self.add_default_functions(&enum_type_ref, &enum_type_name.name);
345    }
346
347    /// # Errors
348    ///
349    pub fn analyze_alias_type_definition(&mut self, ast_alias: &swamp_ast::AliasType) -> AliasType {
350        let resolved_type =
351            self.analyze_type(&ast_alias.referenced_type, &TypeAnalyzeContext::default());
352
353        // Ensure string functions are generated for the resolved type
354        self.ensure_default_functions_for_type(&resolved_type, &ast_alias.identifier.0);
355
356        let alias_name_str = self.get_text(&ast_alias.identifier.0).to_string();
357        let name_node = self.to_node(&ast_alias.identifier.0);
358        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
359        self.shared.state.symbols.insert_top(
360            symbol_id,
361            Symbol {
362                id: symbol_id.into(),
363                kind: SymbolKind::Alias,
364                source_map_node: name_node.clone(),
365                name: name_node.clone(),
366            },
367        );
368        let resolved_alias = AliasType {
369            symbol_id,
370            name: name_node,
371            ty: resolved_type,
372            assigned_name: alias_name_str,
373        };
374
375        let resolved_alias_ref = match self.shared.definition_table.add_alias(resolved_alias) {
376            Ok(re) => re,
377
378            Err(err) => {
379                self.add_err(ErrorKind::SemanticError(err), &ast_alias.identifier.0);
380                AliasType {
381                    symbol_id: TopLevelSymbolId::new_illegal(),
382                    name: source_map_node::Node::default(),
383                    assigned_name: "err".to_string(),
384                    ty: self.types().unit(),
385                }
386            }
387        };
388
389        if let Err(sem_err) = self
390            .shared
391            .lookup_table
392            .add_alias_link(resolved_alias_ref.clone())
393        {
394            self.add_err(ErrorKind::SemanticError(sem_err), &ast_alias.identifier.0);
395            AliasType {
396                symbol_id: TopLevelSymbolId::new_illegal(),
397                name: source_map_node::Node::default(),
398                assigned_name: "err".to_string(),
399                ty: self.types().unit(),
400            }
401        } else {
402            resolved_alias_ref
403        }
404    }
405
406    /// # Errors
407    ///
408    pub fn analyze_anonymous_struct_type(
409        &mut self,
410        ast_struct: &swamp_ast::AnonymousStructType,
411        ctx: &TypeAnalyzeContext,
412    ) -> AnonymousStructType {
413        let resolved_fields = self.analyze_anonymous_struct_type_fields(&ast_struct.fields, ctx);
414
415        AnonymousStructType::new_and_sort_fields(&resolved_fields)
416    }
417
418    /// # Errors
419    ///
420    pub fn analyze_anonymous_struct_type_fields(
421        &mut self,
422        ast_struct_fields: &[swamp_ast::StructTypeField],
423        ctx: &TypeAnalyzeContext,
424    ) -> SeqMap<String, StructTypeField> {
425        let mut resolved_fields = SeqMap::new();
426
427        for field_name_and_type in ast_struct_fields {
428            let resolved_type = self.analyze_type(&field_name_and_type.field_type, ctx);
429            let name_string = self.get_text(&field_name_and_type.field_name.0).to_string();
430
431            if !resolved_type.can_be_stored_in_transient_field() {
432                self.add_err(ErrorKind::NeedStorage, &field_name_and_type.field_name.0);
433                return resolved_fields;
434            }
435
436            if !resolved_type.can_be_stored_in_field() {
437                self.add_hint(ErrorKind::NeedStorage, &field_name_and_type.field_name.0);
438            }
439            let name_node = self.to_node(&field_name_and_type.field_name.0);
440
441            let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
442            self.shared.state.symbols.insert_top(
443                symbol_id,
444                Symbol {
445                    id: symbol_id.into(),
446                    kind: SymbolKind::NamedStructField,
447                    source_map_node: name_node.clone(),
448                    name: name_node.clone(),
449                },
450            );
451
452            let field_type = StructTypeField {
453                symbol_id,
454                identifier: Some(name_node),
455                field_type: resolved_type,
456            };
457
458            if let Err(_seq_map_err) = resolved_fields.insert(name_string, field_type) {
459                self.add_err(
460                    ErrorKind::DuplicateFieldName,
461                    &field_name_and_type.field_name.0,
462                );
463            }
464        }
465
466        resolved_fields
467    }
468
469    /// # Errors
470    ///
471    pub fn analyze_named_struct_type_definition(
472        &mut self,
473        ast_struct_def: &swamp_ast::NamedStructDef,
474    ) {
475        let struct_name_str = self.get_text(&ast_struct_def.identifier.name).to_string();
476
477        let fields = self.analyze_anonymous_struct_type_fields(
478            &ast_struct_def.struct_type.fields,
479            &TypeAnalyzeContext::default(),
480        );
481
482        let analyzed_anonymous_struct = AnonymousStructType::new(fields);
483
484        let anon_struct_type_ref = self
485            .shared
486            .state
487            .types
488            .anonymous_struct(analyzed_anonymous_struct);
489
490        let name_node = self.to_node(&ast_struct_def.identifier.name);
491
492        let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
493        self.shared.state.symbols.insert_top(
494            symbol_id,
495            Symbol {
496                id: symbol_id.into(),
497                kind: SymbolKind::NamedStruct,
498                source_map_node: name_node.clone(),
499                name: name_node.clone(),
500            },
501        );
502
503        let named_struct_type = NamedStructType {
504            symbol_id,
505            name: name_node,
506            anon_struct_type: anon_struct_type_ref,
507            assigned_name: struct_name_str,
508            module_path: self.shared.definition_table.module_path(),
509        };
510
511        let named_struct_type_ref = self.shared.state.types.named_struct(named_struct_type);
512
513        match self
514            .shared
515            .definition_table
516            .add_named_type(named_struct_type_ref.clone())
517        {
518            Ok(()) => {}
519            Err(sem_err) => {
520                return self.add_err(
521                    ErrorKind::SemanticError(sem_err),
522                    &ast_struct_def.identifier.name,
523                );
524            }
525        }
526
527        match self
528            .shared
529            .lookup_table
530            .add_named_type(named_struct_type_ref.clone())
531        {
532            Ok(()) => {}
533            Err(sem_err) => {
534                return self.add_err(
535                    ErrorKind::SemanticError(sem_err),
536                    &ast_struct_def.identifier.name,
537                );
538            }
539        }
540
541        if !named_struct_type_ref.is_storage() {
542            self.add_err(ErrorKind::NeedStorage, &ast_struct_def.identifier.name);
543        }
544
545        self.add_default_functions(&named_struct_type_ref, &ast_struct_def.identifier.name);
546    }
547
548    #[allow(clippy::too_many_lines)]
549    pub(crate) fn analyze_function_definition(
550        &mut self,
551        function: &swamp_ast::Function,
552        attributes: &Attributes,
553    ) -> Option<Function> {
554        let func = match &function {
555            swamp_ast::Function::Internal(function_data) => {
556                let parameters = self.analyze_parameters(&function_data.declaration.params);
557                let return_type = if let Some(found) = &function_data.declaration.return_type {
558                    let analyzed_return_type =
559                        self.analyze_type(found, &TypeAnalyzeContext::default());
560                    if !analyzed_return_type.allowed_as_return_type() {
561                        self.add_err(
562                            ErrorKind::NotAllowedAsReturnType(analyzed_return_type),
563                            function.node(),
564                        );
565                        return None;
566                    }
567                    analyzed_return_type
568                } else {
569                    self.shared.state.types.unit()
570                };
571
572                for param in &parameters {
573                    let param_type = &param.resolved_type;
574                    let actual_type = param_type.clone();
575                    self.create_parameter_resolved(
576                        &param.node.as_ref().unwrap().name,
577                        param.node.as_ref().unwrap().is_mutable.as_ref(),
578                        &actual_type,
579                    );
580                }
581                let function_name = self
582                    .get_text(&function_data.declaration.name)
583                    .trim()
584                    .to_string();
585
586                let name_node = self.to_node(&function_data.declaration.name);
587                let statements =
588                    self.analyze_function_body_expression(&function_data.body, &return_type);
589
590                let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
591                self.shared.state.symbols.insert_top(
592                    symbol_id,
593                    Symbol {
594                        id: symbol_id.into(),
595                        kind: SymbolKind::Function,
596                        source_map_node: name_node.clone(),
597                        name: name_node.clone(),
598                    },
599                );
600                let internal = InternalFunctionDefinition {
601                    symbol_id,
602                    signature: Signature {
603                        parameters,
604                        return_type,
605                    },
606                    body: statements,
607                    name: LocalIdentifier(name_node),
608                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
609                    associated_with_type: None,
610                    defined_in_module_path: self.module_path.clone(),
611                    function_variables: self.scope.total_scopes.clone(),
612                    program_unique_id: self.shared.state.allocate_internal_function_id(),
613                    attributes: attributes.clone(),
614                };
615
616                let function_ref = match self
617                    .shared
618                    .definition_table
619                    .add_internal_function(&function_name, internal)
620                {
621                    Ok(func_def) => func_def,
622                    Err(sem_err) => {
623                        self.add_err(
624                            ErrorKind::SemanticError(sem_err),
625                            &function_data.declaration.name,
626                        );
627                        return None;
628                    }
629                };
630
631                match self
632                    .shared
633                    .lookup_table
634                    .add_internal_function_link(&function_name, function_ref.clone())
635                {
636                    Ok(()) => {}
637                    Err(sem_err) => {
638                        self.add_err(
639                            ErrorKind::SemanticError(sem_err),
640                            &function_data.declaration.name,
641                        );
642                        return None;
643                    }
644                }
645
646                Function::Internal(function_ref)
647            }
648            swamp_ast::Function::External(int_node, ast_signature) => {
649                let parameters = self.analyze_parameters(&ast_signature.params);
650                let external_return_type = if let Some(found) = &ast_signature.return_type {
651                    self.analyze_type(found, &TypeAnalyzeContext::default())
652                } else {
653                    self.shared.state.types.unit()
654                };
655
656                let return_type = external_return_type;
657
658                let int_string = self.get_text(int_node);
659                let external_function_id_int = Self::str_to_int(int_string).unwrap() as u32;
660
661                let external_function_id = external_function_id_int as ExternalFunctionId;
662
663                let external = ExternalFunctionDefinition {
664                    assigned_name: self.get_text(&ast_signature.name).to_string(),
665                    signature: Signature {
666                        parameters,
667                        return_type,
668                    },
669                    name: self.to_node(&ast_signature.name),
670                    id: external_function_id,
671                };
672
673                let function_ref = match self
674                    .shared
675                    .definition_table
676                    .add_external_function_declaration(external)
677                {
678                    Ok(func_ref) => func_ref,
679                    Err(sem_err) => {
680                        self.add_err(ErrorKind::SemanticError(sem_err), &ast_signature.name);
681                        return None;
682                    }
683                };
684
685                if let Err(sem_err) = self
686                    .shared
687                    .lookup_table
688                    .add_external_function_declaration_link(function_ref.clone())
689                {
690                    self.add_err(ErrorKind::SemanticError(sem_err), &ast_signature.name);
691                    return None;
692                }
693
694                Function::External(function_ref)
695            }
696        };
697
698        Some(func)
699    }
700
701    pub fn debug_definition(&self, definition: &swamp_ast::Definition) {
702        let (line, col) = self
703            .shared
704            .source_map
705            .get_span_location_utf8(self.shared.file_id, definition.node.span.offset as usize);
706        let source_line = self
707            .shared
708            .source_map
709            .get_source_line(self.shared.file_id, line)
710            .unwrap();
711        debug!(?line, ?col, ?source_line);
712    }
713
714    /// # Errors
715    ///
716    pub fn analyze_definition(&mut self, ast_def: &swamp_ast::Definition) {
717        //self.debug_definition(ast_def);
718
719        let analyzed_attributes = self.analyze_attributes(&ast_def.attributes);
720
721        match &ast_def.kind {
722            swamp_ast::DefinitionKind::NamedStructDef(ast_struct) => {
723                self.analyze_named_struct_type_definition(ast_struct);
724            }
725            swamp_ast::DefinitionKind::AliasDef(alias_def) => {
726                self.analyze_alias_type_definition(alias_def);
727            }
728            swamp_ast::DefinitionKind::EnumDef(identifier, variants) => {
729                self.analyze_enum_type_definition(identifier, variants);
730            }
731            swamp_ast::DefinitionKind::FunctionDef(function) => {
732                let _resolved_return_type = self.analyze_return_type(function);
733                self.start_function(function.node());
734                self.analyze_function_definition(function, &analyzed_attributes);
735                self.stop_function();
736            }
737            swamp_ast::DefinitionKind::ImplDef(type_identifier, functions) => {
738                self.analyze_impl_definition(type_identifier, functions);
739            }
740            swamp_ast::DefinitionKind::Mod(mod_info) => self.analyze_mod_definition(mod_info),
741            swamp_ast::DefinitionKind::Use(use_info) => self.analyze_use_definition(use_info),
742            swamp_ast::DefinitionKind::Constant(const_info) => {
743                self.analyze_constant_definition(const_info);
744            }
745        }
746    }
747
748    fn analyze_impl_definition(
749        &mut self,
750        attached_to_type: &swamp_ast::LocalTypeIdentifierWithOptionalTypeVariables,
751        functions: &[swamp_ast::Function],
752    ) {
753        let converted_type_variables_to_ast_types = attached_to_type
754            .type_variables
755            .iter()
756            .map(|x| {
757                swamp_ast::GenericParameter::Type(swamp_ast::Type::Named(
758                    swamp_ast::QualifiedTypeIdentifier {
759                        name: swamp_ast::LocalTypeIdentifier(x.0.clone()),
760                        module_path: None,
761                        generic_params: vec![],
762                    },
763                ))
764            })
765            .collect();
766
767        let qualified = swamp_ast::QualifiedTypeIdentifier {
768            name: swamp_ast::LocalTypeIdentifier(attached_to_type.name.clone()),
769            module_path: None,
770            generic_params: converted_type_variables_to_ast_types,
771        };
772
773        let maybe_type_to_attach_to = Some(self.analyze_named_type(&qualified));
774        if let Some(type_to_attach_to) = maybe_type_to_attach_to {
775            let function_refs: Vec<&swamp_ast::Function> = functions.iter().collect();
776            self.analyze_impl_functions(&type_to_attach_to, &function_refs);
777        } else {
778            self.add_err(
779                ErrorKind::CanNotAttachFunctionsToType,
780                &attached_to_type.name,
781            );
782        }
783    }
784
785    /// # Errors
786    ///
787    pub fn analyze_impl_functions(
788        &mut self,
789        attach_to_type: &TypeRef,
790        functions: &[&swamp_ast::Function],
791    ) {
792        if !self
793            .shared
794            .state
795            .associated_impls
796            .is_prepared(attach_to_type)
797        {
798            self.shared.state.associated_impls.prepare(attach_to_type);
799        }
800
801        for function in functions {
802            let function_name = match function {
803                swamp_ast::Function::Internal(function_with_body) => {
804                    &function_with_body.declaration
805                }
806                swamp_ast::Function::External(_, external_declaration) => external_declaration,
807            };
808            self.start_function(&function_name.name);
809
810            let function_name_str = self.get_text(&function_name.name).to_string();
811
812            let existing_function_id = if matches!(
813                function_name_str.as_str(),
814                "string"
815                    | "short_string"
816                    | "pretty_string"
817                    | "pretty_string_with_indent"
818                    | "default"
819            ) {
820                self.shared
821                    .state
822                    .associated_impls
823                    .get_internal_member_function(attach_to_type, &function_name_str)
824                    .map(|existing_fn| existing_fn.program_unique_id)
825            } else {
826                None
827            };
828
829            let resolved_function =
830                self.analyze_impl_func(function, attach_to_type, existing_function_id);
831
832            let resolved_function_ref = Rc::new(resolved_function);
833
834            self.stop_function();
835
836            let is_built_in = matches!(
837                function_name_str.as_str(),
838                "string"
839                    | "short_string"
840                    | "pretty_string"
841                    | "pretty_string_with_indent"
842                    | "default"
843            );
844            if is_built_in {
845                self.shared
846                    .state
847                    .associated_impls
848                    .remove_internal_function_if_exists(attach_to_type, &function_name_str);
849            }
850
851            if let Err(sem_err) = self.shared.state.associated_impls.add_member_function(
852                attach_to_type,
853                &function_name_str,
854                resolved_function_ref,
855            ) {
856                return self.add_err(ErrorKind::SemanticError(sem_err), &function_name.name);
857            }
858        }
859    }
860
861    #[allow(clippy::too_many_lines)]
862    fn analyze_impl_func(
863        &mut self,
864        function: &swamp_ast::Function,
865        self_type: &TypeRef,
866        existing_function_id: Option<InternalFunctionId>,
867    ) -> Function {
868        match function {
869            swamp_ast::Function::Internal(function_data) => {
870                let mut parameters = Vec::new();
871
872                if let Some(found_self) = &function_data.declaration.self_parameter {
873                    let actual_self_type = self_type.clone();
874                    parameters.push(TypeForParameter {
875                        name: self.get_text(&found_self.self_node).to_string(),
876                        resolved_type: actual_self_type,
877                        is_mutable: found_self.is_mutable.is_some(),
878                        node: Option::from(ParameterNode {
879                            name: self.to_node(&found_self.self_node),
880                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
881                        }),
882                    });
883                }
884
885                for param in &function_data.declaration.params {
886                    let resolved_type =
887                        self.analyze_type(&param.param_type, &TypeAnalyzeContext::default());
888
889                    let resolved_param = TypeForParameter {
890                        name: self.get_text(&param.variable.name).to_string(),
891                        resolved_type,
892                        is_mutable: param.variable.is_mutable.is_some(),
893                        node: Option::from(ParameterNode {
894                            name: self.to_node(&param.variable.name),
895                            is_mutable: self
896                                .to_node_option(Option::from(&param.variable.is_mutable)),
897                        }),
898                    };
899
900                    parameters.push(resolved_param);
901                }
902
903                let return_type =
904                    if let Some(ast_return_type) = &function_data.declaration.return_type {
905                        self.analyze_type(ast_return_type, &TypeAnalyzeContext::default())
906                    } else {
907                        self.shared.state.types.unit()
908                    };
909
910                for param in &parameters {
911                    self.create_parameter_resolved(
912                        &param.node.as_ref().unwrap().name,
913                        param.node.as_ref().unwrap().is_mutable.as_ref(),
914                        &param.resolved_type.clone(),
915                    );
916                }
917
918                let statements =
919                    self.analyze_function_body_expression(&function_data.body, &return_type);
920
921                let attributes = self.analyze_attributes(&function_data.attributes);
922
923                let symbol_id = self.shared.state.symbol_id_allocator.alloc_top_level();
924
925                let name_node = self.to_node(&function_data.declaration.name);
926                self.shared.state.symbols.insert_top(
927                    symbol_id,
928                    Symbol {
929                        id: symbol_id.into(),
930                        kind: SymbolKind::MemberFunction,
931                        source_map_node: name_node.clone(),
932                        name: name_node.clone(),
933                    },
934                );
935
936                let internal = InternalFunctionDefinition {
937                    symbol_id,
938                    signature: Signature {
939                        parameters,
940                        return_type,
941                    },
942                    body: statements,
943                    name: LocalIdentifier(name_node),
944                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
945                    defined_in_module_path: self.module_path.clone(),
946                    associated_with_type: Some(self_type.clone()),
947                    function_variables: self.scope.total_scopes.clone(),
948                    program_unique_id: existing_function_id
949                        .unwrap_or_else(|| self.shared.state.allocate_internal_function_id()),
950                    attributes,
951                };
952
953                let internal_ref = Rc::new(internal);
954
955                Function::Internal(internal_ref)
956            }
957
958            swamp_ast::Function::External(int_node, signature) => {
959                let mut parameters = Vec::new();
960
961                if let Some(found_self) = &signature.self_parameter {
962                    let param = TypeForParameter {
963                        name: self.get_text(&found_self.self_node).to_string(),
964                        resolved_type: self_type.clone(),
965                        is_mutable: found_self.is_mutable.is_some(),
966                        node: Option::from(ParameterNode {
967                            name: self.to_node(&found_self.self_node),
968                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
969                        }),
970                    };
971
972                    parameters.push(param);
973                }
974
975                for param in &signature.params {
976                    let resolved_type =
977                        self.analyze_type(&param.param_type, &TypeAnalyzeContext::default());
978
979                    parameters.push(TypeForParameter {
980                        name: self.get_text(&param.variable.name).to_string(),
981                        resolved_type,
982                        is_mutable: param.variable.is_mutable.is_some(),
983                        node: Option::from(ParameterNode {
984                            name: self.to_node(&param.variable.name),
985                            is_mutable: self
986                                .to_node_option(Option::from(&param.variable.is_mutable)),
987                        }),
988                    });
989                }
990
991                let return_type = self.analyze_maybe_type(Option::from(&signature.return_type));
992
993                let int_string = self.get_text(int_node);
994                let external_function_id_int = Self::str_to_int(int_string).unwrap() as u32;
995
996                let external_function_id = external_function_id_int as ExternalFunctionId;
997
998                let external = ExternalFunctionDefinition {
999                    assigned_name: self.get_text(&signature.name).to_string(),
1000                    name: self.to_node(&signature.name),
1001                    signature: Signature {
1002                        parameters,
1003                        return_type,
1004                    },
1005                    id: external_function_id,
1006                };
1007
1008                let external_ref = Rc::new(external);
1009
1010                Function::External(external_ref)
1011            }
1012        }
1013    }
1014
1015    /// Called whenever a type is resolved/created during analysis to ensure string functions exist
1016    pub fn on_type_encountered(&mut self, ty: &TypeRef, node: &swamp_ast::Node) {
1017        // Only generate string functions for types that need them and don't already have them
1018        if self.needs_any_string_functions(ty) {
1019            // Check if we already have the functions to avoid infinite recursion
1020            if !self.shared.state.associated_impls.is_prepared(ty)
1021                || self
1022                    .shared
1023                    .state
1024                    .associated_impls
1025                    .get_internal_member_function(ty, "string")
1026                    .is_none()
1027            {
1028                self.add_default_functions(ty, node);
1029            }
1030        }
1031    }
1032
1033    // Helper method to check if a type needs any string functions
1034    fn needs_any_string_functions(&self, ty: &TypeRef) -> bool {
1035        // Types that should not have generated string functions:
1036        // - Primitives: handled in core_text()
1037        // - String types: (they return themselves)
1038        // - Function types: (cannot be stored in fields)
1039        let should_not_have_string_functions = matches!(
1040            &*ty.kind,
1041            TypeKind::Any
1042                | TypeKind::Byte
1043                | TypeKind::Codepoint
1044                | TypeKind::Int
1045                | TypeKind::Float
1046                | TypeKind::Bool
1047                | TypeKind::Range(_)
1048                | TypeKind::StringView(..)
1049                | TypeKind::Function(_)
1050        );
1051
1052        if should_not_have_string_functions {
1053            return false;
1054        }
1055
1056        // Early check - if not prepared at all, definitely needs functions
1057        if !self.shared.state.associated_impls.is_prepared(ty) {
1058            return true;
1059        }
1060
1061        let has_to_string = self
1062            .shared
1063            .state
1064            .associated_impls
1065            .get_internal_member_function(ty, "string")
1066            .is_some();
1067
1068        let has_to_short_string = self
1069            .shared
1070            .state
1071            .associated_impls
1072            .get_internal_member_function(ty, "short_string")
1073            .is_some();
1074
1075        let has_to_pretty_string = self
1076            .shared
1077            .state
1078            .associated_impls
1079            .get_internal_member_function(ty, "pretty_string")
1080            .is_some();
1081
1082        let has_to_pretty_string_with_indent = self
1083            .shared
1084            .state
1085            .associated_impls
1086            .get_internal_member_function(ty, "pretty_string_with_indent")
1087            .is_some();
1088
1089        !has_to_string
1090            || !has_to_short_string
1091            || !has_to_pretty_string
1092            || !has_to_pretty_string_with_indent
1093    }
1094
1095    pub fn add_default_functions(&mut self, type_to_attach_to: &TypeRef, node: &swamp_ast::Node) {
1096        if let TypeKind::Enum(enum_type) = &*type_to_attach_to.kind {
1097            for (_, variant) in &enum_type.variants {
1098                if !matches!(&*variant.payload_type.kind, TypeKind::Unit)
1099                    && !TypeRef::ptr_eq(&variant.payload_type, type_to_attach_to)
1100                {
1101                    let needs_string_functions =
1102                        self.needs_any_string_functions(&variant.payload_type);
1103
1104                    if needs_string_functions {
1105                        self.add_default_functions(&variant.payload_type, node);
1106                    }
1107                }
1108            }
1109        }
1110
1111        // Also check tuple elements and other nested types
1112        match &*type_to_attach_to.kind {
1113            TypeKind::Tuple(tuple_types) => {
1114                for element_type in tuple_types {
1115                    if self.needs_any_string_functions(element_type) {
1116                        self.add_default_functions(element_type, node);
1117                    }
1118                }
1119            }
1120            TypeKind::Optional(inner_type) => {
1121                if self.needs_any_string_functions(inner_type) {
1122                    self.add_default_functions(inner_type, node);
1123                }
1124            }
1125            TypeKind::FixedCapacityAndLengthArray(element_type, _)
1126            | TypeKind::SliceView(element_type)
1127            | TypeKind::DynamicLengthVecView(element_type)
1128            | TypeKind::VecStorage(element_type, _)
1129            | TypeKind::StackView(element_type)
1130            | TypeKind::QueueView(element_type)
1131            | TypeKind::StackStorage(element_type, _)
1132            | TypeKind::QueueStorage(element_type, _)
1133            | TypeKind::SparseView(element_type)
1134            | TypeKind::SparseStorage(element_type, _)
1135            | TypeKind::GridView(element_type)
1136            | TypeKind::GridStorage(element_type, _, _) => {
1137                if self.needs_any_string_functions(element_type) {
1138                    self.add_default_functions(element_type, node);
1139                }
1140            }
1141            TypeKind::MapStorage(key_type, value_type, _)
1142            | TypeKind::DynamicLengthMapView(key_type, value_type) => {
1143                if self.needs_any_string_functions(key_type) {
1144                    self.add_default_functions(key_type, node);
1145                }
1146                if self.needs_any_string_functions(value_type) {
1147                    self.add_default_functions(value_type, node);
1148                }
1149            }
1150            _ => {}
1151        }
1152
1153        let underlying = type_to_attach_to;
1154
1155        if self.needs_any_string_functions(underlying) {
1156            if !self
1157                .shared
1158                .state
1159                .associated_impls
1160                .is_prepared(type_to_attach_to)
1161            {
1162                self.shared
1163                    .state
1164                    .associated_impls
1165                    .prepare(type_to_attach_to);
1166            }
1167
1168            if self
1169                .shared
1170                .state
1171                .associated_impls
1172                .get_internal_member_function(underlying, "string")
1173                .is_none()
1174            {
1175                let to_string_function =
1176                    self.generate_to_string_function_for_type(type_to_attach_to, node);
1177                self.shared
1178                    .state
1179                    .associated_impls
1180                    .add_internal_function(type_to_attach_to, to_string_function)
1181                    .unwrap();
1182            }
1183
1184            if self
1185                .shared
1186                .state
1187                .associated_impls
1188                .get_internal_member_function(underlying, "short_string")
1189                .is_none()
1190            {
1191                let to_short_string_function =
1192                    self.generate_to_short_string_function_for_type(type_to_attach_to, node);
1193                self.shared
1194                    .state
1195                    .associated_impls
1196                    .add_internal_function(type_to_attach_to, to_short_string_function)
1197                    .unwrap();
1198            }
1199
1200            if self
1201                .shared
1202                .state
1203                .associated_impls
1204                .get_internal_member_function(underlying, "pretty_string")
1205                .is_none()
1206            {
1207                let to_pretty_string_function = self
1208                    .generate_to_pretty_string_parameterless_function_for_type(
1209                        type_to_attach_to,
1210                        node,
1211                    );
1212                self.shared
1213                    .state
1214                    .associated_impls
1215                    .add_internal_function(type_to_attach_to, to_pretty_string_function)
1216                    .unwrap();
1217            }
1218
1219            if self
1220                .shared
1221                .state
1222                .associated_impls
1223                .get_internal_member_function(underlying, "pretty_string_with_indent")
1224                .is_none()
1225            {
1226                let to_pretty_string_with_indent_function =
1227                    self.generate_to_pretty_string_function_for_type(type_to_attach_to, node);
1228                self.shared
1229                    .state
1230                    .associated_impls
1231                    .add_internal_function(type_to_attach_to, to_pretty_string_with_indent_function)
1232                    .unwrap();
1233            }
1234        }
1235    }
1236
1237    /// Ensures that a type has all necessary string functions generated
1238    /// This should be called whenever a type is encountered during analysis
1239    pub fn ensure_default_functions_for_type(&mut self, ty: &TypeRef, node: &swamp_ast::Node) {
1240        if self.needs_any_string_functions(ty) {
1241            self.add_default_functions(ty, node);
1242        }
1243    }
1244
1245    fn generate_to_string_function_for_type(
1246        &mut self,
1247        ty: &TypeRef,
1248        ast_node: &Node,
1249    ) -> InternalFunctionDefinition {
1250        let node = self.to_node(ast_node);
1251        let mut generator = ExpressionGenerator::new(
1252            &mut self.shared.state.types,
1253            &self.shared.state.associated_impls,
1254        );
1255        internal_generate_to_string_function_for_type(
1256            &mut generator,
1257            &mut self.shared.state.internal_function_id_allocator,
1258            &mut self.shared.state.symbol_id_allocator,
1259            &mut self.shared.state.symbols,
1260            &self.module_path,
1261            ty,
1262            &node,
1263            false,
1264        )
1265    }
1266
1267    fn generate_to_short_string_function_for_type(
1268        &mut self,
1269        ty: &TypeRef,
1270        ast_node: &Node,
1271    ) -> InternalFunctionDefinition {
1272        let node = self.to_node(ast_node);
1273        let mut generator = ExpressionGenerator::new(
1274            &mut self.shared.state.types,
1275            &self.shared.state.associated_impls,
1276        );
1277        internal_generate_to_short_string_function_for_type(
1278            &mut generator,
1279            &mut self.shared.state.internal_function_id_allocator,
1280            &mut self.shared.state.symbol_id_allocator,
1281            &mut self.shared.state.symbols,
1282            &self.module_path,
1283            ty,
1284            &node,
1285        )
1286    }
1287
1288    fn generate_to_pretty_string_function_for_type(
1289        &mut self,
1290        ty: &TypeRef,
1291        ast_node: &Node,
1292    ) -> InternalFunctionDefinition {
1293        let node = self.to_node(ast_node);
1294        let mut generator = ExpressionGenerator::new(
1295            &mut self.shared.state.types,
1296            &self.shared.state.associated_impls,
1297        );
1298        internal_generate_to_pretty_string_function_for_type(
1299            &mut generator,
1300            &mut self.shared.state.internal_function_id_allocator,
1301            &mut self.shared.state.symbol_id_allocator,
1302            &mut self.shared.state.symbols,
1303            &self.module_path,
1304            ty,
1305            &node,
1306        )
1307    }
1308
1309    fn generate_to_pretty_string_parameterless_function_for_type(
1310        &mut self,
1311        ty: &TypeRef,
1312        ast_node: &Node,
1313    ) -> InternalFunctionDefinition {
1314        let node = self.to_node(ast_node);
1315        let mut generator = ExpressionGenerator::new(
1316            &mut self.shared.state.types,
1317            &self.shared.state.associated_impls,
1318        );
1319        internal_generate_to_pretty_string_parameterless_function_for_type(
1320            &mut generator,
1321            &mut self.shared.state.internal_function_id_allocator,
1322            &mut self.shared.state.symbol_id_allocator,
1323            &mut self.shared.state.symbols,
1324            &self.module_path,
1325            ty,
1326            &node,
1327        )
1328    }
1329}