deimos-lang/src/name_analysis/gather.rs

1004 lines
29 KiB
Rust

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<usize>,
symbol_types: &str,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) -> Option<Vec<Rc<ParameterSymbol>>> {
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<DmDiagnostic>,
) -> Option<Rc<ParameterSymbol>> {
let parameter_name = parameter.identifier.name();
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
&parameter_name,
Some(&parameter.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,
&parameter_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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<RefCell<Identifier>>,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}
fn gather_class_level_declaration(
declaration: &mut ClassLevelDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
/* Main Declarations */
fn gather_module_declaration(
declaration: &mut ModuleDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// 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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}
fn gather_platform_function_definition(
platform_function_declaration: &mut PlatformFunctionDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}
fn gather_interface_operator_function_declaration(
declaration: &mut InterfaceOperatorFunctionDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
fn gather_function_body(
function_body: &mut FunctionBody,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}
fn gather_property_declaration(
property_declaration: &mut PropertyDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
fn gather_field_declaration(
field_declaration: &mut FieldDeclaration,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
/* Statements */
fn gather_block_statement(
block: &mut BlockStatement,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}
fn gather_if_else_statement(
if_else_statement: &mut IfElseStatement,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
fn gather_while_statement(
while_statement: &mut WhileStatement,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
fn gather_for_statement(
for_statement: &mut ForStatement,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
/* Expressions */
fn gather_expression(
expression: &mut Expression,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
gather_expression(&mut prefix_expression.expression, symbol_table, diagnostics);
}
fn gather_suffix_expression(
suffix_expression: &mut SuffixExpression,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
gather_expression(&mut suffix_expression.expression, symbol_table, diagnostics);
}
fn gather_call_expression(
call_expression: &mut CallExpression,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}
fn gather_closure(
closure: &mut Closure,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
todo!()
}
fn gather_object_access(
object_access: &mut ObjectAccess,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
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<DmDiagnostic>,
) {
todo!()
}