diff --git a/dmc-lib/src/ast/assign_statement.rs b/dmc-lib/src/ast/assign_statement.rs index e00d76c..3eb3f22 100644 --- a/dmc-lib/src/ast/assign_statement.rs +++ b/dmc-lib/src/ast/assign_statement.rs @@ -1,7 +1,9 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; +use crate::ast::helpers::insert_resolved_names_into; use crate::ast::ir_builder::IrBuilder; use crate::ast::ir_util::get_or_init_mut_field_pointer_variable; -use crate::diagnostic::{Diagnostic, SecondaryLabel}; +use crate::diagnostic::{Diagnostic, Diagnostics, SecondaryLabel}; use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_set_field::IrSetField; @@ -10,6 +12,8 @@ use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; use crate::symbol_table::SymbolTable; use crate::types_table::TypesTable; +use std::collections::HashSet; +use std::rc::Rc; pub struct AssignStatement { destination: Box, @@ -33,6 +37,53 @@ impl AssignStatement { self.value.init_scopes(symbol_table, container_scope); } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for expression in [self.destination.as_ref(), self.value.as_ref()] { + let (ns, mut ds) = expression.resolve_names_static(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + initialized_fields: &mut HashSet>, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + { + let (ns, mut ds) = self + .value + .resolve_names_ctor(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + match self.destination.as_ref() { + Expression::Identifier(identifier) => { + let (ns, mut ds) = + identifier.resolve_name_ctor_destination(symbol_table, initialized_fields); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + _ => { + // no-op, because this is a non-L-Value and will be caught during type checking. + } + } + + (names_table, diagnostics) + } + pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/binary_expression.rs b/dmc-lib/src/ast/binary_expression.rs index cbad6b8..50e64fd 100644 --- a/dmc-lib/src/ast/binary_expression.rs +++ b/dmc-lib/src/ast/binary_expression.rs @@ -1,6 +1,8 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; +use crate::ast::helpers::insert_resolved_names_into; use crate::ast::ir_builder::IrBuilder; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::error_codes::BINARY_INCOMPATIBLE_TYPES; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator}; @@ -79,6 +81,53 @@ impl BinaryExpression { self.rhs.init_scopes(symbol_table, container_scope); } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { + let (ns, mut ds) = expression.resolve_names_static(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_field_init( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { + let (ns, mut ds) = expression.resolve_names_field_init(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for expression in [self.lhs.as_ref(), self.rhs.as_ref()] { + let (ns, mut ds) = expression.resolve_names_ctor(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/call.rs b/dmc-lib/src/ast/call.rs index ba2d88d..f2b6608 100644 --- a/dmc-lib/src/ast/call.rs +++ b/dmc-lib/src/ast/call.rs @@ -1,7 +1,9 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; use crate::ast::fqn_util::fqn_parts_to_string; +use crate::ast::helpers::insert_resolved_names_into; use crate::ast::ir_builder::IrBuilder; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostic_factories::class_has_no_constructor; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; @@ -43,6 +45,75 @@ impl Call { } } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + { + let (ns, mut ds) = self.callee.resolve_names_static(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + for argument in &self.arguments { + let (ns, mut ds) = argument.resolve_names_static(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_field_init( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + { + let (ns, mut ds) = self + .callee + .resolve_names_field_init(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + for argument in &self.arguments { + let (ns, mut ds) = argument.resolve_names_field_init(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + { + let (ns, mut ds) = self + .callee + .resolve_names_ctor(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + for argument in &self.arguments { + let (ns, mut ds) = argument.resolve_names_ctor(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index 4742a28..4cd4b84 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -6,9 +6,13 @@ use crate::ast::fqn_context::FqnContext; use crate::ast::fqn_util::fqn_parts_to_string; use crate::ast::function::Function; use crate::ast::generic_parameter::GenericParameter; -use crate::ast::helpers::{collect_diagnostics_mut, collect_diagnostics_single, resolve_ctor_name}; +use crate::ast::helpers::{ + collect_diagnostics_mut, collect_diagnostics_single, insert_resolved_names_into, + resolve_ctor_name, +}; use crate::ast::statement::Statement; -use crate::diagnostic::Diagnostic; +use crate::ast::{NamesTable, NodeId}; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT}; use crate::ir::ir_class::{IrClass, IrField}; use crate::ir::ir_function::IrFunction; @@ -24,6 +28,7 @@ use std::collections::HashSet; use std::rc::Rc; pub struct Class { + node_id: NodeId, declared_name: Rc, declared_name_source_range: SourceRange, generic_parameters: Vec, @@ -37,6 +42,7 @@ pub struct Class { impl Class { pub fn new( + node_id: NodeId, declared_name: &str, declared_name_source_range: SourceRange, generic_parameters: Vec, @@ -45,6 +51,7 @@ impl Class { functions: Vec, ) -> Self { Self { + node_id, declared_name: declared_name.into(), declared_name_source_range, generic_parameters, @@ -147,6 +154,39 @@ impl Class { all_symbols } + pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for generic_parameter in &self.generic_parameters { + let (ns, mut ds) = generic_parameter.resolve_names(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + let self_class_symbol = self.get_class_symbol_owned(symbol_table); + let mut initialized_fields = HashSet::new(); + + for field in &self.fields { + let (ns, mut ds) = field.resolve_names(symbol_table, &self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + initialized_fields.insert(field.declared_name_owned()); + } + + if let Some(constructor) = &self.constructor { + let (ns, mut ds) = constructor.resolve_names( + symbol_table, + self_class_symbol.as_ref(), + &mut initialized_fields, + ); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); @@ -169,6 +209,13 @@ impl Class { diagnostics } + fn get_self_class_symbol<'a>(&self, symbol_table: &'a SymbolTable) -> &'a ClassSymbol { + symbol_table + .get_class_symbol(self.scope_id.unwrap(), &self.declared_name) + .unwrap() + .as_ref() + } + fn get_class_symbol_owned(&self, symbol_table: &SymbolTable) -> Rc { symbol_table .get_class_symbol(self.scope_id.unwrap(), &self.declared_name) diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index 9955d2d..9a31bb8 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -3,8 +3,9 @@ use crate::ast::extern_function::ExternFunction; use crate::ast::fqn_context::FqnContext; use crate::ast::function::Function; use crate::ast::helpers::collect_diagnostics_into_mut; +use crate::ast::{NamesTable, NodeId}; use crate::compile_pipeline::FileId; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_class::IrClass; use crate::ir::ir_function::IrFunction; use crate::symbol::Symbol; @@ -12,6 +13,7 @@ use crate::symbol_table::SymbolTable; use crate::symbol_table::util::try_insert_symbols_into; use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics}; +use std::collections::HashMap; pub struct CompilationUnit { file_id: Option, @@ -106,6 +108,37 @@ impl CompilationUnit { diagnostics_result!(diagnostics) } + pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for function in &self.functions { + let (ns, mut ds) = function.resolve_names_static(symbol_table); + for (node_id, symbol) in ns.into_iter() { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + for extern_function in &self.extern_functions { + let (ns, mut ds) = extern_function.resolve_names_static(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + for class in &self.classes { + let (ns, mut ds) = class.resolve_names(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_names(&self, symbol_table: &mut SymbolTable) -> Result<(), Vec> { let mut diagnostics = vec![]; for class in &self.classes { diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index d0f393c..4e24135 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -1,11 +1,14 @@ +use crate::ast::NamesTable; use crate::ast::field::Field; use crate::ast::fqn_context::FqnContext; use crate::ast::fqn_util::fqn_parts_to_string; -use crate::ast::helpers::{collect_parameter_symbols_into, resolve_ctor_name}; +use crate::ast::helpers::{ + collect_parameter_symbols_into, insert_resolved_names_into, resolve_ctor_name, +}; use crate::ast::ir_builder::IrBuilder; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_allocate::IrAllocate; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; @@ -26,6 +29,7 @@ use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use crate::types_table::TypesTable; use std::cell::RefCell; +use std::collections::HashSet; use std::ops::Neg; use std::rc::Rc; @@ -94,6 +98,31 @@ impl Constructor { (constructor_symbol, all_symbols) } + pub fn resolve_names( + &self, + symbol_table: &mut SymbolTable, + self_class_symbol: &ClassSymbol, + initialized_fields: &mut HashSet>, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for parameter in &self.parameters { + let (ns, mut ds) = parameter.resolve_names(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + for statement in &self.statements { + let (ns, mut ds) = + statement.resolve_names_ctor(symbol_table, self_class_symbol, initialized_fields); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); for parameter in &self.parameters { diff --git a/dmc-lib/src/ast/expression.rs b/dmc-lib/src/ast/expression.rs index 69b0de5..3b12b44 100644 --- a/dmc-lib/src/ast/expression.rs +++ b/dmc-lib/src/ast/expression.rs @@ -1,3 +1,4 @@ +use crate::ast::NamesTable; use crate::ast::binary_expression::BinaryExpression; use crate::ast::call::Call; use crate::ast::double_literal::DoubleLiteral; @@ -6,7 +7,7 @@ use crate::ast::integer_literal::IntegerLiteral; use crate::ast::ir_builder::IrBuilder; use crate::ast::negative_expression::NegativeExpression; use crate::ast::string_literal::StringLiteral; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_operation::IrOperation; @@ -49,6 +50,62 @@ impl Expression { } } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + match self { + Expression::Binary(binary_expression) => { + binary_expression.resolve_names_static(symbol_table) + } + Expression::Negative(negative_expression) => { + negative_expression.resolve_names_static(symbol_table) + } + Expression::Call(call) => call.resolve_names_static(symbol_table), + Expression::Identifier(identifier) => identifier.resolve_name_static(symbol_table), + _ => (NamesTable::new(), Diagnostics::new()), + } + } + + pub fn resolve_names_field_init( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + match self { + Expression::Binary(binary_expression) => { + binary_expression.resolve_names_field_init(symbol_table, self_class_symbol) + } + Expression::Negative(negative_expression) => { + negative_expression.resolve_names_field_init(symbol_table, self_class_symbol) + } + Expression::Call(call) => { + call.resolve_names_field_init(symbol_table, self_class_symbol) + } + Expression::Identifier(identifier) => { + identifier.resolve_name_field_init(symbol_table, self_class_symbol) + } + _ => (NamesTable::new(), Diagnostics::new()), + } + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + match self { + Expression::Binary(binary_expression) => { + binary_expression.resolve_names_ctor(symbol_table, self_class_symbol) + } + Expression::Negative(negative_expression) => { + negative_expression.resolve_names_ctor(symbol_table, self_class_symbol) + } + Expression::Call(call) => call.resolve_names_ctor(symbol_table, self_class_symbol), + Expression::Identifier(identifier) => { + identifier.resolve_name_ctor(symbol_table, self_class_symbol) + } + _ => (NamesTable::new(), Diagnostics::new()), + } + } + pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/expression_statement.rs b/dmc-lib/src/ast/expression_statement.rs index 4122df2..65f82a6 100644 --- a/dmc-lib/src/ast/expression_statement.rs +++ b/dmc-lib/src/ast/expression_statement.rs @@ -1,6 +1,7 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_return::IrReturn; use crate::ir::ir_statement::IrStatement; use crate::symbol::class_symbol::ClassSymbol; @@ -27,6 +28,19 @@ impl ExpressionStatement { self.expression.init_scopes(symbol_table, container_scope); } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + self.expression.resolve_names_static(symbol_table) + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + self.expression + .resolve_names_ctor(symbol_table, self_class_symbol) + } + pub fn check_constructor_local_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/extern_function.rs b/dmc-lib/src/ast/extern_function.rs index 4ab26d4..d7ee0dd 100644 --- a/dmc-lib/src/ast/extern_function.rs +++ b/dmc-lib/src/ast/extern_function.rs @@ -1,8 +1,11 @@ use crate::ast::fqn_context::FqnContext; -use crate::ast::helpers::{collect_diagnostics_into_mut, collect_parameter_symbols_into}; +use crate::ast::helpers::{ + collect_diagnostics_into_mut, collect_parameter_symbols_into, resolve_parameter_names_into, +}; use crate::ast::parameter::Parameter; use crate::ast::type_use::TypeUse; -use crate::diagnostic::Diagnostic; +use crate::ast::{NamesTable, NodeId}; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::source_range::SourceRange; use crate::symbol::Symbol; use crate::symbol::function_symbol::FunctionSymbol; @@ -13,6 +16,7 @@ use crate::{diagnostics_result, handle_diagnostics}; use std::rc::Rc; pub struct ExternFunction { + node_id: NodeId, declared_name: Rc, declared_name_source_range: SourceRange, parameters: Vec, @@ -22,12 +26,14 @@ pub struct ExternFunction { impl ExternFunction { pub fn new( + node_id: NodeId, name: &str, declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, ) -> Self { Self { + node_id, declared_name: name.into(), declared_name_source_range, parameters, @@ -74,6 +80,28 @@ impl ExternFunction { (function_symbol, all_symbols) } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + resolve_parameter_names_into( + &self.parameters, + symbol_table, + &mut names_table, + &mut diagnostics, + ); + + { + let (ns, mut ds) = self.return_type.resolve_names(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); for parameter in &self.parameters { diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index 456d893..f4ed690 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -1,6 +1,8 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; +use crate::ast::helpers::insert_resolved_names_into; use crate::ast::type_use::TypeUse; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostic_factories::field_has_no_type_or_init; use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; @@ -79,6 +81,30 @@ impl Field { ) } + pub fn resolve_names( + &self, + symbol_table: &SymbolTable, + class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut names_table = NamesTable::new(); + let mut diagnostics = Diagnostics::new(); + + if let Some(type_use) = &self.declared_type { + let (ns, mut ds) = type_use.resolve_names(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + if let Some(initializer) = &self.initializer { + let (ns, mut ds) = initializer.resolve_names_field_init(symbol_table, class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + #[deprecated] pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); if let Some(type_use) = &self.declared_type { @@ -87,6 +113,7 @@ impl Field { diagnostics } + #[deprecated] pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 2533661..571cd64 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -2,13 +2,14 @@ use crate::ast::fqn_context::FqnContext; use crate::ast::fqn_util::fqn_parts_to_string; use crate::ast::helpers::{ collect_diagnostics_into_enumerated_mut, collect_diagnostics_into_mut, - collect_parameter_symbols_into, + collect_parameter_symbols_into, resolve_parameter_names_into, }; use crate::ast::ir_builder::IrBuilder; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; use crate::ast::type_use::TypeUse; -use crate::diagnostic::Diagnostic; +use crate::ast::{NamesTable, NodeId}; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_function::IrFunction; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_parameter_or_variable::IrParameterOrVariable; @@ -24,6 +25,7 @@ use std::ops::Neg; use std::rc::Rc; pub struct Function { + node_id: NodeId, declared_name: Rc, declared_name_source_range: SourceRange, is_public: bool, @@ -35,6 +37,7 @@ pub struct Function { impl Function { pub fn new( + node_id: NodeId, declared_name: &str, declared_name_source_range: SourceRange, is_public: bool, @@ -43,6 +46,7 @@ impl Function { statements: Vec, ) -> Self { Self { + node_id, declared_name: declared_name.into(), declared_name_source_range, is_public, @@ -108,6 +112,51 @@ impl Function { (function_symbol, all_symbols) } + fn resolve_names_common(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + resolve_parameter_names_into( + &self.parameters, + symbol_table, + &mut names_table, + &mut diagnostics, + ); + + if let Some(type_use) = &self.return_type { + let (ns, mut ds) = type_use.resolve_names(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_static( + &self, + symbol_table: &mut SymbolTable, + ) -> (NamesTable, Diagnostics) { + let (mut names_table, mut diagnostics) = self.resolve_names_common(symbol_table); + + for statement in &self.statements { + let (ns, mut ds) = statement.resolve_names_static(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_method(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let (names_table, diagnostics) = self.resolve_names_common(symbol_table); + + (names_table, diagnostics) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics = Vec::new(); for parameter in &self.parameters { diff --git a/dmc-lib/src/ast/generic_parameter.rs b/dmc-lib/src/ast/generic_parameter.rs index 06764ea..a2689db 100644 --- a/dmc-lib/src/ast/generic_parameter.rs +++ b/dmc-lib/src/ast/generic_parameter.rs @@ -1,5 +1,7 @@ +use crate::ast::NamesTable; +use crate::ast::helpers::insert_resolved_names_into; use crate::ast::type_use::TypeUse; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::source_range::SourceRange; use crate::symbol::generic_parameter_symbol::GenericParameterSymbol; use crate::symbol_table::SymbolTable; @@ -47,6 +49,19 @@ impl GenericParameter { ) } + pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + for type_use in &self.extends { + let (ns, mut ds) = type_use.resolve_names(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + (names_table, diagnostics) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { self.extends .iter() diff --git a/dmc-lib/src/ast/helpers.rs b/dmc-lib/src/ast/helpers.rs index c4bfcef..1ecdb9a 100644 --- a/dmc-lib/src/ast/helpers.rs +++ b/dmc-lib/src/ast/helpers.rs @@ -1,9 +1,11 @@ +use crate::ast::NamesTable; use crate::ast::fqn_context::FqnContext; use crate::ast::parameter::Parameter; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostics_result; use crate::symbol::Symbol; use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::symbol_table::SymbolTable; use std::rc::Rc; /// Iterates through all `ts`, running the `f` function, and pushing returned `Diagnostic`s @@ -104,3 +106,24 @@ pub fn collect_parameter_symbols_into( parameter_symbols.push(symbol); } } + +pub fn resolve_parameter_names_into( + parameters: &[Parameter], + symbol_table: &SymbolTable, + names_table: &mut NamesTable, + diagnostics: &mut Diagnostics, +) { + for parameter in parameters { + let (ns, mut ds) = parameter.resolve_names(symbol_table); + for (node_id, symbol) in ns { + names_table.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } +} + +pub fn insert_resolved_names_into(source: NamesTable, destination: &mut NamesTable) { + for (node_id, symbol) in source { + destination.insert(node_id, symbol); + } +} diff --git a/dmc-lib/src/ast/identifier.rs b/dmc-lib/src/ast/identifier.rs index d347dda..4d3ef1d 100644 --- a/dmc-lib/src/ast/identifier.rs +++ b/dmc-lib/src/ast/identifier.rs @@ -1,9 +1,11 @@ use crate::ast::ir_builder::IrBuilder; use crate::ast::ir_util::get_or_init_field_pointer_variable; -use crate::diagnostic::Diagnostic; +use crate::ast::{NamesTable, NodeId}; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostic_factories::{ - outer_class_field_usage, outer_class_method_usage, self_constructor_used_in_init, - self_field_used_in_init, self_method_used_in_init, symbol_not_found, + cannot_reassign_immutable_field, not_assignable, outer_class_field_usage, + outer_class_method_usage, self_constructor_used_in_init, self_field_used_in_init, + self_method_used_in_init, symbol_not_found, }; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; @@ -12,6 +14,7 @@ use crate::ir::ir_read_field::IrReadField; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; use crate::source_range::SourceRange; +use crate::symbol::Symbol; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; use crate::symbol::field_symbol::FieldSymbol; @@ -20,17 +23,20 @@ use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use crate::types_table::TypesTable; use std::cell::RefCell; +use std::collections::HashSet; use std::rc::Rc; pub struct Identifier { - name: String, + node_id: NodeId, + name: Rc, source_range: SourceRange, scope_id: Option, } impl Identifier { - pub fn new(name: &str, source_range: SourceRange) -> Self { + pub fn new(node_id: NodeId, name: &str, source_range: SourceRange) -> Self { Self { + node_id, name: name.into(), source_range, scope_id: None, @@ -49,7 +55,222 @@ impl Identifier { self.scope_id.unwrap() } + pub fn resolve_name_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + match symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name) { + None => { + diagnostics.push(symbol_not_found(&self.name, &self.source_range)); + } + Some(expressible_symbol) => { + names_table.insert(self.node_id, expressible_symbol.into_symbol()); + } + } + + (names_table, diagnostics) + } + + pub fn resolve_name_field_init( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); + if let Some(symbol) = symbol { + match symbol { + ExpressibleSymbol::Class(class_symbol) => { + self.init_referring_to_class( + self_class_symbol, + &class_symbol, + &mut names_table, + &mut diagnostics, + ); + } + ExpressibleSymbol::Field(field_symbol) => { + self.init_referring_to_field( + self_class_symbol, + &field_symbol, + &mut diagnostics, + ); + } + ExpressibleSymbol::Function(function_symbol) => { + self.init_referring_to_function( + self_class_symbol, + &function_symbol, + &mut names_table, + &mut diagnostics, + ); + } + ExpressibleSymbol::Parameter(_) => { + // Cannot get here, because classes cannot currently be declared in functions + unreachable!() + } + ExpressibleSymbol::Variable(_) => { + // Cannot get here, as classes cannot currently be declared in functions + unreachable!() + } + } + } else { + diagnostics.push(symbol_not_found(&self.name, &self.source_range)); + } + + (names_table, diagnostics) + } + + pub fn resolve_name_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); + if let Some(symbol) = symbol { + match symbol { + ExpressibleSymbol::Class(class_symbol) => { + self.init_referring_to_class( + self_class_symbol, + &class_symbol, + &mut names_table, + &mut diagnostics, + ); + } + ExpressibleSymbol::Field(field_symbol) => { + self.init_referring_to_field( + self_class_symbol, + &field_symbol, + &mut diagnostics, + ); + } + ExpressibleSymbol::Function(function_symbol) => { + self.init_referring_to_function( + self_class_symbol, + &function_symbol, + &mut names_table, + &mut diagnostics, + ); + } + ExpressibleSymbol::Parameter(parameter_symbol) => { + names_table.insert(self.node_id, Symbol::Parameter(parameter_symbol)); + } + ExpressibleSymbol::Variable(variable_symbol) => { + names_table.insert(self.node_id, Symbol::Variable(variable_symbol)); + } + } + } else { + diagnostics.push(symbol_not_found(&self.name, &self.source_range)); + } + + (names_table, diagnostics) + } + + pub fn resolve_name_ctor_destination( + &self, + symbol_table: &SymbolTable, + initialized_fields: &mut HashSet>, + ) -> (NamesTable, Diagnostics) { + let mut diagnostics = Diagnostics::new(); + let mut names_table = NamesTable::new(); + + let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name); + if let Some(symbol) = symbol { + match symbol { + ExpressibleSymbol::Class(_) => { + // error + diagnostics.push(not_assignable(&self.name, &self.source_range)); + } + ExpressibleSymbol::Field(field_symbol) => { + // ok if field has not been initialized yet OR field is mutable + if !initialized_fields.contains(&self.name) { + initialized_fields.insert(self.name.clone()); + names_table.insert(self.node_id, Symbol::Field(field_symbol)); + } else if !field_symbol.is_mut() { + // error since we are trying to reassign an immutable field + diagnostics.push(cannot_reassign_immutable_field(&self.source_range)); + } else { + // mut is ok + names_table.insert(self.node_id, Symbol::Field(field_symbol)); + } + } + ExpressibleSymbol::Function(_) => { + diagnostics.push(not_assignable(&self.name, &self.source_range)); + } + ExpressibleSymbol::Parameter(_) => { + // assigning to parameter is an error + // we may in the future allow mut on parameters, but it's probably pointless + diagnostics.push(not_assignable(&self.name, &self.source_range)); + } + ExpressibleSymbol::Variable(variable_symbol) => { + // ok + names_table.insert(self.node_id, Symbol::Variable(variable_symbol)); + } + } + } else { + diagnostics.push(symbol_not_found(&self.name, &self.source_range)); + } + + (names_table, diagnostics) + } + + fn init_referring_to_class( + &self, + self_class_symbol: &ClassSymbol, + class_symbol: &Rc, + names_table: &mut NamesTable, + diagnostics: &mut Diagnostics, + ) { + // Check against recursively constructing this class. + // This is not future-proof, as we will eventually allow reference to the self class, which + // would (theoretically) be assigned to an instance field. + if self_class_symbol == class_symbol.as_ref() { + diagnostics.push(self_constructor_used_in_init(&self.source_range)); + } else { + names_table.insert(self.node_id, Symbol::Class(class_symbol.clone())); + } + } + + fn init_referring_to_field( + &self, + self_class_symbol: &ClassSymbol, + field_symbol: &FieldSymbol, + diagnostics: &mut Diagnostics, + ) { + if self_class_symbol + .fields() + .contains_key(field_symbol.declared_name()) + { + diagnostics.push(self_field_used_in_init(&self.source_range)); + } else { + diagnostics.push(outer_class_field_usage(&self.source_range)); + } + } + + fn init_referring_to_function( + &self, + self_class_symbol: &ClassSymbol, + function_symbol: &Rc, + names_table: &mut NamesTable, + diagnostics: &mut Diagnostics, + ) { + if self_class_symbol + .functions() + .contains_key(function_symbol.declared_name()) + { + diagnostics.push(self_method_used_in_init(&self.source_range)); + } else if function_symbol.is_method() { + diagnostics.push(outer_class_method_usage(&self.source_range)); + } else { + names_table.insert(self.node_id, Symbol::Function(function_symbol.clone())); + } + } + /// Check against recursively constructing this class. + #[deprecated] fn check_self_constructor_use( &self, context_class_symbol: &ClassSymbol, @@ -65,6 +286,7 @@ impl Identifier { } /// Check against using this or outer class' bare fields. + #[deprecated] fn check_self_or_outer_field_use( &self, context_class_symbol: &ClassSymbol, @@ -82,6 +304,7 @@ impl Identifier { } /// Check against using self or outer class methods. + #[deprecated] fn check_self_or_outer_method_use( &self, context_class_symbol: &ClassSymbol, @@ -101,6 +324,7 @@ impl Identifier { } } + #[deprecated] pub fn check_name_as_field_initializer( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/let_statement.rs b/dmc-lib/src/ast/let_statement.rs index 6cde991..edb8bf6 100644 --- a/dmc-lib/src/ast/let_statement.rs +++ b/dmc-lib/src/ast/let_statement.rs @@ -1,6 +1,8 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; +use crate::ast::helpers::insert_resolved_names_into; use crate::ast::ir_builder::IrBuilder; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_statement::IrStatement; use crate::ir::ir_variable::IrVariable; @@ -73,6 +75,49 @@ impl LetStatement { try_insert_symbol_into(Symbol::Variable(variable_symbol), symbol_table).err() } + pub fn resolve_names_static( + &self, + symbol_table: &mut SymbolTable, + ) -> (NamesTable, Diagnostics) { + let mut names_table = NamesTable::new(); + let mut diagnostics = Diagnostics::new(); + + { + let (ns, mut ds) = self.initializer.resolve_names_static(symbol_table); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) { + diagnostics.push(diagnostic); + } + + (names_table, diagnostics) + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &mut SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + let mut names_table = NamesTable::new(); + let mut diagnostics = Diagnostics::new(); + + { + let (ns, mut ds) = self + .initializer + .resolve_names_ctor(symbol_table, self_class_symbol); + insert_resolved_names_into(ns, &mut names_table); + diagnostics.append(&mut ds); + } + + if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) { + diagnostics.push(diagnostic); + } + + (names_table, diagnostics) + } + pub fn analyze_constructor_local_names( &self, symbol_table: &mut SymbolTable, diff --git a/dmc-lib/src/ast/mod.rs b/dmc-lib/src/ast/mod.rs index 44722a6..344bde0 100644 --- a/dmc-lib/src/ast/mod.rs +++ b/dmc-lib/src/ast/mod.rs @@ -1,3 +1,6 @@ +use crate::symbol::Symbol; +use std::collections::HashMap; + pub mod assign_statement; pub mod binary_expression; pub mod call; @@ -25,3 +28,6 @@ pub mod parameter; pub mod statement; pub mod string_literal; pub mod type_use; + +pub type NodeId = usize; +pub type NamesTable = HashMap; diff --git a/dmc-lib/src/ast/negative_expression.rs b/dmc-lib/src/ast/negative_expression.rs index 46dcdcf..df58463 100644 --- a/dmc-lib/src/ast/negative_expression.rs +++ b/dmc-lib/src/ast/negative_expression.rs @@ -1,6 +1,7 @@ +use crate::ast::NamesTable; use crate::ast::expression::Expression; use crate::ast::ir_builder::IrBuilder; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator}; use crate::ir::ir_expression::IrExpression; @@ -46,6 +47,28 @@ impl NegativeExpression { self.operand.init_scopes(symbol_table, container_scope); } + pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + self.operand.resolve_names_static(symbol_table) + } + + pub fn resolve_names_field_init( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + self.operand + .resolve_names_field_init(symbol_table, self_class_symbol) + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &SymbolTable, + self_class_symbol: &ClassSymbol, + ) -> (NamesTable, Diagnostics) { + self.operand + .resolve_names_ctor(symbol_table, self_class_symbol) + } + pub fn check_field_initializer_names( &self, symbol_table: &SymbolTable, diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index a2617bc..7e0e0fe 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -1,5 +1,6 @@ +use crate::ast::NamesTable; use crate::ast::type_use::TypeUse; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::source_range::SourceRange; use crate::symbol::parameter_symbol::ParameterSymbol; use crate::symbol_table::SymbolTable; @@ -48,6 +49,10 @@ impl Parameter { ) } + pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + self.type_use.resolve_names(symbol_table) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { self.type_use.check_names(symbol_table) } diff --git a/dmc-lib/src/ast/statement.rs b/dmc-lib/src/ast/statement.rs index 7c65a2c..7f12da3 100644 --- a/dmc-lib/src/ast/statement.rs +++ b/dmc-lib/src/ast/statement.rs @@ -1,12 +1,15 @@ +use crate::ast::NamesTable; use crate::ast::assign_statement::AssignStatement; use crate::ast::expression_statement::ExpressionStatement; use crate::ast::ir_builder::IrBuilder; use crate::ast::let_statement::LetStatement; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use crate::types_table::TypesTable; +use std::collections::HashSet; +use std::rc::Rc; pub enum Statement { Let(LetStatement), @@ -29,6 +32,42 @@ impl Statement { } } + pub fn resolve_names_static( + &self, + symbol_table: &mut SymbolTable, + ) -> (NamesTable, Diagnostics) { + match self { + Statement::Let(let_statement) => let_statement.resolve_names_static(symbol_table), + Statement::Expression(expression_statement) => { + expression_statement.resolve_names_static(symbol_table) + } + Statement::Assign(assign_statement) => { + assign_statement.resolve_names_static(symbol_table) + } + } + } + + pub fn resolve_names_ctor( + &self, + symbol_table: &mut SymbolTable, + self_class_symbol: &ClassSymbol, + initialized_fields: &mut HashSet>, + ) -> (NamesTable, Diagnostics) { + match self { + Statement::Let(let_statement) => { + let_statement.resolve_names_ctor(symbol_table, self_class_symbol) + } + Statement::Expression(expression_statement) => { + expression_statement.resolve_names_ctor(symbol_table, self_class_symbol) + } + Statement::Assign(assign_statement) => assign_statement.resolve_names_ctor( + symbol_table, + self_class_symbol, + initialized_fields, + ), + } + } + pub fn analyze_constructor_local_names( &self, symbol_table: &mut SymbolTable, diff --git a/dmc-lib/src/ast/type_use.rs b/dmc-lib/src/ast/type_use.rs index e40c645..cfd436a 100644 --- a/dmc-lib/src/ast/type_use.rs +++ b/dmc-lib/src/ast/type_use.rs @@ -1,4 +1,5 @@ -use crate::diagnostic::Diagnostic; +use crate::ast::{NamesTable, NodeId}; +use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostic_factories::symbol_not_found; use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS; use crate::source_range::SourceRange; @@ -7,9 +8,11 @@ use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; use crate::types_table::TypesTable; use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics}; +use std::collections::HashMap; use std::rc::Rc; pub struct TypeUse { + node_id: NodeId, declared_name: Rc, declared_name_source_range: SourceRange, generic_arguments: Vec, @@ -18,11 +21,13 @@ pub struct TypeUse { impl TypeUse { pub fn new( + node_id: NodeId, declared_name: &str, declared_name_source_range: SourceRange, generic_arguments: Vec, ) -> Self { Self { + node_id, declared_name: declared_name.into(), declared_name_source_range, generic_arguments, @@ -41,6 +46,35 @@ impl TypeUse { } } + pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) { + let mut diagnostics = Vec::new(); + let mut resolved_names = HashMap::new(); + + // resolve this name + match symbol_table.find_type_symbol(self.scope_id.unwrap(), &self.declared_name) { + None => { + diagnostics.push(symbol_not_found( + &self.declared_name, + &self.declared_name_source_range, + )); + } + Some(type_symbol) => { + resolved_names.insert(self.node_id, type_symbol.into_symbol()); + } + } + + // check generic args + for type_use in &self.generic_arguments { + let (ns, mut ds) = type_use.resolve_names(symbol_table); + for (node_id, symbol) in ns { + resolved_names.insert(node_id, symbol); + } + diagnostics.append(&mut ds); + } + + (resolved_names, diagnostics) + } + pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); diff --git a/dmc-lib/src/compile_pipeline.rs b/dmc-lib/src/compile_pipeline.rs index 365e30d..e5fc5b6 100644 --- a/dmc-lib/src/compile_pipeline.rs +++ b/dmc-lib/src/compile_pipeline.rs @@ -43,5 +43,15 @@ pub fn compile_compilation_units(inputs: &HashMap) -> Result<(), D .collect::>(); try_insert_symbols_into(all_symbols, &mut symbol_table)?; + // now we can just finish each compilation unit, since we have the symbols + let mut diagnostics = Vec::new(); + for compilation_unit in compilation_units.values() { + let (resolved_names, mut ds) = compilation_unit.resolve_names(&mut symbol_table); + if !ds.is_empty() { + diagnostics.append(&mut ds); + continue; + } + } + Ok(()) } diff --git a/dmc-lib/src/diagnostic_factories.rs b/dmc-lib/src/diagnostic_factories.rs index 563e81c..2bfb695 100644 --- a/dmc-lib/src/diagnostic_factories.rs +++ b/dmc-lib/src/diagnostic_factories.rs @@ -1,8 +1,8 @@ use crate::diagnostic::{Diagnostic, SecondaryLabel}; use crate::error_codes::{ - CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT, OUTER_CLASS_FIELD_USED_IN_INIT, - OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT, SELF_FIELD_USED_IN_INIT, - SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND, + ASSIGN_LHS_IMMUTABLE, CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT, NOT_ASSIGNABLE, + OUTER_CLASS_FIELD_USED_IN_INIT, OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT, + SELF_FIELD_USED_IN_INIT, SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND, }; use crate::source_range::SourceRange; use crate::symbol::Symbol; @@ -117,3 +117,21 @@ pub fn class_has_no_constructor(name: &str, source_range: &SourceRange) -> Diagn ) .with_error_code(CLASS_NO_CONSTRUCTOR) } + +pub fn not_assignable(name: &str, source_range: &SourceRange) -> Diagnostic { + Diagnostic::new( + &format!("Symbol {} is not assignable.", name), + source_range.start(), + source_range.end(), + ) + .with_error_code(NOT_ASSIGNABLE) +} + +pub fn cannot_reassign_immutable_field(source_range: &SourceRange) -> Diagnostic { + Diagnostic::new( + "Cannot reassign an immutable field.", + source_range.start(), + source_range.end(), + ) + .with_error_code(ASSIGN_LHS_IMMUTABLE) +} diff --git a/dmc-lib/src/error_codes.rs b/dmc-lib/src/error_codes.rs index 8f1a701..2e4e198 100644 --- a/dmc-lib/src/error_codes.rs +++ b/dmc-lib/src/error_codes.rs @@ -19,3 +19,4 @@ pub const OUTER_CLASS_FIELD_USED_IN_INIT: ErrorCode = 26; pub const OUTER_CLASS_METHOD_USED_IN_INIT: ErrorCode = 27; pub const FIELD_NO_TYPE_OR_INIT: ErrorCode = 28; pub const CLASS_NO_CONSTRUCTOR: ErrorCode = 29; +pub const NOT_ASSIGNABLE: ErrorCode = 30; diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index 3993639..998534f 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -425,6 +425,7 @@ impl<'a> Parser<'a> { if let Some(identifier) = maybe_identifier { let function = Function::new( + self.next_node_id(), self.token_text(&identifier), SourceRange::new(identifier.start(), identifier.end()), is_public, @@ -466,6 +467,7 @@ impl<'a> Parser<'a> { && let Some(type_use) = return_type { let extern_function = ExternFunction::new( + self.next_node_id(), self.token_text(&identifier), SourceRange::new(identifier.start(), identifier.end()), parameters, @@ -539,6 +541,7 @@ impl<'a> Parser<'a> { if let Some(identifier) = maybe_identifier { let class = Class::new( + self.next_node_id(), self.token_text(&identifier), SourceRange::new(identifier.start(), identifier.end()), generic_parameters, @@ -641,6 +644,7 @@ impl<'a> Parser<'a> { if let Some(identifier) = maybe_identifier { let type_use = TypeUse::new( + self.next_node_id(), self.token_text(&identifier), SourceRange::new(identifier.start(), identifier.end()), generic_arguments, @@ -1312,7 +1316,11 @@ impl<'a> Parser<'a> { let source_range = SourceRange::new(current.start(), current.end()); diagnostics.append(&mut self.advance()); ( - Expression::Identifier(Identifier::new(declared_name, source_range)), + Expression::Identifier(Identifier::new( + self.next_node_id(), + declared_name, + source_range, + )), diagnostics, ) } diff --git a/dmc-lib/src/symbol/expressible_symbol.rs b/dmc-lib/src/symbol/expressible_symbol.rs index 25b0ac5..7707274 100644 --- a/dmc-lib/src/symbol/expressible_symbol.rs +++ b/dmc-lib/src/symbol/expressible_symbol.rs @@ -1,4 +1,5 @@ use crate::source_range::SourceRange; +use crate::symbol::Symbol; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::field_symbol::FieldSymbol; use crate::symbol::function_symbol::FunctionSymbol; @@ -15,6 +16,16 @@ pub enum ExpressibleSymbol { } impl ExpressibleSymbol { + pub fn into_symbol(self) -> Symbol { + match self { + ExpressibleSymbol::Class(class_symbol) => Symbol::Class(class_symbol), + ExpressibleSymbol::Field(field_symbol) => Symbol::Field(field_symbol), + ExpressibleSymbol::Function(function_symbol) => Symbol::Function(function_symbol), + ExpressibleSymbol::Parameter(parameter_symbol) => Symbol::Parameter(parameter_symbol), + ExpressibleSymbol::Variable(variable_symbol) => Symbol::Variable(variable_symbol), + } + } + pub fn source_range(&self) -> Option<&SourceRange> { match self { ExpressibleSymbol::Class(class_symbol) => class_symbol.declared_name_source_range(), diff --git a/dmc-lib/src/symbol/type_symbol.rs b/dmc-lib/src/symbol/type_symbol.rs index d718b03..d8860fc 100644 --- a/dmc-lib/src/symbol/type_symbol.rs +++ b/dmc-lib/src/symbol/type_symbol.rs @@ -1,3 +1,4 @@ +use crate::symbol::Symbol; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::generic_parameter_symbol::GenericParameterSymbol; use std::rc::Rc; @@ -6,3 +7,14 @@ pub enum TypeSymbol { Class(Rc), GenericParameter(Rc), } + +impl TypeSymbol { + pub fn into_symbol(self) -> Symbol { + match self { + TypeSymbol::Class(class_symbol) => Symbol::Class(class_symbol), + TypeSymbol::GenericParameter(generic_parameter_symbol) => { + Symbol::GenericParameter(generic_parameter_symbol) + } + } + } +}