1004 lines
29 KiB
Rust
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(
|
|
¶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<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!()
|
|
}
|