From 93eb5eb2043089bd3cd12a22874d6d8dc6d4e8c8 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Thu, 12 Mar 2026 15:55:15 -0500 Subject: [PATCH] Add ability to call constructors. --- dmc-lib/src/ast/call.rs | 13 ++++---- dmc-lib/src/ast/class.rs | 7 +++-- dmc-lib/src/ast/constructor.rs | 4 +-- dmc-lib/src/ast/type_use.rs | 2 +- dmc-lib/src/symbol/callable_symbol.rs | 38 ++++++++++++++++++++++++ dmc-lib/src/symbol/class_symbol.rs | 15 ++++++++++ dmc-lib/src/symbol/expressible_symbol.rs | 2 +- dmc-lib/src/symbol/mod.rs | 1 + dmc-lib/src/type_info.rs | 8 ++--- 9 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 dmc-lib/src/symbol/callable_symbol.rs diff --git a/dmc-lib/src/ast/call.rs b/dmc-lib/src/ast/call.rs index 076b483..4a452f3 100644 --- a/dmc-lib/src/ast/call.rs +++ b/dmc-lib/src/ast/call.rs @@ -5,6 +5,7 @@ use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::source_range::SourceRange; use crate::symbol::Symbol; +use crate::symbol::callable_symbol::CallableSymbol; use crate::symbol::expressible_symbol::ExpressibleSymbol; use crate::symbol::function_symbol::FunctionSymbol; use crate::symbol_table::SymbolTable; @@ -87,8 +88,11 @@ impl Call { .collect(); // check that callee is callable - let function_symbol = match self.callee.type_info() { - TypeInfo::Function(function_symbol) => function_symbol, + let callable_symbol = match self.callee.type_info() { + TypeInfo::Function(function_symbol) => { + CallableSymbol::Function(function_symbol.clone()) + } + TypeInfo::ClassInstance(class_symbol) => CallableSymbol::Class(class_symbol.clone()), _ => { diagnostics.push(Diagnostic::new( &format!( @@ -103,11 +107,10 @@ impl Call { }; // set return type - self.return_type_info = Some(function_symbol.borrow().return_type_info().clone()); + self.return_type_info = Some(callable_symbol.return_type_info()); // check arguments length - let function_symbol_ref = function_symbol.borrow(); - let parameters = function_symbol_ref.parameters(); + let parameters = callable_symbol.parameters(); if parameters.len() != self.arguments.len() { diagnostics.push(Diagnostic::new( &format!( diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index de14b46..6d76153 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -44,7 +44,7 @@ impl Class { false, ); - symbol_table + let class_symbol = symbol_table .insert_class_symbol(to_insert) .map_err(|e| match e { SymbolInsertError::AlreadyDeclared(already_declared) => { @@ -80,7 +80,10 @@ impl Class { // 4. gather constructor if let Some(constructor) = &mut self.constructor { - constructor.gather_declared_names(symbol_table)?; + let constructor_symbol = constructor.gather_declared_names(symbol_table)?; + class_symbol + .borrow_mut() + .set_constructor_symbol(Some(constructor_symbol)); } // 5. gather functions diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index 925f595..f4ba935 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -37,7 +37,7 @@ impl Constructor { pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, - ) -> Result<(), Vec> { + ) -> Result>, Vec> { // insert constructor symbol let to_insert = ConstructorSymbol::new(self.ctor_keyword_source_range.clone(), false); let constructor_symbol = @@ -95,7 +95,7 @@ impl Constructor { symbol_table.pop_scope(); // function if statements_diagnostics.is_empty() { - Ok(()) + Ok(constructor_symbol) } else { Err(statements_diagnostics) } diff --git a/dmc-lib/src/ast/type_use.rs b/dmc-lib/src/ast/type_use.rs index 8f049c7..5588f95 100644 --- a/dmc-lib/src/ast/type_use.rs +++ b/dmc-lib/src/ast/type_use.rs @@ -62,7 +62,7 @@ impl TypeUse { pub fn to_type_info(&self) -> TypeInfo { match self.type_symbol.as_ref().unwrap() { - TypeSymbol::Class(class_symbol) => TypeInfo::Class(class_symbol.clone()), + TypeSymbol::Class(class_symbol) => TypeInfo::ClassInstance(class_symbol.clone()), TypeSymbol::Primitive(primitive_type) => match primitive_type { PrimitiveTypeSymbol::Any => TypeInfo::Any, PrimitiveTypeSymbol::Int => TypeInfo::Integer, diff --git a/dmc-lib/src/symbol/callable_symbol.rs b/dmc-lib/src/symbol/callable_symbol.rs new file mode 100644 index 0000000..458af71 --- /dev/null +++ b/dmc-lib/src/symbol/callable_symbol.rs @@ -0,0 +1,38 @@ +use crate::symbol::class_symbol::ClassSymbol; +use crate::symbol::function_symbol::FunctionSymbol; +use crate::symbol::parameter_symbol::ParameterSymbol; +use crate::type_info::TypeInfo; +use std::cell::RefCell; +use std::rc::Rc; + +pub enum CallableSymbol { + Function(Rc>), + Class(Rc>), +} + +impl CallableSymbol { + pub fn return_type_info(&self) -> TypeInfo { + match self { + CallableSymbol::Function(function) => function.borrow().return_type_info().clone(), + CallableSymbol::Class(class_symbol) => { + // At the language level, constructors "return" an instance of their type + TypeInfo::ClassInstance(class_symbol.clone()) + } + } + } + + pub fn parameters(&self) -> Vec>> { + match self { + CallableSymbol::Function(function_symbol) => { + function_symbol.borrow().parameters().to_vec() + } + CallableSymbol::Class(class_symbol) => { + if let Some(constructor_symbol) = class_symbol.borrow().constructor_symbol() { + constructor_symbol.borrow().parameters().to_vec() + } else { + vec![] + } + } + } + } +} diff --git a/dmc-lib/src/symbol/class_symbol.rs b/dmc-lib/src/symbol/class_symbol.rs index c25181a..6eb5929 100644 --- a/dmc-lib/src/symbol/class_symbol.rs +++ b/dmc-lib/src/symbol/class_symbol.rs @@ -1,5 +1,6 @@ use crate::source_range::SourceRange; use crate::symbol::Symbol; +use crate::symbol::constructor_symbol::ConstructorSymbol; use crate::symbol::field_symbol::FieldSymbol; use crate::symbol::function_symbol::FunctionSymbol; use std::cell::RefCell; @@ -10,6 +11,7 @@ pub struct ClassSymbol { declared_name: Rc, declared_name_source_range: SourceRange, is_extern: bool, + constructor_symbol: Option>>, fields: HashMap, Rc>>, functions: HashMap, Rc>>, } @@ -24,10 +26,23 @@ impl ClassSymbol { declared_name: declared_name.clone(), declared_name_source_range, is_extern, + constructor_symbol: None, fields: HashMap::new(), functions: HashMap::new(), } } + + pub fn set_constructor_symbol( + &mut self, + constructor_symbol: Option>>, + ) { + self.constructor_symbol = constructor_symbol; + } + + /// A value of `None` indicates that there is no declared constructor for this class. + pub fn constructor_symbol(&self) -> Option<&Rc>> { + self.constructor_symbol.as_ref() + } } impl Symbol for ClassSymbol { diff --git a/dmc-lib/src/symbol/expressible_symbol.rs b/dmc-lib/src/symbol/expressible_symbol.rs index ef47076..53e0bc9 100644 --- a/dmc-lib/src/symbol/expressible_symbol.rs +++ b/dmc-lib/src/symbol/expressible_symbol.rs @@ -19,7 +19,7 @@ pub enum ExpressibleSymbol { impl ExpressibleSymbol { pub fn type_info(&self) -> TypeInfo { match self { - ExpressibleSymbol::Class(class_symbol) => TypeInfo::Class(class_symbol.clone()), + ExpressibleSymbol::Class(class_symbol) => TypeInfo::ClassInstance(class_symbol.clone()), ExpressibleSymbol::Field(field_symbol) => field_symbol.borrow().type_info().clone(), ExpressibleSymbol::Function(function_symbol) => { TypeInfo::Function(function_symbol.clone()) // n.b. not the return type! diff --git a/dmc-lib/src/symbol/mod.rs b/dmc-lib/src/symbol/mod.rs index 83dcdf4..cb8b1dc 100644 --- a/dmc-lib/src/symbol/mod.rs +++ b/dmc-lib/src/symbol/mod.rs @@ -1,6 +1,7 @@ use crate::source_range::SourceRange; use std::rc::Rc; +pub mod callable_symbol; pub mod class_symbol; pub mod constructor_symbol; pub mod expressible_symbol; diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index 434aa01..39b3686 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -12,7 +12,7 @@ pub enum TypeInfo { Double, String, Function(Rc>), - Class(Rc>), + ClassInstance(Rc>), Void, } @@ -30,7 +30,7 @@ impl Display for TypeInfo { } write!(f, ")") } - TypeInfo::Class(class_symbol) => { + TypeInfo::ClassInstance(class_symbol) => { write!(f, "{}", class_symbol.borrow().declared_name()) } TypeInfo::Void => write!(f, "Void"), @@ -67,9 +67,9 @@ impl TypeInfo { TypeInfo::Function(_) => { unimplemented!("Type matching on Functions not yet supported.") } - TypeInfo::Class(class_symbol) => { + TypeInfo::ClassInstance(class_symbol) => { match other { - TypeInfo::Class(other_class_symbol) => { + TypeInfo::ClassInstance(other_class_symbol) => { class_symbol.borrow().declared_name() == other_class_symbol.borrow().declared_name() // good enough for now }