1use 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 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 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 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 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 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 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 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 ¶meters {
573 let param_type = ¶m.resolved_type;
574 let actual_type = param_type.clone();
575 self.create_parameter_resolved(
576 ¶m.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 pub fn analyze_definition(&mut self, ast_def: &swamp_ast::Definition) {
717 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 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(¶m.param_type, &TypeAnalyzeContext::default());
888
889 let resolved_param = TypeForParameter {
890 name: self.get_text(¶m.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(¶m.variable.name),
895 is_mutable: self
896 .to_node_option(Option::from(¶m.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 ¶meters {
911 self.create_parameter_resolved(
912 ¶m.node.as_ref().unwrap().name,
913 param.node.as_ref().unwrap().is_mutable.as_ref(),
914 ¶m.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(¶m.param_type, &TypeAnalyzeContext::default());
978
979 parameters.push(TypeForParameter {
980 name: self.get_text(¶m.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(¶m.variable.name),
985 is_mutable: self
986 .to_node_option(Option::from(¶m.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 pub fn on_type_encountered(&mut self, ty: &TypeRef, node: &swamp_ast::Node) {
1017 if self.needs_any_string_functions(ty) {
1019 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 fn needs_any_string_functions(&self, ty: &TypeRef) -> bool {
1035 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 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 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 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}