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