use crate::ast::named::Named; use crate::ast::*; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::symbol::*; use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::cell::RefCell; use std::ops::DerefMut; use std::range::Range; use std::rc::Rc; fn handle_insert_error( err: SymbolInsertError, error_symbol_name: &str, error_file_id: usize, error_range: Range, symbol_types: &str, diagnostics: &mut Vec, ) { match err { SymbolInsertError::SymbolAlreadyDefined(s) => { let mut diagnostic = Diagnostic::error() .with_message(format!( "{} symbol '{}' already defined in the current scope.", symbol_types, error_symbol_name, )) .with_label( Label::primary(error_file_id, error_range) .with_message("Symbol duplicated here."), ); if let Some(source_definition) = s.definition() { diagnostic = diagnostic.with_label( Label::secondary(source_definition.file_id(), source_definition.range()) .with_message("Symbol defined here."), ); } diagnostics.push(diagnostic); } } } /* Names */ fn gather_identifier(identifier: &mut Identifier, symbol_table: &mut SymbolTable) { identifier.set_scope_id(symbol_table.current_scope_id()); } fn gather_fully_qualified_name( fully_qualified_name: &mut FullyQualifiedName, symbol_table: &mut SymbolTable, ) { gather_identifier(fully_qualified_name.last_mut(), symbol_table); } /* Type Use */ fn gather_type_use( type_use: &mut TypeUse, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { match type_use { TypeUse::Primitive(primitive_type_use) => { gather_primitive_type_use(primitive_type_use, symbol_table, fqn_context, diagnostics) } TypeUse::InterfaceOrClass(interface_or_class_type_use) => { gather_interface_or_class_type_use( interface_or_class_type_use, symbol_table, fqn_context, diagnostics, ); } TypeUse::Tuple(tuple_type_use) => { gather_tuple_type_use(tuple_type_use, symbol_table, fqn_context, diagnostics); } TypeUse::Function(function_type_use) => { gather_function_type_use(function_type_use, symbol_table, fqn_context, diagnostics); } } } fn gather_primitive_type_use( primitive_type_use: &mut PrimitiveTypeUse, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { match primitive_type_use { PrimitiveTypeUse::Array(generic_arguments_opt) => { if let Some(generic_arguments) = generic_arguments_opt { gather_generic_arguments(generic_arguments, symbol_table, fqn_context, diagnostics); } } _ => {} } } fn gather_interface_or_class_type_use( interface_or_class_type_use: &mut InterfaceOrClassTypeUse, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { gather_fully_qualified_name(&mut interface_or_class_type_use.fqn, symbol_table); gather_generic_arguments( &mut interface_or_class_type_use.generics, symbol_table, fqn_context, diagnostics, ); } fn gather_tuple_type_use( tuple_type_use: &mut TupleTypeUse, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { for generic_argument in &mut tuple_type_use.arguments.0 { gather_type_use(generic_argument, symbol_table, fqn_context, diagnostics); } } fn gather_function_type_use( function_type_use: &mut FunctionTypeUse, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { gather_generic_parameters( &mut function_type_use.generics, symbol_table, fqn_context, diagnostics, ); gather_parameters( &mut function_type_use.parameters, symbol_table, fqn_context, diagnostics, ); gather_return_type( &mut function_type_use.return_type, symbol_table, fqn_context, diagnostics, ); } /* Generic Arguments */ fn gather_generic_arguments( generic_arguments: &mut GenericArguments, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { for argument in &mut generic_arguments.0 { gather_type_use(argument, symbol_table, fqn_context, diagnostics); } } /* Generic Parameters */ fn gather_generic_parameters( generic_parameters: &mut GenericParameters, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!("Add each Identifier as a type to the current scope; make sure caller's push/pop before/after") } /* Implements List */ fn gather_implements_list( implements_list: &mut ImplementsList, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { for type_use in &mut implements_list.0 { gather_type_use(type_use, symbol_table, fqn_context, diagnostics); } } /* Function Parameters */ fn gather_parameters( parameters: &mut Parameters, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) -> Option>> { parameters .0 .iter_mut() .map(|parameter| gather_parameter(parameter, symbol_table, fqn_context, diagnostics)) .collect() } fn gather_parameter( parameter: &mut Parameter, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) -> Option> { let parameter_name = parameter.identifier.name(); let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( ¶meter_name, Some(¶meter.identifier), )); match insert_result { Ok(parameter_symbol) => { parameter .identifier .set_scope_id(symbol_table.current_scope_id()); gather_type_use( &mut parameter.type_use, symbol_table, fqn_context, diagnostics, ); Some(parameter_symbol) } Err(err) => { handle_insert_error( err, ¶meter_name, parameter.identifier.file_id(), parameter.identifier.range(), "function/variable", diagnostics, ); None } } } /* Return Type */ fn gather_return_type( return_type: &mut ReturnType, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { gather_type_use( &mut return_type.declared_type, symbol_table, fqn_context, diagnostics, ); gather_references( &mut return_type.references, symbol_table, fqn_context, diagnostics, ); } /* References */ fn gather_references( references: &mut References, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { for identifier in &mut references.0 { gather_identifier(identifier, symbol_table); } } /* Compilation Unit/Top-level construct */ pub(super) fn gather_compilation_unit( compilation_unit: &mut CompilationUnit, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { let mut fqn_context = FqnContext::new(); if let Some(namespace) = &compilation_unit.namespace { fqn_context.push(namespace.name().to_string()); } symbol_table.push_scope(&format!("FileScope({})", compilation_unit.file_name)); for use_statement in &mut compilation_unit.use_statements { gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics) } for declaration in &mut compilation_unit.declarations { gather_module_level_declaration(declaration, symbol_table, &mut fqn_context, diagnostics); } symbol_table.pop_scope(); assert_eq!(symbol_table.current_scope_id(), 0); } /* Use Statement */ fn handle_use_statement_import( symbol_table: &mut SymbolTable, base_name: &str, identifier: Rc>, diagnostics: &mut Vec, ) { let borrowed_identifier = identifier.borrow(); let declared_name = borrowed_identifier.name().to_string(); let insert_result = symbol_table.insert_use_statement_symbol(UseStatementSymbol::new( &format!("{}::{}", base_name, &declared_name), &declared_name, Some(identifier.clone()), )); match insert_result { Ok(use_statement_symbol) => { drop(borrowed_identifier); let mut mutable_borrowed_identifier = identifier.borrow_mut(); gather_identifier(mutable_borrowed_identifier.deref_mut(), symbol_table); mutable_borrowed_identifier .set_saved_symbol(Symbol::UseStatement(use_statement_symbol)); } Err(err) => { handle_insert_error( err, &declared_name, borrowed_identifier.file_id(), borrowed_identifier.range(), "Use statement", diagnostics, ); } } } fn gather_use_statement( use_statement: &mut UseStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { if use_statement.is_star() { todo!() } let base_name = use_statement.base_name().to_string(); match &mut use_statement.last { UseStatementLast::Identifier(identifier) => { handle_use_statement_import(symbol_table, &base_name, identifier.clone(), diagnostics) } UseStatementLast::Identifiers(identifiers) => { for identifier in identifiers { handle_use_statement_import( symbol_table, &base_name, identifier.clone(), diagnostics, ) } } UseStatementLast::Star => panic!(), } } /* Declarations allowed in each level */ fn gather_module_level_declaration( declaration: &mut ModuleLevelDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { use ModuleLevelDeclaration::*; match declaration { Module(module_declaration) => { gather_module_declaration(module_declaration, symbol_table, fqn_context, diagnostics); } Class(class_declaration) => { gather_class_declaration(class_declaration, symbol_table, fqn_context, diagnostics) } Function(function_definition) => { gather_function_definition(function_definition, symbol_table, fqn_context, diagnostics) } PlatformFunction(platform_function_definition) => { gather_platform_function_definition( platform_function_definition, symbol_table, fqn_context, diagnostics, ); } _ => todo!(), } } fn gather_interface_level_declaration( declaration: &mut InterfaceLevelDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_class_level_declaration( declaration: &mut ClassLevelDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } /* Main Declarations */ fn gather_module_declaration( declaration: &mut ModuleDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { // 1. Add mod identifier symbol // 2. Update fqn context // 3. Push scope // 4. Process declarations // 5. Pop scope let module_name = declaration.identifier.name(); let insert_result = symbol_table.insert_module_symbol(ModuleSymbol::new( &fqn_context.resolve(&module_name), &module_name, declaration.is_public, Some(&declaration.identifier), )); if let Err(err) = insert_result { handle_insert_error( err, &module_name, declaration.identifier.file_id(), declaration.identifier.range(), "module/type", diagnostics, ) } fqn_context.push(module_name.to_string()); symbol_table.push_scope(&format!("ModuleScope({})", module_name)); for inner_declaration in &mut declaration.declarations { gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope() } fn gather_class_declaration( class_declaration: &mut ClassDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let declared_name = class_declaration.identifier.name(); let resolved_name = fqn_context.resolve(&declared_name); let insert_result = symbol_table.insert_type_symbol(TypeSymbol::new( &resolved_name, &declared_name, class_declaration.is_public, Some(&class_declaration.identifier), )); if let Err(err) = insert_result { handle_insert_error( err, &declared_name, class_declaration.identifier.file_id(), class_declaration.identifier.range(), "interface/class", diagnostics, ); } // todo: scopes, generics, etc. } /* Function declarations and components */ fn gather_function_definition( function: &mut FunctionDefinition, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let declared_name = function.identifier.name(); let resolved_name = fqn_context.resolve(&declared_name); let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( &resolved_name, &declared_name, function.is_public, false, Some(&function.identifier), )); match insert_result { Ok(function_symbol) => { function .identifier .set_scope_id(symbol_table.current_scope_id()); symbol_table.push_scope(&format!("FunctionParameterScope({})", resolved_name)); let parameters_result = gather_parameters( &mut function.parameters, symbol_table, fqn_context, diagnostics, ); match parameters_result { Some(parameter_symbols) => { function_symbol .borrow_mut() .set_parameters(parameter_symbols); } None => {} } gather_return_type( &mut function.return_type, symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope(&format!("FunctionBodyScope({})", resolved_name)); gather_function_body(&mut function.body, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); // body symbol_table.pop_scope(); // parameters } Err(err) => { handle_insert_error( err, &declared_name, function.identifier.file_id(), function.identifier.range(), "function/variable", diagnostics, ); } } } fn gather_operator_function_definition( operator_function_definition: &mut OperatorFunctionDefinition, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_platform_function_definition( platform_function_declaration: &mut PlatformFunctionDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let declared_name = platform_function_declaration.identifier.name(); let fully_qualified_name = fqn_context.resolve(&declared_name); let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( &fully_qualified_name, &declared_name, platform_function_declaration.is_public, true, Some(&platform_function_declaration.identifier), )); match insert_result { Ok(function_symbol) => { let declared_name_as_string = platform_function_declaration.identifier.name().to_string(); platform_function_declaration .identifier .set_scope_id(symbol_table.current_scope_id()); symbol_table.push_scope(&format!( "FunctionParameterScope({})", declared_name_as_string )); let parameter_symbols_result = gather_parameters( &mut platform_function_declaration.parameters, symbol_table, fqn_context, diagnostics, ); match parameter_symbols_result { Some(parameter_symbols) => { function_symbol .borrow_mut() .set_parameters(parameter_symbols); } None => {} } gather_return_type( &mut platform_function_declaration.return_type, symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } Err(err) => { handle_insert_error( err, &declared_name, platform_function_declaration.identifier.file_id(), platform_function_declaration.identifier.range(), "(Platform-) Function", diagnostics, ); } } } fn gather_interface_function_declaration( declaration: &mut InterfaceFunctionDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_interface_operator_function_declaration( declaration: &mut InterfaceOperatorFunctionDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_function_body( function_body: &mut FunctionBody, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { use crate::ast::FunctionBody::*; match function_body { Block(block) => gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics), _ => todo!(), } } /* Class Components */ fn gather_class_constructor( class_constructor: &mut ClassConstructor, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_property_declaration( property_declaration: &mut PropertyDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_field_declaration( field_declaration: &mut FieldDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } /* Statements */ fn gather_block_statement( block: &mut BlockStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("BlockStatementScope"); gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); } fn gather_block_statement_inner( block: &mut BlockStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { for statement in &mut block.statements { gather_statement(statement, symbol_table, fqn_context, diagnostics); } if let Some(expression) = &mut block.expression { gather_expression(expression, symbol_table, diagnostics); } } fn gather_statement( statement: &mut Statement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { use crate::ast::Statement::*; match statement { BlockStatement(block) => { gather_block_statement(block, symbol_table, fqn_context, diagnostics) } VariableDeclarationStatement(variable_declaration) => { gather_variable_declaration(variable_declaration, symbol_table, diagnostics) } AssignStatement(assign_statement) => { gather_assign_statement(assign_statement, symbol_table, fqn_context, diagnostics) } CallStatement(call_statement) => { gather_call_statement(call_statement, symbol_table, diagnostics) } _ => todo!(), } } fn gather_variable_declaration( variable_declaration: &mut VariableDeclarationStatement, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { let variable_name = variable_declaration.identifier.name(); let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new( &variable_name, variable_declaration.is_mutable, Some(&variable_declaration.identifier), )); if let Err(err) = insert_result { handle_insert_error( err, &variable_name, variable_declaration.identifier.file_id(), variable_declaration.identifier.range(), "function/variable", diagnostics, ) } variable_declaration .identifier .set_scope_id(symbol_table.current_scope_id()); if let Some(initializer) = &mut variable_declaration.initializer { gather_expression(initializer, symbol_table, diagnostics); } } fn gather_assign_statement( assign_statement: &mut AssignStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { gather_expression(&mut assign_statement.lhs, symbol_table, diagnostics); gather_expression(&mut assign_statement.rhs, symbol_table, diagnostics); } fn gather_call_statement( call_statement: &mut CallStatement, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut call_statement.0, symbol_table, diagnostics); } fn gather_return_statement( return_statement: &mut ReturnStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { if let Some(expression) = &mut return_statement.0 { gather_expression(expression, symbol_table, diagnostics); } } fn gather_if_statement( if_statement: &mut IfStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_if_else_statement( if_else_statement: &mut IfElseStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_while_statement( while_statement: &mut WhileStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } fn gather_for_statement( for_statement: &mut ForStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { todo!() } /* Expressions */ fn gather_expression( expression: &mut Expression, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { use crate::ast::Expression::*; match expression { Ternary(ternary_expression) => { gather_ternary_expression(ternary_expression, symbol_table, diagnostics); } Binary(binary_expression) => { gather_binary_expression(binary_expression, symbol_table, diagnostics); } UnaryPrefix(prefix_expression) => { gather_prefix_expression(prefix_expression, symbol_table, diagnostics); } UnarySuffix(suffix_expression) => { gather_suffix_expression(suffix_expression, symbol_table, diagnostics); } Call(call_expression) => { gather_call_expression(call_expression, symbol_table, diagnostics); } ObjectAccess(object_access) => { gather_object_access(object_access, symbol_table, diagnostics); } Literal(literal) => { gather_literal(literal, symbol_table, diagnostics); } FullyQualifiedName(fully_qualified_name) => { gather_fully_qualified_name(fully_qualified_name, symbol_table); } Closure(closure) => { gather_closure(closure, symbol_table, diagnostics); } } } fn gather_ternary_expression( ternary_expression: &mut TernaryExpression, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut ternary_expression.condition, symbol_table, diagnostics); gather_expression( &mut ternary_expression.true_expression, symbol_table, diagnostics, ); gather_expression( &mut ternary_expression.false_expression, symbol_table, diagnostics, ); } fn gather_binary_expression( binary_expression: &mut BinaryExpression, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut binary_expression.left, symbol_table, diagnostics); gather_expression(&mut binary_expression.right, symbol_table, diagnostics); } fn gather_prefix_expression( prefix_expression: &mut PrefixExpression, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut prefix_expression.expression, symbol_table, diagnostics); } fn gather_suffix_expression( suffix_expression: &mut SuffixExpression, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut suffix_expression.expression, symbol_table, diagnostics); } fn gather_call_expression( call_expression: &mut CallExpression, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut call_expression.callee, symbol_table, diagnostics); if let Some(turbo_fish) = &mut call_expression.turbo_fish { gather_turbo_fish(turbo_fish, symbol_table, diagnostics); } for call_argument in &mut call_expression.arguments.0 { gather_expression(&mut call_argument.0, symbol_table, diagnostics); } } fn gather_turbo_fish( turbo_fish: &mut TurboFish, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { todo!() } fn gather_closure( closure: &mut Closure, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { todo!() } fn gather_object_access( object_access: &mut ObjectAccess, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { gather_expression(&mut object_access.receiver, symbol_table, diagnostics); for object_navigation in &mut object_access.navigations.0 { match object_navigation { ObjectNavigation::Index(index_expression) => { gather_expression(index_expression, symbol_table, diagnostics); } ObjectNavigation::Identifier(identifier) => { // TODO: use a special gather for names belonging to a struct gather_identifier(identifier, symbol_table); } } } } fn gather_literal( literal: &mut Literal, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { match literal { Literal::DString(d_string) => gather_d_string(d_string, symbol_table, diagnostics), Literal::BacktickString(backtick_string) => { gather_d_string(backtick_string, symbol_table, diagnostics) } _ => {} } } fn gather_d_string( d_string: &mut DString, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { todo!() }