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