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