/// The gather phase must exclusively gather all named items that can be used elsewhere. use crate::ast::ast_node::{AstNode, AstNodeRefMut}; use crate::ast::node::{ Class, Closure, ClosureParameter, CompilationUnit, ForStatement, Function, FunctionBody, GenericParameters, Identifier, IfClause, Interface, InterfaceDefaultFunction, InterfaceDefaultOperatorFunction, InterfaceFunction, InterfaceOperatorFunction, Member, Module, Namespace, OperatorFunction, Parameter, PlatformFunction, PlatformOperatorFunction, TernaryExpression, UseStatement, UseStatementSuffix, VariableDeclaration, VariableUse, WhileStatement, }; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol::source_definition::SourceDefinition; use crate::name_analysis::symbol::type_symbol::{ ConcreteTypeSymbol, ConcreteTypeSymbolKind, GenericTypeSymbol, TypeSymbol, }; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError, SymbolTable}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::range::Range; 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); } } } fn handle_lookup_error( err: SymbolLookupError, error_symbol_name: &str, error_file_id: usize, error_range: Range, symbol_types: &str, diagnostics: &mut Vec, ) { match err { SymbolLookupError::NoDefinition => { let diagnostic = Diagnostic::error() .with_message(format!( "No such {} symbol '{}' in scope.", symbol_types, error_symbol_name, )) .with_label( Label::primary(error_file_id, error_range).with_message("Symbol used here."), ); diagnostics.push(diagnostic); } } } fn gather_node_children<'a>( node: &'a mut dyn AstNode<'a>, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { node.for_each_child_mut(&mut |child| { gather_node(child, symbol_table, fqn_context, diagnostics); }); } fn gather_node<'a>( node: &'a mut dyn AstNode<'a>, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let node_ref = node.as_node_ref_mut(); match node_ref { AstNodeRefMut::GenericParameters(generic_parameters) => { gather_generic_parameters(generic_parameters, symbol_table, diagnostics); } AstNodeRefMut::Parameter(parameter) => { gather_parameter(parameter, symbol_table, diagnostics); } AstNodeRefMut::Namespace(namespace) => { gather_namespace(namespace, fqn_context); } AstNodeRefMut::UseStatement(use_statement) => { gather_use_statement(use_statement, symbol_table, diagnostics); } AstNodeRefMut::Module(module) => { gather_module(module, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::Interface(interface) => { gather_interface(interface, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::Class(class) => { gather_class(class, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::Function(function) => { gather_function(function, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::OperatorFunction(operator_function) => { gather_operator_function(operator_function, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::PlatformFunction(platform_function) => { gather_platform_function(platform_function, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::PlatformOperatorFunction(platform_operator_function) => { gather_platform_operator_function( platform_operator_function, symbol_table, fqn_context, diagnostics, ); } AstNodeRefMut::InterfaceFunction(interface_function) => { gather_interface_function(interface_function, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::InterfaceDefaultFunction(interface_default_function) => { gather_interface_default_function( interface_default_function, symbol_table, fqn_context, diagnostics, ); } AstNodeRefMut::InterfaceOperatorFunction(interface_operator_function) => { gather_interface_operator_function( interface_operator_function, symbol_table, fqn_context, diagnostics, ); } AstNodeRefMut::InterfaceDefaultOperatorFunction(interface_default_operator_function) => { gather_interface_default_operator_function( interface_default_operator_function, symbol_table, fqn_context, diagnostics, ); } AstNodeRefMut::FunctionBody(function_body) => { gather_function_body(function_body, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::Member(member) => { gather_member(member, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::VariableDeclaration(variable_declaration) => { gather_variable_declaration( variable_declaration, symbol_table, fqn_context, diagnostics, ); } AstNodeRefMut::IfClause(if_clause) => { gather_if_clause(if_clause, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::IfElseIf(if_else_if) => { gather_node_children(if_else_if, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::WhileStatement(while_statement) => { gather_while_statement(while_statement, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::ForStatement(for_statement) => { gather_for_statement(for_statement, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::VariableUse(variable_use) => { gather_variable_use(variable_use, symbol_table, diagnostics); } AstNodeRefMut::TernaryExpression(ternary_expression) => { gather_ternary_expression(ternary_expression, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::Closure(closure) => { gather_closure(closure, symbol_table, fqn_context, diagnostics); } AstNodeRefMut::ClosureParameter(closure_parameter) => { gather_closure_parameter(closure_parameter, symbol_table, fqn_context, diagnostics); } _ => todo!(), } } fn gather_generic_parameters<'a>( generic_parameters: &'a GenericParameters, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { for identifier in generic_parameters.identifier_list().identifiers() { let type_symbol = TypeSymbol::Generic(GenericTypeSymbol::new( identifier.name(), Some(SourceDefinition::from_identifier(identifier)), )); if let Err(insert_error) = symbol_table.insert_type_symbol(type_symbol) { handle_insert_error( insert_error, identifier.name(), identifier.file_id(), identifier.range(), "Type", diagnostics, ); } } } fn gather_parameter<'a>( parameter: &'a mut Parameter, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { let parameter_symbol = ParameterSymbol::new( parameter.identifier().name(), Some(SourceDefinition::from_identifier(parameter.identifier())), ); if let Err(insert_error) = symbol_table.insert_parameter_symbol(parameter_symbol) { handle_insert_error( insert_error, parameter.identifier().name(), parameter.identifier().file_id(), parameter.identifier().range(), "Parameter", diagnostics, ); } } pub fn gather_compilation_unit<'a>( compilation_unit: &'a mut CompilationUnit, file_name: &str, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { let mut fqn_context = FqnContext::new(); symbol_table.push_scope(&format!("FileScope {}", file_name)); gather_node( compilation_unit, symbol_table, &mut fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_namespace(namespace: &Namespace, fqn_context: &mut FqnContext) { for identifier in namespace.fqn().identifiers() { fqn_context.push(identifier.name()); } } fn gather_use_statement( use_statement: &UseStatement, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { let base_fqn = use_statement .prefixes() .map(|prefix| prefix.identifier().name()) .collect::>() .join("::"); match use_statement.suffix() { UseStatementSuffix::Identifier(identifier) => { gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics); } UseStatementSuffix::Star => { let symbol = StarUseSymbol::new( &base_fqn, Some(SourceDefinition::from_use_statement(use_statement)), ); let insert_result = symbol_table.insert_star_use_symbol(symbol); if let Err(error) = insert_result { handle_insert_error( error, &base_fqn, use_statement.file_id(), use_statement.range(), "Use Statement", diagnostics, ); } } UseStatementSuffix::UseList(use_list) => { for identifier in use_list.identifiers() { gather_concrete_use_symbol(&base_fqn, identifier, symbol_table, diagnostics); } } } } fn gather_concrete_use_symbol( base_fqn: &str, identifier: &Identifier, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { let symbol = ConcreteUseSymbol::new( base_fqn, identifier.name(), Some(SourceDefinition::from_identifier(identifier)), ); if let Err(insert_error) = symbol_table.insert_concrete_use_symbol(symbol) { handle_insert_error( insert_error, &base_fqn, identifier.file_id(), identifier.range(), "Use Statement", diagnostics, ); } } fn gather_module<'a>( module: &'a mut Module, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let module_symbol = ModuleSymbol::new( &fqn_context.resolve(module.identifier().name()), module.identifier().name(), module.is_public(), Some(SourceDefinition::from_identifier(module.identifier())), ); if let Err(symbol_insert_error) = symbol_table.insert_module_symbol(module_symbol) { handle_insert_error( symbol_insert_error, module.identifier().name(), module.identifier().file_id(), module.identifier().range(), "Module", diagnostics, ); } fqn_context.push(module.identifier().name()); symbol_table.push_scope(&format!("ModuleScope {}", module.identifier().name())); for declaration in module.declarations_mut() { gather_node(declaration, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); fqn_context.pop(); } fn gather_interface<'a>( interface: &'a mut Interface, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let type_symbol = ConcreteTypeSymbol::new( &fqn_context.resolve(interface.identifier().name()), interface.identifier().name(), interface.is_public(), ConcreteTypeSymbolKind::Interface, Some(SourceDefinition::from_identifier(interface.identifier())), ); if let Err(symbol_insert_error) = symbol_table.insert_type_symbol(TypeSymbol::Concrete(type_symbol)) { handle_insert_error( symbol_insert_error, interface.identifier().name(), interface.identifier().file_id(), interface.identifier().range(), "Interface", diagnostics, ); } fqn_context.push(interface.identifier().name()); symbol_table.push_scope(&format!("InterfaceScope {}", interface.identifier().name())); for declaration in interface.declarations_mut() { gather_node(declaration, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); fqn_context.pop(); } fn gather_class<'a>( class: &'a mut Class, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let class_symbol = ConcreteTypeSymbol::new( &fqn_context.resolve(class.identifier().name()), class.identifier().name(), class.is_public(), ConcreteTypeSymbolKind::Class, Some(SourceDefinition::from_identifier(class.identifier())), ); if let Err(symbol_insert_error) = symbol_table.insert_type_symbol(TypeSymbol::Concrete(class_symbol)) { handle_insert_error( symbol_insert_error, class.identifier().name(), class.identifier().file_id(), class.identifier().range(), "Class", diagnostics, ); } fqn_context.push(class.identifier().name()); symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name())); gather_node( class.class_constructor_mut(), symbol_table, fqn_context, diagnostics, ); for declaration in class.class_level_declarations_mut() { gather_node(declaration, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); fqn_context.pop(); } fn gather_function<'a>( function: &'a mut Function, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(function.identifier().name()), function.identifier().name(), function.is_public(), false, Some(SourceDefinition::from_identifier(function.identifier())), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, function.identifier().name(), function.identifier().file_id(), function.identifier().range(), "Function", diagnostics, ); } symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name())); gather_node( function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( function.function_body_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_operator_function<'a>( operator_function: &'a mut OperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(&operator_function.operator().inner().name()), operator_function.operator().inner().name(), operator_function.is_public(), false, Some(SourceDefinition::from_operator( operator_function.operator(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, operator_function.operator().inner().name(), operator_function.operator().file_id(), operator_function.operator().range(), "Operator", diagnostics, ); } symbol_table.push_scope(&format!( "FunctionScope {}", operator_function.operator().inner().name() )); gather_node( operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( operator_function.function_body_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_platform_function<'a>( platform_function: &'a mut PlatformFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(platform_function.identifier().name()), platform_function.identifier().name(), platform_function.is_public(), true, Some(SourceDefinition::from_identifier( platform_function.identifier(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, platform_function.identifier().name(), platform_function.identifier().file_id(), platform_function.identifier().range(), "Function", diagnostics, ); } symbol_table.push_scope(&format!( "PlatformFunctionScope {}", platform_function.identifier().name() )); gather_node( platform_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( platform_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( platform_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_platform_operator_function<'a>( platform_operator_function: &'a mut PlatformOperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(platform_operator_function.operator().inner().name()), platform_operator_function.operator().inner().name(), platform_operator_function.is_public(), true, Some(SourceDefinition::from_operator( platform_operator_function.operator(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, platform_operator_function.operator().inner().name(), platform_operator_function.operator().file_id(), platform_operator_function.operator().range(), "Function", diagnostics, ); } symbol_table.push_scope(&format!( "PlatformOperatorFunctionScope {}", platform_operator_function.operator().inner().name() )); gather_node( platform_operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( platform_operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( platform_operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_interface_function<'a>( interface_function: &'a mut InterfaceFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(interface_function.identifier().name()), interface_function.identifier().name(), true, false, Some(SourceDefinition::from_identifier( interface_function.identifier(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, interface_function.identifier().name(), interface_function.identifier().file_id(), interface_function.identifier().range(), "Type", diagnostics, ); } symbol_table.push_scope(&format!( "InterfaceFunctionScope {}", interface_function.identifier().name() )); gather_node( interface_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_interface_default_function<'a>( interface_default_function: &'a mut InterfaceDefaultFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(interface_default_function.identifier().name()), interface_default_function.identifier().name(), true, false, Some(SourceDefinition::from_identifier( interface_default_function.identifier(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, interface_default_function.identifier().name(), interface_default_function.identifier().file_id(), interface_default_function.identifier().range(), "Function", diagnostics, ); } symbol_table.push_scope(&format!( "InterfaceDefaultFunctionScope {}", interface_default_function.identifier().name() )); gather_node( interface_default_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_default_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_default_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_default_function.function_body_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_interface_operator_function<'a>( interface_operator_function: &'a mut InterfaceOperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve(interface_operator_function.operator().inner().name()), interface_operator_function.operator().inner().name(), true, false, Some(SourceDefinition::from_operator( interface_operator_function.operator(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, interface_operator_function.operator().inner().name(), interface_operator_function.operator().file_id(), interface_operator_function.operator().range(), "Function", diagnostics, ); } symbol_table.push_scope(&format!( "InterfaceOperatorFunctionScope {}", interface_operator_function.operator().inner().name() )); gather_node( interface_operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_interface_default_operator_function<'a>( interface_default_operator_function: &'a mut InterfaceDefaultOperatorFunction, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let function_symbol = FunctionSymbol::without_parameters_or_return_type( &fqn_context.resolve( interface_default_operator_function .operator() .inner() .name(), ), interface_default_operator_function .operator() .inner() .name(), true, false, Some(SourceDefinition::from_operator( interface_default_operator_function.operator(), )), ); if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) { handle_insert_error( insert_error, interface_default_operator_function .operator() .inner() .name(), interface_default_operator_function.operator().file_id(), interface_default_operator_function.operator().range(), "Function", diagnostics, ); } symbol_table.push_scope(&format!( "InterfaceDefaultOperatorFunctionScope {}", interface_default_operator_function .operator() .inner() .name() )); gather_node( interface_default_operator_function.generics_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_default_operator_function.parameters_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_default_operator_function.return_type_mut(), symbol_table, fqn_context, diagnostics, ); gather_node( interface_default_operator_function.function_body_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.pop_scope(); } fn gather_function_body<'a>( function_body: &'a mut FunctionBody, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("FunctionBodyScope"); gather_node_children(function_body, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); } fn gather_member<'a>( member: &'a mut Member, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let member_symbol = ClassMemberSymbol::new( member.is_public(), member.is_mut(), member.identifier().name(), Some(SourceDefinition::from_identifier(member.identifier())), ); if let Err(insert_error) = symbol_table.insert_class_member_symbol(member_symbol) { handle_insert_error( insert_error, member.identifier().name(), member.identifier().file_id(), member.identifier().range(), "Class Member", diagnostics, ); } gather_node( member.type_use_mut(), symbol_table, fqn_context, diagnostics, ); } fn gather_variable_declaration<'a>( variable_declaration: &'a mut VariableDeclaration, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let variable_symbol = VariableSymbol::new( variable_declaration.identifier().name(), variable_declaration.is_mut(), Some(SourceDefinition::from_identifier( variable_declaration.identifier(), )), ); if let Err(insert_error) = symbol_table.insert_variable_symbol(variable_symbol) { handle_insert_error( insert_error, variable_declaration.identifier().name(), variable_declaration.identifier().file_id(), variable_declaration.identifier().range(), "Variable", diagnostics, ); } if let Some(expression) = variable_declaration.expression_mut() { gather_node(expression, symbol_table, fqn_context, diagnostics); } } fn gather_if_clause<'a>( if_clause: &'a mut IfClause, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("IfClauseScope"); gather_node( if_clause.expression_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("IfClauseStatementsScope"); for statement in if_clause.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); symbol_table.pop_scope(); } fn gather_while_statement<'a>( while_statement: &'a mut WhileStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("WhileStatementScope"); gather_node( while_statement.expression_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("WhileStatementStatementsScope"); for statement in while_statement.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); symbol_table.pop_scope(); } fn gather_for_statement<'a>( for_statement: &'a mut ForStatement, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { gather_node( for_statement.expression_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("ForStatementScope"); let identifier_symbol = VariableSymbol::new( for_statement.identifier().name(), false, Some(SourceDefinition::from_identifier( for_statement.identifier(), )), ); if let Err(insert_error) = symbol_table.insert_variable_symbol(identifier_symbol) { handle_insert_error( insert_error, for_statement.identifier().name(), for_statement.identifier().file_id(), for_statement.identifier().range(), "Variable", diagnostics, ); } symbol_table.push_scope("ForStatementStatementsScope"); for statement in for_statement.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); symbol_table.pop_scope(); } fn gather_variable_use<'a>( variable_use: &'a VariableUse, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { if let Err(lookup_error) = symbol_table.lookup_addressable_by_identifier( variable_use.identifier().name(), symbol_table.current_scope_id(), ) { handle_lookup_error( lookup_error, variable_use.identifier().name(), variable_use.identifier().file_id(), variable_use.identifier().range(), "Variable", diagnostics, ) } } fn gather_ternary_expression<'a>( ternary_expression: &'a mut TernaryExpression, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("TernaryExpressionScope"); gather_node_children(ternary_expression, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); } fn gather_closure<'a>( closure: &'a mut Closure, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { symbol_table.push_scope("ClosureScope"); gather_node( closure.closure_parameters_mut(), symbol_table, fqn_context, diagnostics, ); symbol_table.push_scope("ClosureStatementsScope"); for statement in closure.statements_mut() { gather_node(statement, symbol_table, fqn_context, diagnostics); } symbol_table.pop_scope(); symbol_table.pop_scope(); } fn gather_closure_parameter<'a>( closure_parameter: &'a mut ClosureParameter, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut Vec, ) { let parameter_symbol = ParameterSymbol::new( closure_parameter.identifier().name(), Some(SourceDefinition::from_identifier( closure_parameter.identifier(), )), ); if let Err(insert_err) = symbol_table.insert_parameter_symbol(parameter_symbol) { handle_insert_error( insert_err, closure_parameter.identifier().name(), closure_parameter.identifier().file_id(), closure_parameter.identifier().range(), "Parameter", diagnostics, ); } if let Some(type_use) = closure_parameter.type_use_mut() { gather_node(type_use, symbol_table, fqn_context, diagnostics); } }