diff --git a/dm/src/repl.rs b/dm/src/repl.rs index f0dce6f..a3918b4 100644 --- a/dm/src/repl.rs +++ b/dm/src/repl.rs @@ -133,8 +133,12 @@ fn compile_expression( "__repl", SourceRange::new(0, 0), false, - expression.type_info().clone(), // dubious ))); + + fake_function_symbol + .borrow_mut() + .set_return_type_info(expression.type_info().clone()); + let mut ir_function = IrFunction::new( fake_function_symbol, &[], diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index 4d51a1d..a7c1736 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -2,7 +2,8 @@ use crate::ast::field::Field; use crate::ast::function::Function; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; -use crate::symbol_table::SymbolTable; +use crate::symbol::class_symbol::ClassSymbol; +use crate::symbol_table::{SymbolInsertError, SymbolTable}; use std::rc::Rc; pub struct Class { @@ -32,16 +33,142 @@ impl Class { symbol_table: &mut SymbolTable, ) -> Result<(), Vec> { // 1. insert class symbol - // 2. gather fields - // 3. gather functions - todo!() + let to_insert = ClassSymbol::new( + &self.declared_name, + self.declared_name_source_range.clone(), + false, + ); + + symbol_table + .insert_class_symbol(to_insert) + .map_err(|e| match e { + SymbolInsertError::AlreadyDeclared(already_declared) => { + vec![ + Diagnostic::new( + &format!( + "Symbol {} already declared in current scope.", + already_declared.symbol().borrow().declared_name(), + ), + self.declared_name_source_range.start(), + self.declared_name_source_range.end(), + ) + .with_reporter(file!(), line!()), + ] + } + })?; + + // 2. push scope + symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name)); + + // 3. gather fields + let fields_diagnostics: Vec = self + .fields + .iter_mut() + .map(|field| field.gather_declared_names(symbol_table)) + .filter_map(Result::err) + .flatten() + .collect(); + + if !fields_diagnostics.is_empty() { + return Err(fields_diagnostics); + } + + // 4. gather functions + let functions_diagnostics: Vec = self + .functions + .iter_mut() + .map(|function| function.gather_declared_names(symbol_table)) + .filter_map(Result::err) + .flatten() + .collect(); + + if !functions_diagnostics.is_empty() { + return Err(functions_diagnostics); + } + + // 5. pop scope + symbol_table.pop_scope(); + + Ok(()) } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { - todo!() + let fields_diagnostics: Vec = self + .fields + .iter_mut() + .map(|field| field.check_name_usages(symbol_table)) + .filter_map(Result::err) + .flatten() + .collect(); + if !fields_diagnostics.is_empty() { + return Err(fields_diagnostics); + } + + let functions_diagnostics: Vec = self + .functions + .iter_mut() + .map(|function| function.check_name_usages(symbol_table)) + .filter_map(Result::err) + .flatten() + .collect(); + + if functions_diagnostics.is_empty() { + Ok(()) + } else { + Err(functions_diagnostics) + } } pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { todo!() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::parser::parse_compilation_unit; + + #[test] + fn name_analysis_no_diagnostics() { + let parse_result = parse_compilation_unit( + " + class Foo + mut bar = 42 + + fn baz() -> Int + bar + end + end + + class Qux + fn foo() -> Foo + Foo() + end + end + ", + ); + + let mut compilation_unit = match parse_result { + Ok(compilation_unit) => compilation_unit, + Err(diagnostics) => { + panic!("{:?}", diagnostics); + } + }; + + let mut symbol_table = SymbolTable::new(); + match compilation_unit.gather_declared_names(&mut symbol_table) { + Ok(_) => {} + Err(diagnostics) => { + panic!("{:?}", diagnostics); + } + } + + match compilation_unit.check_name_usages(&symbol_table) { + Ok(_) => {} + Err(diagnostics) => { + panic!("{:?}", diagnostics); + } + } + } +} diff --git a/dmc-lib/src/ast/extern_function.rs b/dmc-lib/src/ast/extern_function.rs index ea94149..11ce302 100644 --- a/dmc-lib/src/ast/extern_function.rs +++ b/dmc-lib/src/ast/extern_function.rs @@ -4,12 +4,15 @@ use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; +use std::cell::RefCell; +use std::rc::Rc; pub struct ExternFunction { declared_name: String, declared_name_source_range: SourceRange, parameters: Vec, return_type: TypeUse, + function_symbol: Option>>, } impl ExternFunction { @@ -24,6 +27,7 @@ impl ExternFunction { declared_name_source_range, parameters, return_type, + function_symbol: None, } } @@ -41,7 +45,6 @@ impl ExternFunction { &self.declared_name, self.declared_name_source_range.clone(), true, - self.return_type.to_type_info(), )); let function_symbol = match insert_result { @@ -82,6 +85,16 @@ impl ExternFunction { .borrow_mut() .set_parameters(parameter_symbols); + self.function_symbol = Some(function_symbol); + + // handle return type + match self.return_type.gather_declared_names(symbol_table) { + Ok(_) => {} + Err(mut type_use_diagnostics) => { + diagnostics.append(&mut type_use_diagnostics); + } + } + symbol_table.pop_scope(); // function scope if diagnostics.is_empty() { @@ -92,14 +105,29 @@ impl ExternFunction { } pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { - let diagnostics: Vec = self + let mut diagnostics: Vec = self .parameters .iter_mut() .map(|parameter| parameter.check_name_usages(symbol_table)) .filter_map(Result::err) .flatten() .collect(); + + match self.return_type.check_name_usages(symbol_table) { + Ok(_) => {} + Err(mut return_type_diagnostics) => { + diagnostics.append(&mut return_type_diagnostics); + } + } + if diagnostics.is_empty() { + // set return type info on symbol now that its available + self.function_symbol + .as_mut() + .unwrap() + .borrow_mut() + .set_return_type_info(self.return_type.to_type_info()); + Ok(()) } else { Err(diagnostics) diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index 4aa8c76..e864ad4 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -1,6 +1,9 @@ use crate::ast::expression::Expression; use crate::ast::type_use::TypeUse; +use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; +use crate::symbol::field_symbol::FieldSymbol; +use crate::symbol_table::{SymbolInsertError, SymbolTable}; use std::rc::Rc; pub struct Field { @@ -30,4 +33,51 @@ impl Field { initializer: initializer.map(Box::new), } } + + pub fn gather_declared_names( + &mut self, + symbol_table: &mut SymbolTable, + ) -> Result<(), Vec> { + // 1. insert field symbol + let to_insert = + FieldSymbol::new(&self.declared_name, self.declared_name_source_range.clone()); + + symbol_table + .insert_field_symbol(to_insert) + .map_err(|e| match e { + SymbolInsertError::AlreadyDeclared(already_declared) => { + vec![Diagnostic::new( + &format!( + "Symbol {} already declared in current scope.", + already_declared.symbol().borrow().declared_name() + ), + self.declared_name_source_range.start(), + self.declared_name_source_range.end(), + )] + } + })?; + + // 2. gather initializer, if present + if let Some(initializer) = &mut self.initializer { + initializer.gather_declared_names(symbol_table)?; + } + + Ok(()) + } + + pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + if let Some(type_use) = &mut self.declared_type { + type_use.check_name_usages(symbol_table)?; + } + + // This is going to get hairy, because users might attempt to use a field in an initializer + // (for either this field, or another one) before it's actually initialized. As such, we + // need a way to prevent lookup of current class' fields in the initializer. + // For now, the following is okay so long as we don't start referencing things in the + // initializers. + if let Some(initializer) = self.initializer.as_mut() { + initializer.check_name_usages(symbol_table)?; + } + Ok(()) + } } diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index f019fb2..4cc1f80 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -58,15 +58,15 @@ impl Function { ) -> Result<(), Vec> { let mut diagnostics = vec![]; + if !diagnostics.is_empty() { + return Err(diagnostics); + } + // insert function symbol let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new( self.declared_name(), self.declared_name_source_range.clone(), false, - self.return_type - .as_ref() - .map(|return_type| return_type.to_type_info()) - .unwrap_or(TypeInfo::Void), )); // get function symbol if successful @@ -109,6 +109,16 @@ impl Function { .borrow_mut() .set_parameters(parameter_symbols); + // return type + if let Some(type_use) = &mut self.return_type { + match type_use.gather_declared_names(symbol_table) { + Ok(_) => {} + Err(mut type_use_diagnostics) => { + diagnostics.append(&mut type_use_diagnostics); + } + } + } + symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name)); for statement in &mut self.statements { match statement.gather_declared_names(symbol_table) { @@ -142,6 +152,28 @@ impl Function { .collect(), ); + // return type + if let Some(type_use) = &mut self.return_type { + match type_use.check_name_usages(symbol_table) { + Ok(_) => { + // set return type info on function symbol + self.function_symbol + .as_mut() + .unwrap() + .borrow_mut() + .set_return_type_info(type_use.to_type_info()); + } + Err(mut type_use_diagnostics) => { + diagnostics.append(&mut type_use_diagnostics); + } + } + } else { + // we don't have a given return type, so it's void + self.function_symbol.as_mut().unwrap().borrow_mut().set_return_type_info( + TypeInfo::Void + ); + } + // statements for statement in &mut self.statements { match statement.check_name_usages(symbol_table) { diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index daf85ed..0a1614d 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -32,6 +32,7 @@ impl Parameter { &mut self, symbol_table: &mut SymbolTable, ) -> Result>, Vec> { + // insert parameter symbol let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( &self.declared_name, self.declared_name_source_range.clone(), @@ -40,26 +41,32 @@ impl Parameter { match insert_result { Ok(parameter_symbol) => { self.parameter_symbol = Some(parameter_symbol.clone()); - Ok(parameter_symbol) } - Err(symbol_insert_error) => match symbol_insert_error { - SymbolInsertError::AlreadyDeclared(already_declared) => Err(vec![Diagnostic::new( - &format!( - "Parameter {} already declared.", - already_declared.symbol().borrow().declared_name() - ), - self.declared_name_source_range.start(), - self.declared_name_source_range.end(), - )]), - }, + Err(symbol_insert_error) => { + return match symbol_insert_error { + SymbolInsertError::AlreadyDeclared(already_declared) => { + Err(vec![Diagnostic::new( + &format!( + "Parameter {} already declared.", + already_declared.symbol().borrow().declared_name() + ), + self.declared_name_source_range.start(), + self.declared_name_source_range.end(), + )]) + } + }; + } } + + // type use + self.type_use.gather_declared_names(symbol_table)?; + + Ok(self.parameter_symbol.clone().unwrap()) } - pub fn check_name_usages( - &mut self, - _symbol_table: &SymbolTable, - ) -> Result<(), Vec> { - Ok(()) // no-op for now + pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + self.type_use.check_name_usages(symbol_table)?; + Ok(()) } pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec> { diff --git a/dmc-lib/src/ast/type_use.rs b/dmc-lib/src/ast/type_use.rs index e72393a..b9d9d49 100644 --- a/dmc-lib/src/ast/type_use.rs +++ b/dmc-lib/src/ast/type_use.rs @@ -1,9 +1,14 @@ +use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; +use crate::symbol::type_symbol::{PrimitiveTypeSymbol, TypeSymbol}; +use crate::symbol_table::SymbolTable; use crate::type_info::TypeInfo; pub struct TypeUse { declared_name: String, declared_name_source_range: SourceRange, + scope_id: Option, + type_symbol: Option, } impl TypeUse { @@ -11,6 +16,8 @@ impl TypeUse { Self { declared_name: declared_name.into(), declared_name_source_range, + scope_id: None, + type_symbol: None, } } @@ -18,7 +25,47 @@ impl TypeUse { &self.declared_name } + pub fn gather_declared_names( + &mut self, + symbol_table: &mut SymbolTable, + ) -> Result<(), Vec> { + self.scope_id = Some(symbol_table.current_scope_id()); + Ok(()) + } + + pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec> { + let maybe_type_symbol = + symbol_table.find_type_symbol(self.scope_id.unwrap(), &self.declared_name); + if let Some(type_symbol) = maybe_type_symbol { + self.type_symbol = Some(type_symbol); + Ok(()) + } else if let Some(primitive_type_symbol) = + PrimitiveTypeSymbol::try_from_declared_name(self.declared_name()) + { + self.type_symbol = Some(TypeSymbol::Primitive(primitive_type_symbol)); + Ok(()) + } else { + Err(vec![ + Diagnostic::new( + &format!("Unable to resolve symbol {}", self.declared_name), + self.declared_name_source_range.start(), + self.declared_name_source_range.end(), + ) + .with_reporter(file!(), line!()), + ]) + } + } + pub fn to_type_info(&self) -> TypeInfo { - TypeInfo::from_declared_name(self.declared_name()) + match self.type_symbol.as_ref().unwrap() { + TypeSymbol::Class(class_symbol) => TypeInfo::Class(class_symbol.clone()), + TypeSymbol::Primitive(primitive_type) => match primitive_type { + PrimitiveTypeSymbol::Any => TypeInfo::Any, + PrimitiveTypeSymbol::Int => TypeInfo::Integer, + PrimitiveTypeSymbol::Double => TypeInfo::Double, + PrimitiveTypeSymbol::String => TypeInfo::String, + PrimitiveTypeSymbol::Void => TypeInfo::Void, + }, + } } } diff --git a/dmc-lib/src/symbol/function_symbol.rs b/dmc-lib/src/symbol/function_symbol.rs index f584403..74c7974 100644 --- a/dmc-lib/src/symbol/function_symbol.rs +++ b/dmc-lib/src/symbol/function_symbol.rs @@ -10,7 +10,7 @@ pub struct FunctionSymbol { declared_name_source_range: SourceRange, is_extern: bool, parameters: Option>>>, - return_type: TypeInfo, + return_type: Option, } impl FunctionSymbol { @@ -18,27 +18,16 @@ impl FunctionSymbol { declared_name: &str, declared_name_source_range: SourceRange, is_extern: bool, - return_type: TypeInfo, ) -> Self { Self { declared_name: declared_name.into(), declared_name_source_range, is_extern, parameters: None, - return_type, + return_type: None, } } - #[deprecated(note = "use declared_name")] - pub fn name(&self) -> &str { - &self.declared_name - } - - #[deprecated(note = "use declared_name_owned")] - pub fn name_owned(&self) -> Rc { - self.declared_name.clone() - } - pub fn set_parameters(&mut self, parameters: Vec>>) { self.parameters = Some(parameters); } @@ -47,8 +36,12 @@ impl FunctionSymbol { self.parameters.as_ref().unwrap() } + pub fn set_return_type_info(&mut self, return_type: TypeInfo) { + self.return_type = Some(return_type); + } + pub fn return_type_info(&self) -> &TypeInfo { - &self.return_type + self.return_type.as_ref().unwrap() } pub fn is_extern(&self) -> bool { diff --git a/dmc-lib/src/symbol/mod.rs b/dmc-lib/src/symbol/mod.rs index 2f16e74..88c0143 100644 --- a/dmc-lib/src/symbol/mod.rs +++ b/dmc-lib/src/symbol/mod.rs @@ -6,6 +6,7 @@ pub mod expressible_symbol; pub mod field_symbol; pub mod function_symbol; pub mod parameter_symbol; +pub mod type_symbol; pub mod variable_symbol; pub trait Symbol { diff --git a/dmc-lib/src/symbol/type_symbol.rs b/dmc-lib/src/symbol/type_symbol.rs new file mode 100644 index 0000000..5a0e59f --- /dev/null +++ b/dmc-lib/src/symbol/type_symbol.rs @@ -0,0 +1,29 @@ +use crate::symbol::class_symbol::ClassSymbol; +use std::cell::RefCell; +use std::rc::Rc; + +pub enum TypeSymbol { + Class(Rc>), + Primitive(PrimitiveTypeSymbol), +} + +pub enum PrimitiveTypeSymbol { + Any, + Int, + Double, + String, + Void, +} + +impl PrimitiveTypeSymbol { + pub fn try_from_declared_name(declared_name: &str) -> Option { + match declared_name { + "Any" => Some(PrimitiveTypeSymbol::Any), + "Int" => Some(PrimitiveTypeSymbol::Int), + "Double" => Some(PrimitiveTypeSymbol::Double), + "String" => Some(PrimitiveTypeSymbol::String), + "Void" => Some(PrimitiveTypeSymbol::Void), + _ => None, + } + } +} diff --git a/dmc-lib/src/symbol_table/helpers.rs b/dmc-lib/src/symbol_table/helpers.rs index 7378c01..86acbbe 100644 --- a/dmc-lib/src/symbol_table/helpers.rs +++ b/dmc-lib/src/symbol_table/helpers.rs @@ -5,6 +5,7 @@ use crate::scope::function_scope::FunctionScope; use crate::scope::module_scope::ModuleScope; use crate::symbol::Symbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; +use crate::symbol::type_symbol::TypeSymbol; use std::cell::RefCell; use std::rc::Rc; @@ -134,3 +135,25 @@ pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option find_expressible_in_block_by_name(block_scope, name), } } + +fn find_type_symbol_in_module(module_scope: &ModuleScope, name: &str) -> Option { + module_scope + .class_symbols() + .get(name) + .map(|symbol| TypeSymbol::Class(symbol.clone())) +} + +fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option { + class_scope + .class_symbols() + .get(name) + .map(|symbol| TypeSymbol::Class(symbol.clone())) +} + +pub fn find_type_symbol(scope: &Scope, name: &str) -> Option { + match scope { + Scope::Module(module_scope) => find_type_symbol_in_module(module_scope, name), + Scope::Class(class_scope) => find_type_symbol_in_class(class_scope, name), + _ => None, + } +} diff --git a/dmc-lib/src/symbol_table/mod.rs b/dmc-lib/src/symbol_table/mod.rs index f270650..b69f00b 100644 --- a/dmc-lib/src/symbol_table/mod.rs +++ b/dmc-lib/src/symbol_table/mod.rs @@ -6,13 +6,16 @@ use crate::scope::class_scope::ClassScope; use crate::scope::function_scope::FunctionScope; use crate::scope::module_scope::ModuleScope; use crate::symbol::Symbol; +use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; +use crate::symbol::field_symbol::FieldSymbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::symbol::type_symbol::TypeSymbol; use crate::symbol::variable_symbol::VariableSymbol; use crate::symbol_table::helpers::{ find_expressible_symbol, find_in_block_by_name, find_in_class_by_name, - find_in_function_by_name, find_in_module_by_name, + find_in_function_by_name, find_in_module_by_name, find_type_symbol, }; use std::cell::RefCell; use std::rc::Rc; @@ -84,6 +87,72 @@ impl SymbolTable { &mut self.scopes[self.current_scope_id.unwrap()] } + pub fn insert_class_symbol( + &mut self, + class_symbol: ClassSymbol, + ) -> Result>, SymbolInsertError> { + let maybe_already_inserted = match self.current_scope() { + Scope::Module(module_scope) => { + find_in_module_by_name(module_scope, class_symbol.declared_name()) + } + Scope::Class(class_scope) => { + find_in_class_by_name(class_scope, class_symbol.declared_name()) + } + _ => panic!("Attempt to insert ClassSymbol in incompatible scope"), + }; + + if let Some(already_inserted) = maybe_already_inserted { + return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( + already_inserted, + ))); + } + + let name = class_symbol.declared_name_owned(); + let as_rc = Rc::new(RefCell::new(class_symbol)); + let to_return = as_rc.clone(); + + match self.current_scope_mut() { + Scope::Module(module_scope) => { + module_scope.class_symbols_mut().insert(name, as_rc); + } + Scope::Class(class_scope) => { + class_scope.class_symbols_mut().insert(name, as_rc); + } + _ => unreachable!(), + } + Ok(to_return) + } + + pub fn insert_field_symbol( + &mut self, + field_symbol: FieldSymbol, + ) -> Result>, SymbolInsertError> { + let maybe_already_inserted = match self.current_scope() { + Scope::Class(class_scope) => { + find_in_class_by_name(class_scope, field_symbol.declared_name()) + } + _ => panic!("Attempt to insert FieldSymbol in incompatible scope"), + }; + + if let Some(already_inserted) = maybe_already_inserted { + return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new( + already_inserted, + ))); + } + + let name = field_symbol.declared_name_owned(); + let as_rc = Rc::new(RefCell::new(field_symbol)); + let to_return = as_rc.clone(); + + match self.current_scope_mut() { + Scope::Class(class_scope) => { + class_scope.field_symbols_mut().insert(name, as_rc); + } + _ => unreachable!(), + } + Ok(to_return) + } + pub fn insert_function_symbol( &mut self, function_symbol: FunctionSymbol, @@ -198,6 +267,22 @@ impl SymbolTable { None } + pub fn find_type_symbol(&self, scope_id: usize, name: &str) -> Option { + let mut maybe_scope = self.scopes.get(scope_id); + if maybe_scope.is_none() { + panic!("Invalid scope_id: {}", scope_id); + } + while let Some(scope) = maybe_scope { + let maybe_type_symbol = find_type_symbol(scope, name); + if maybe_type_symbol.is_some() { + return maybe_type_symbol; + } else { + maybe_scope = scope.parent_id().map(|id| &self.scopes[id]); + } + } + None + } + pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc> { match &self.scopes[scope_id] { Scope::Block(block_scope) => block_scope.variable_symbols().get(name).cloned().unwrap(), diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index 49d66fd..434aa01 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -1,3 +1,5 @@ +use crate::symbol::Symbol; +use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::function_symbol::FunctionSymbol; use std::cell::RefCell; use std::fmt::{Display, Formatter}; @@ -10,6 +12,7 @@ pub enum TypeInfo { Double, String, Function(Rc>), + Class(Rc>), Void, } @@ -27,6 +30,9 @@ impl Display for TypeInfo { } write!(f, ")") } + TypeInfo::Class(class_symbol) => { + write!(f, "{}", class_symbol.borrow().declared_name()) + } TypeInfo::Void => write!(f, "Void"), } } @@ -34,6 +40,7 @@ impl Display for TypeInfo { impl TypeInfo { // This is very naive but works for now + #[deprecated] pub fn from_declared_name(declared_name: &str) -> Self { match declared_name { "Any" => TypeInfo::Any, @@ -60,6 +67,15 @@ impl TypeInfo { TypeInfo::Function(_) => { unimplemented!("Type matching on Functions not yet supported.") } + TypeInfo::Class(class_symbol) => { + match other { + TypeInfo::Class(other_class_symbol) => { + class_symbol.borrow().declared_name() + == other_class_symbol.borrow().declared_name() // good enough for now + } + _ => false, + } + } TypeInfo::Void => { matches!(other, TypeInfo::Void) }