From d50cc24d0aa36e2d65b3dff746ffbb1f4bc67f48 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Mon, 4 May 2026 14:02:34 -0500 Subject: [PATCH] Work on constructor with new lowering api. WIP. --- dmc-lib/src/ast/constructor.rs | 145 ++++++++++++++++++++++++++++++++- dmc-lib/src/ast/field.rs | 4 + dmc-lib/src/parser.rs | 1 + dmc-lib/src/symbol/mod.rs | 14 ++++ 4 files changed, 163 insertions(+), 1 deletion(-) diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index 60b9f31..d41c676 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -1,4 +1,3 @@ -use crate::ast::NodesToSymbols; use crate::ast::field::Field; use crate::ast::fqn_context::FqnContext; use crate::ast::fqn_util::fqn_parts_to_string; @@ -8,6 +7,7 @@ use crate::ast::helpers::{ use crate::ast::ir_builder::IrBuilder; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; +use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes}; use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::ir::ir_allocate::IrAllocate; use crate::ir::ir_assign::IrAssign; @@ -34,6 +34,7 @@ use std::ops::Neg; use std::rc::Rc; pub struct Constructor { + node_id: NodeId, is_public: bool, ctor_keyword_source_range: SourceRange, parameters: Vec, @@ -43,12 +44,14 @@ pub struct Constructor { impl Constructor { pub fn new( + node_id: NodeId, is_public: bool, ctor_keyword_source_range: SourceRange, parameters: Vec, statements: Vec, ) -> Self { Self { + node_id, is_public, ctor_keyword_source_range, parameters, @@ -123,6 +126,7 @@ impl Constructor { (names_table, diagnostics) } + #[deprecated] pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec { let mut diagnostics: Vec = Vec::new(); for parameter in &self.parameters { @@ -131,6 +135,7 @@ impl Constructor { diagnostics } + #[deprecated] pub fn analyze_local_names( &self, symbol_table: &mut SymbolTable, @@ -142,12 +147,14 @@ impl Constructor { .collect() } + #[deprecated] pub fn gather_types_into(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) { for parameter in &self.parameters { parameter.gather_types_into(symbol_table, types_table); } } + #[deprecated] pub fn type_check( &mut self, symbol_table: &SymbolTable, @@ -180,6 +187,7 @@ impl Constructor { } } + #[deprecated] pub fn to_ir( &self, class_symbol: &Rc, @@ -315,4 +323,139 @@ impl Constructor { entry_block.clone(), ) } + + pub fn lower_to_ir( + &self, + class_symbol: &Rc, + fields: &[Field], + nodes_to_symbols: &NodesToSymbols, + symbols_to_types: &SymbolsToTypes, + nodes_to_types: &NodesToTypes, + ) -> IrFunction { + let mut ir_builder = IrBuilder::new(); + + // gather ir_parameters + let mut ir_parameters = Vec::new(); + let base_offset = (self.parameters.len() as isize).neg(); + for (i, parameter) in self.parameters.iter().enumerate() { + let symbol = nodes_to_symbols.get(¶meter.node_id()).unwrap(); + let parameter_type = symbols_to_types.get(symbol).unwrap(); + let offset = base_offset + i as isize; + let ir_parameter = Rc::new(IrParameter::new( + symbol.declared_name(), + parameter_type.clone(), + offset, + )); + + // save in builder + ir_builder.push_parameter(symbol.unwrap_parameter_symbol(), ir_parameter.clone()); + + // push for saving to IrFunction + ir_parameters.push(ir_parameter); + } + + // entry-block + let entry_block_id = ir_builder.new_block(); + + // PART 1: Make self object + let self_variable = Rc::new(RefCell::new(IrVariable::new_vr( + ir_builder.new_t_var().into(), + ir_builder.current_block().id(), + &TypeInfo::ParameterizedClass(class_symbol.clone(), Vec::new()), // todo: figure out the correct TypeInfo for this + ))); + + // save self variable in builder + ir_builder + .set_self_parameter_or_variable(IrParameterOrVariable::Variable(self_variable.clone())); + + // allocate the self object + let ir_assign = IrAssign::new( + self_variable.clone(), + IrOperation::Allocate(IrAllocate::new(class_symbol.declared_name_owned())), + ); + ir_builder + .current_block_mut() + .add_statement(IrStatement::Assign(ir_assign)); + + // PART 2: Initialize fields that are initialized OUTSIDE the constructor + for field in fields { + if let Some(initializer) = field.initializer() { + let symbol = nodes_to_symbols.get(&field.node_id()).unwrap(); + let field_type = symbols_to_types.get(symbol).unwrap(); + let field_symbol = symbol.unwrap_field_symbol(); + + // 1. Get a mut ref to the field + // mut t_var: Type = &mut self.x + let ir_get_field_ref_mut = IrGetFieldRefMut::new( + IrParameterOrVariable::Variable(self_variable.clone()), + field_symbol.field_index(), + ); + let field_ref_mut_ir_variable = Rc::new(RefCell::new(IrVariable::new_vr( + ir_builder.new_t_var().into(), + ir_builder.current_block().id(), + field_type, + ))); + let ir_assign = IrAssign::new( + field_ref_mut_ir_variable.clone(), + IrOperation::GetFieldRefMut(ir_get_field_ref_mut), + ); + ir_builder + .current_block_mut() + .add_statement(IrStatement::Assign(ir_assign)); + + // save the mut ref for later uses if needed + ir_builder.field_mut_pointer_variables_mut().insert( + field.declared_name_owned(), + field_ref_mut_ir_variable.clone(), + ); + + // 2. Evaluate initializer and save result to mut field ref + let ir_expression = initializer.lower_to_ir_expression( + &mut ir_builder, + nodes_to_symbols, + symbols_to_types, + nodes_to_types, + ); + let ir_set_field = IrSetField::new(&field_ref_mut_ir_variable, ir_expression); + ir_builder + .current_block_mut() + .add_statement(IrStatement::SetField(ir_set_field)); + } + } + + // PART 3. Constructor statements + for statement in &self.statements { + statement.lower( + &mut ir_builder, + nodes_to_symbols, + symbols_to_types, + nodes_to_types, + false, + ); + } + + // PART 4. Return finished self object + let ir_return_statement = IrStatement::Return(IrReturn::new(Some(IrExpression::Variable( + self_variable.clone(), + )))); + ir_builder + .current_block_mut() + .add_statement(ir_return_statement); + + // Finish up the builder and return IrFunction + ir_builder.finish_block(); + let entry_block = ir_builder.get_block(entry_block_id); + + let constructor_symbol = nodes_to_symbols + .get(&self.node_id) + .unwrap() + .unwrap_constructor_symbol(); + + IrFunction::new( + fqn_parts_to_string(constructor_symbol.fqn_parts()), + ir_parameters, + &TypeInfo::Class(class_symbol.clone()), // TODO + entry_block.clone(), + ) + } } diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index bb7fa9d..48b6709 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -45,6 +45,10 @@ impl Field { } } + pub fn node_id(&self) -> NodeId { + self.node_id + } + pub fn declared_name(&self) -> &str { &self.declared_name } diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index b0ad4c3..8581fcd 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -848,6 +848,7 @@ impl<'a> Parser<'a> { if let Some(ctor_keyword) = ctor_keyword { let constructor = Constructor::new( + self.next_node_id(), is_public, SourceRange::new(ctor_keyword.start(), ctor_keyword.end()), parameters, diff --git a/dmc-lib/src/symbol/mod.rs b/dmc-lib/src/symbol/mod.rs index f4d42fe..cfad8a4 100644 --- a/dmc-lib/src/symbol/mod.rs +++ b/dmc-lib/src/symbol/mod.rs @@ -131,4 +131,18 @@ impl Symbol { _ => panic!(), } } + + pub fn unwrap_parameter_symbol(&self) -> &Rc { + match self { + Symbol::Parameter(parameter_symbol) => parameter_symbol, + _ => panic!(), + } + } + + pub fn unwrap_constructor_symbol(&self) -> &Rc { + match self { + Symbol::Constructor(constructor_symbol) => constructor_symbol, + _ => panic!(), + } + } }