swamp_script_analyzer/
def.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/script
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use crate::Analyzer;
7use crate::err::{Error, ErrorKind};
8use seq_map::SeqMap;
9use std::rc::Rc;
10use swamp_script_semantic::{
11    AliasType, AliasTypeRef, AnonymousStructType, EnumType, EnumTypeRef, EnumVariantCommon,
12    EnumVariantSimpleType, EnumVariantSimpleTypeRef, EnumVariantStructType, EnumVariantTupleType,
13    EnumVariantType, ExternalFunctionDefinition, Function, InternalFunctionDefinition,
14    LocalIdentifier, LocalTypeIdentifier, NamedStructType, ParameterNode, Signature,
15    StructTypeField, Type, TypeForParameter, UseItem,
16};
17
18impl Analyzer<'_> {
19    fn general_import(
20        &mut self,
21        path: &[String],
22        import_items: &swamp_script_ast::ImportItems,
23        node: &swamp_script_ast::Node,
24    ) -> Result<(), Error> {
25        let found_module = self
26            .shared
27            .get_module(path)
28            .ok_or_else(|| self.create_err(ErrorKind::UnknownModule, node))?
29            .clone();
30
31        match import_items {
32            swamp_script_ast::ImportItems::Nothing => {
33                let last_name = path.last().unwrap();
34                self.shared
35                    .lookup_table
36                    .add_module_link(last_name, found_module.clone())
37                    .map_err(|err| self.create_err(ErrorKind::SemanticError(err), node))?;
38            }
39            swamp_script_ast::ImportItems::Items(items) => {
40                for ast_items in items {
41                    match ast_items {
42                        swamp_script_ast::ImportItem::Identifier(node) => {
43                            let ident_resolved_node = self.to_node(&node.0);
44                            let ident = UseItem::Identifier(ident_resolved_node.clone());
45                            let ident_text =
46                                self.get_text_resolved(&ident_resolved_node).to_string();
47                            if let Some(found_symbol) =
48                                found_module.namespace.symbol_table.get_symbol(&ident_text)
49                            {
50                                self.shared
51                                    .lookup_table
52                                    .add_symbol(&ident_text, found_symbol.clone())
53                                    .map_err(|err| {
54                                        self.create_err(ErrorKind::SemanticError(err), &node.0)
55                                    })?;
56                            } else {
57                                return Err(self.create_err_resolved(
58                                    ErrorKind::UnknownTypeReference,
59                                    &ident_resolved_node,
60                                ));
61                            }
62                            ident
63                        }
64                        swamp_script_ast::ImportItem::Type(node) => {
65                            let ident_resolved_node = self.to_node(&node.0);
66                            let ident_text =
67                                self.get_text_resolved(&ident_resolved_node).to_string();
68                            if let Some(found_symbol) =
69                                found_module.namespace.symbol_table.get_symbol(&ident_text)
70                            {
71                                self.shared
72                                    .lookup_table
73                                    .add_symbol(&ident_text, found_symbol.clone())
74                                    .map_err(|err| {
75                                        self.create_err(ErrorKind::SemanticError(err), &node.0)
76                                    })?;
77                            } else {
78                                return Err(self.create_err_resolved(
79                                    ErrorKind::UnknownTypeReference,
80                                    &ident_resolved_node,
81                                ));
82                            }
83                            UseItem::TypeIdentifier(self.to_node(&node.0))
84                        }
85                    };
86                }
87            }
88            swamp_script_ast::ImportItems::All => {
89                self.shared
90                    .lookup_table
91                    .extend_from(&found_module.namespace.symbol_table)?;
92            }
93        }
94
95        Ok(())
96    }
97
98    fn analyze_mod_definition(
99        &mut self,
100        mod_definition: &swamp_script_ast::Mod,
101    ) -> Result<(), Error> {
102        let mut path = Vec::new();
103        for ast_node in &mod_definition.module_path.0 {
104            path.push(self.get_text(ast_node).to_string());
105        }
106
107        let mut nodes_copy = path.clone();
108        nodes_copy.insert(0, "crate".to_string());
109
110        self.general_import(
111            &nodes_copy,
112            &mod_definition.items,
113            &mod_definition.module_path.0[0],
114        )
115    }
116
117    fn analyze_use_definition(
118        &mut self,
119        use_definition: &swamp_script_ast::Use,
120    ) -> Result<(), Error> {
121        let mut nodes = Vec::new();
122        for ast_node in &use_definition.module_path.0 {
123            nodes.push(self.to_node(ast_node));
124        }
125
126        let path: Vec<String> = nodes
127            .iter()
128            .map(|node| {
129                let text = self.get_text_resolved(node);
130                text.to_string()
131            })
132            .collect();
133
134        self.general_import(
135            &path,
136            &use_definition.items,
137            &use_definition.module_path.0[0],
138        )
139    }
140
141    fn analyze_enum_type_definition(
142        &mut self,
143        enum_type_name: &swamp_script_ast::LocalTypeIdentifier,
144        ast_variants: &[swamp_script_ast::EnumVariantType],
145    ) -> Result<EnumTypeRef, Error> {
146        let mut resolved_variants = SeqMap::new();
147
148        let parent_number = self.shared.state.allocate_number();
149
150        let enum_parent = EnumType {
151            name: LocalTypeIdentifier(self.to_node(&enum_type_name.0)),
152            assigned_name: self.get_text(&enum_type_name.0).to_string(),
153            module_path: vec![],
154            type_id: parent_number,
155            variants: SeqMap::default(),
156        };
157
158        let parent_ref = self
159            .shared
160            .definition_table
161            .add_enum_type(enum_parent)
162            .map_err(|err| self.create_err(ErrorKind::SemanticError(err), &enum_type_name.0))?;
163        self.shared
164            .lookup_table
165            .add_enum_type_link(parent_ref.clone())
166            .map_err(|err| self.create_err(ErrorKind::SemanticError(err), &enum_type_name.0))?;
167
168        for (container_index_usize, ast_variant_type) in ast_variants.iter().enumerate() {
169            let variant_name_node = match ast_variant_type {
170                swamp_script_ast::EnumVariantType::Simple(name) => name,
171                swamp_script_ast::EnumVariantType::Tuple(name, _) => name,
172                swamp_script_ast::EnumVariantType::Struct(name, _) => name,
173            };
174
175            let number = self.shared.state.allocate_number();
176
177            let common = EnumVariantCommon {
178                name: LocalTypeIdentifier(self.to_node(variant_name_node)),
179                number,
180                assigned_name: self.get_text(variant_name_node).to_string(),
181                container_index: container_index_usize as u8,
182                owner: parent_ref.clone(),
183            };
184
185            let variant_type = match ast_variant_type {
186                swamp_script_ast::EnumVariantType::Simple(_variant_name_node) => {
187                    let simple_ref = EnumVariantSimpleType { common };
188                    EnumVariantType::Nothing(EnumVariantSimpleTypeRef::from(simple_ref))
189                }
190                swamp_script_ast::EnumVariantType::Tuple(variant_name_node, types) => {
191                    let mut vec = Vec::new();
192                    for tuple_type in types {
193                        let resolved_type = self.analyze_type(tuple_type)?;
194                        vec.push(resolved_type);
195                    }
196
197                    let resolved_tuple_type = EnumVariantTupleType {
198                        common,
199                        fields_in_order: vec,
200                    };
201                    let resolved_tuple_type_ref = Rc::new(resolved_tuple_type);
202
203                    EnumVariantType::Tuple(resolved_tuple_type_ref)
204                }
205                swamp_script_ast::EnumVariantType::Struct(
206                    _variant_name_node,
207                    ast_struct_fields,
208                ) => {
209                    let mut fields = SeqMap::new();
210
211                    for (_index, field_with_type) in ast_struct_fields.fields.iter().enumerate() {
212                        // TODO: Check the index
213                        let resolved_type = self.analyze_type(&field_with_type.field_type)?;
214                        let field_name_str =
215                            self.get_text(&field_with_type.field_name.0).to_string();
216
217                        let resolved_field = StructTypeField {
218                            identifier: Some(self.to_node(&field_with_type.field_name.0)),
219                            field_type: resolved_type,
220                        };
221
222                        fields.insert(field_name_str, resolved_field).map_err(|_| {
223                            self.create_err(
224                                ErrorKind::DuplicateFieldName,
225                                &field_with_type.field_name.0,
226                            )
227                        })?;
228                    }
229
230                    let enum_variant_struct_type = EnumVariantStructType {
231                        common,
232                        anon_struct: AnonymousStructType::new(fields),
233                    };
234
235                    let enum_variant_struct_type_ref = Rc::new(enum_variant_struct_type);
236
237                    EnumVariantType::Struct(enum_variant_struct_type_ref)
238                }
239            };
240
241            let variant_name_str = self.get_text(variant_name_node).to_string();
242
243            resolved_variants
244                .insert(variant_name_str, variant_type.into())
245                .map_err(|_| self.create_err(ErrorKind::DuplicateFieldName, variant_name_node))?;
246        }
247
248        parent_ref.borrow_mut().variants = resolved_variants;
249
250        Ok(parent_ref)
251    }
252
253    /// # Errors
254    ///
255    pub fn analyze_alias_type_definition(
256        &mut self,
257        ast_alias: &swamp_script_ast::AliasType,
258    ) -> Result<AliasTypeRef, Error> {
259        let resolved_type = self.analyze_type(&ast_alias.referenced_type)?;
260
261        let alias_name_str = self.get_text(&ast_alias.identifier.0).to_string();
262        let resolved_alias = AliasType {
263            name: self.to_node(&ast_alias.identifier.0),
264            assigned_name: alias_name_str,
265            referenced_type: resolved_type,
266        };
267
268        let resolved_alias_ref = self
269            .shared
270            .definition_table
271            .add_alias(resolved_alias)
272            .map_err(|err| {
273                self.create_err(ErrorKind::SemanticError(err), &ast_alias.identifier.0)
274            })?;
275        self.shared
276            .lookup_table
277            .add_alias_link(resolved_alias_ref.clone())
278            .map_err(|err| {
279                self.create_err(ErrorKind::SemanticError(err), &ast_alias.identifier.0)
280            })?;
281
282        Ok(resolved_alias_ref)
283    }
284
285    /// # Errors
286    ///
287    pub fn analyze_anonymous_struct_type(
288        &mut self,
289        ast_struct: &swamp_script_ast::AnonymousStructType,
290    ) -> Result<AnonymousStructType, Error> {
291        let resolved_fields = self.analyze_anonymous_struct_type_fields(&ast_struct.fields)?;
292
293        let resolved_anon_struct = AnonymousStructType::new_and_sort_fields(resolved_fields);
294
295        Ok(resolved_anon_struct)
296    }
297
298    /// # Errors
299    ///
300    pub fn analyze_anonymous_struct_type_fields(
301        &mut self,
302        ast_struct_fields: &[swamp_script_ast::StructTypeField],
303    ) -> Result<SeqMap<String, StructTypeField>, Error> {
304        let mut resolved_fields = SeqMap::new();
305
306        for (_index, field_name_and_type) in ast_struct_fields.iter().enumerate() {
307            let resolved_type = self.analyze_type(&field_name_and_type.field_type)?;
308            let name_string = self.get_text(&field_name_and_type.field_name.0).to_string();
309
310            let field_type = StructTypeField {
311                identifier: Some(self.to_node(&field_name_and_type.field_name.0)),
312                field_type: resolved_type,
313            };
314
315            resolved_fields
316                .insert(name_string, field_type)
317                .map_err(|_| {
318                    self.create_err(
319                        ErrorKind::DuplicateFieldName,
320                        &field_name_and_type.field_name.0,
321                    )
322                })?;
323        }
324
325        Ok(resolved_fields)
326    }
327
328    /// # Errors
329    ///
330    pub fn analyze_named_struct_type_definition(
331        &mut self,
332        ast_struct_def: &swamp_script_ast::NamedStructDef,
333    ) -> Result<(), Error> {
334        let struct_name_str = self.get_text(&ast_struct_def.identifier.0).to_string();
335
336        let fields =
337            self.analyze_anonymous_struct_type_fields(&ast_struct_def.struct_type.fields)?;
338
339        let analyzed_anonymous_struct = AnonymousStructType::new(fields); // the order encountered in source should be kept
340
341        let named_struct_type = NamedStructType {
342            name: self.to_node(&ast_struct_def.identifier.0),
343            anon_struct_type: analyzed_anonymous_struct,
344            assigned_name: struct_name_str,
345            type_id: self.shared.state.allocate_number(),
346        };
347
348        let struct_ref = self
349            .shared
350            .definition_table
351            .add_struct(named_struct_type)
352            .map_err(|err| {
353                self.create_err(ErrorKind::SemanticError(err), &ast_struct_def.identifier.0)
354            })?;
355
356        self.shared
357            .lookup_table
358            .add_struct_link(struct_ref)
359            .map_err(|err| {
360                self.create_err(ErrorKind::SemanticError(err), &ast_struct_def.identifier.0)
361            })?;
362
363        Ok(())
364    }
365
366    pub(crate) fn analyze_function_definition(
367        &mut self,
368        function: &swamp_script_ast::Function,
369    ) -> Result<Function, Error> {
370        let func = match function {
371            swamp_script_ast::Function::Internal(function_data) => {
372                let parameters = self.analyze_parameters(&function_data.declaration.params)?;
373                let return_type = if let Some(found) = &function_data.declaration.return_type {
374                    self.analyze_type(found)?
375                } else {
376                    Type::Unit
377                };
378
379                self.scope.return_type = return_type.clone();
380
381                // Set up scope for function body
382                for param in &parameters {
383                    self.create_local_variable_resolved(
384                        &param.node.as_ref().unwrap().name,
385                        param.node.as_ref().unwrap().is_mutable.as_ref(),
386                        &param.resolved_type.clone(),
387                    )?;
388                }
389                let function_name = self.get_text(&function_data.declaration.name).to_string();
390                let statements =
391                    self.analyze_function_body_expression(&function_data.body, &return_type)?;
392                self.scope.return_type = Type::Unit;
393
394                let internal = InternalFunctionDefinition {
395                    signature: Signature {
396                        parameters,
397                        return_type: Box::new(return_type),
398                    },
399                    body: statements,
400                    name: LocalIdentifier(self.to_node(&function_data.declaration.name)),
401                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
402                };
403
404                let function_ref = self
405                    .shared
406                    .definition_table
407                    .add_internal_function(&function_name, internal)
408                    .map_err(|err| {
409                        self.create_err(
410                            ErrorKind::SemanticError(err),
411                            &function_data.declaration.name,
412                        )
413                    })?;
414
415                self.shared
416                    .lookup_table
417                    .add_internal_function_link(&function_name, function_ref.clone())
418                    .map_err(|err| {
419                        self.create_err(
420                            ErrorKind::SemanticError(err),
421                            &function_data.declaration.name,
422                        )
423                    })?;
424
425                Function::Internal(function_ref)
426            }
427            swamp_script_ast::Function::External(ast_signature) => {
428                let parameters = self.analyze_parameters(&ast_signature.params)?;
429                let external_return_type = if let Some(found) = &ast_signature.return_type {
430                    self.analyze_type(found)?
431                } else {
432                    Type::Unit
433                };
434
435                let return_type = external_return_type;
436                let external_function_id = self.shared.state.allocate_external_function_id();
437
438                let external = ExternalFunctionDefinition {
439                    assigned_name: self.get_text(&ast_signature.name).to_string(),
440                    signature: Signature {
441                        parameters,
442                        return_type: Box::new(return_type),
443                    },
444                    name: Some(self.to_node(&ast_signature.name)),
445                    id: external_function_id,
446                };
447
448                let function_ref = self
449                    .shared
450                    .definition_table
451                    .add_external_function_declaration(external)
452                    .map_err(|err| {
453                        self.create_err(ErrorKind::SemanticError(err), &ast_signature.name)
454                    })?;
455
456                self.shared
457                    .lookup_table
458                    .add_external_function_declaration_link(function_ref.clone())
459                    .map_err(|err| {
460                        self.create_err(ErrorKind::SemanticError(err), &ast_signature.name)
461                    })?;
462
463                Function::External(function_ref)
464            }
465        };
466
467        Ok(func)
468    }
469
470    /// # Errors
471    ///
472    pub fn analyze_definition(
473        &mut self,
474        ast_def: &swamp_script_ast::Definition,
475    ) -> Result<(), Error> {
476        match ast_def {
477            swamp_script_ast::Definition::NamedStructDef(ast_struct) => {
478                self.analyze_named_struct_type_definition(ast_struct)?
479            }
480            swamp_script_ast::Definition::AliasDef(alias_def) => {
481                self.analyze_alias_type_definition(alias_def)?;
482            }
483            swamp_script_ast::Definition::EnumDef(identifier, variants) => {
484                self.analyze_enum_type_definition(
485                    &swamp_script_ast::LocalTypeIdentifier(identifier.clone()),
486                    variants,
487                )?;
488            }
489            swamp_script_ast::Definition::FunctionDef(function) => {
490                let resolved_return_type = self.analyze_return_type(function)?;
491                self.start_function(resolved_return_type);
492                self.analyze_function_definition(function)?;
493                self.stop_function();
494            }
495            swamp_script_ast::Definition::ImplDef(type_identifier, functions) => {
496                self.analyze_impl_definition(type_identifier, functions)?;
497            }
498            swamp_script_ast::Definition::Mod(mod_info) => self.analyze_mod_definition(mod_info)?,
499            swamp_script_ast::Definition::Use(use_info) => self.analyze_use_definition(use_info)?,
500            swamp_script_ast::Definition::Constant(const_info) => {
501                self.analyze_constant_definition(const_info)?;
502            }
503        };
504
505        Ok(())
506    }
507
508    fn analyze_impl_definition(
509        &mut self,
510        named_type_node: &swamp_script_ast::Node,
511        functions: &[swamp_script_ast::Function],
512    ) -> Result<(), Error> {
513        let qualified = swamp_script_ast::QualifiedTypeIdentifier {
514            name: swamp_script_ast::LocalTypeIdentifier(named_type_node.clone()),
515            module_path: None,
516            generic_params: vec![],
517        };
518
519        let type_to_attach_to = self.analyze_named_type(&qualified)?;
520        let function_refs: Vec<&swamp_script_ast::Function> = functions.iter().collect();
521        self.analyze_impl_functions(&type_to_attach_to, &function_refs)?;
522
523        Ok(())
524    }
525
526    pub fn analyze_impl_functions(
527        &mut self,
528        type_to_attach_to: &Type,
529        functions: &[&swamp_script_ast::Function],
530    ) -> Result<(), Error> {
531        self.shared
532            .state
533            .associated_impls
534            .prepare(type_to_attach_to);
535
536        for function in functions {
537            let new_return_type = self.analyze_return_type(function)?;
538            self.start_function(new_return_type);
539
540            let function_name = match function {
541                swamp_script_ast::Function::Internal(function_with_body) => {
542                    &function_with_body.declaration
543                }
544                swamp_script_ast::Function::External(external_declaration) => external_declaration,
545            };
546
547            let function_name_str = self.get_text(&function_name.name).to_string();
548
549            let resolved_function = self.analyze_impl_func(function, type_to_attach_to)?;
550
551            let resolved_function_ref = Rc::new(resolved_function);
552
553            self.stop_function();
554
555            self.shared
556                .state
557                .associated_impls
558                .add_member_function(type_to_attach_to, &function_name_str, resolved_function_ref)
559                .map_err(|err| {
560                    self.create_err(ErrorKind::SemanticError(err), &function_name.name)
561                })?;
562        }
563
564        Ok(())
565    }
566
567    fn analyze_impl_func(
568        &mut self,
569        function: &swamp_script_ast::Function,
570        self_type: &Type,
571    ) -> Result<Function, Error> {
572        let resolved_fn = match function {
573            swamp_script_ast::Function::Internal(function_data) => {
574                let mut parameters = Vec::new();
575
576                if let Some(found_self) = &function_data.declaration.self_parameter {
577                    parameters.push(TypeForParameter {
578                        name: self.get_text(&found_self.self_node).to_string(),
579                        resolved_type: self_type.clone(),
580                        is_mutable: found_self.is_mutable.is_some(),
581                        node: Option::from(ParameterNode {
582                            name: self.to_node(&found_self.self_node),
583                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
584                        }),
585                    });
586                }
587
588                for param in &function_data.declaration.params {
589                    let resolved_type = self.analyze_type(&param.param_type)?;
590
591                    parameters.push(TypeForParameter {
592                        name: self.get_text(&param.variable.name).to_string(),
593                        resolved_type,
594                        is_mutable: param.variable.is_mutable.is_some(),
595                        node: Option::from(ParameterNode {
596                            name: self.to_node(&param.variable.name),
597                            is_mutable: self
598                                .to_node_option(Option::from(&param.variable.is_mutable)),
599                        }),
600                    });
601                }
602
603                let return_type =
604                    self.analyze_maybe_type(Option::from(&function_data.declaration.return_type))?;
605
606                for param in &parameters {
607                    self.create_local_variable_resolved(
608                        &param.node.as_ref().unwrap().name,
609                        param.node.as_ref().unwrap().is_mutable.as_ref(),
610                        &param.resolved_type.clone(),
611                    )?;
612                }
613
614                let statements =
615                    self.analyze_function_body_expression(&function_data.body, &return_type)?;
616
617                let internal = InternalFunctionDefinition {
618                    signature: Signature {
619                        parameters,
620                        return_type: Box::new(return_type),
621                    },
622                    body: statements,
623                    name: LocalIdentifier(self.to_node(&function_data.declaration.name)),
624                    assigned_name: self.get_text(&function_data.declaration.name).to_string(),
625                };
626
627                let internal_ref = Rc::new(internal);
628
629                Function::Internal(internal_ref)
630            }
631
632            swamp_script_ast::Function::External(signature) => {
633                let mut parameters = Vec::new();
634
635                if let Some(found_self) = &signature.self_parameter {
636                    parameters.push(TypeForParameter {
637                        name: self.get_text(&found_self.self_node).to_string(),
638                        resolved_type: self_type.clone(),
639                        is_mutable: found_self.is_mutable.is_some(),
640                        node: Option::from(ParameterNode {
641                            name: self.to_node(&found_self.self_node),
642                            is_mutable: self.to_node_option(Option::from(&found_self.is_mutable)),
643                        }),
644                    });
645                }
646
647                // Handle parameters, including self if present
648                for param in &signature.params {
649                    let resolved_type = self.analyze_type(&param.param_type)?;
650
651                    parameters.push(TypeForParameter {
652                        name: self.get_text(&param.variable.name).to_string(),
653                        resolved_type,
654                        is_mutable: param.variable.is_mutable.is_some(),
655                        node: Option::from(ParameterNode {
656                            name: self.to_node(&param.variable.name),
657                            is_mutable: self
658                                .to_node_option(Option::from(&param.variable.is_mutable)),
659                        }),
660                    });
661                }
662
663                let return_type = self.analyze_maybe_type(Option::from(&signature.return_type))?;
664
665                let external = ExternalFunctionDefinition {
666                    assigned_name: self.get_text(&signature.name).to_string(),
667                    name: Some(self.to_node(&signature.name)),
668                    signature: Signature {
669                        parameters,
670                        return_type: Box::new(return_type),
671                    },
672                    id: 0,
673                };
674
675                let external_ref = Rc::new(external);
676
677                Function::External(external_ref)
678            }
679        };
680        Ok(resolved_fn)
681    }
682}