From 320cdcf80594f4d1f3e63e7be0655f85fdccf67a Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Thu, 12 Mar 2026 21:52:21 -0500 Subject: [PATCH] Compiling fields getters/setters. --- dm/src/repl.rs | 17 +--- dmc-lib/src/ast/class.rs | 40 +++++++++- dmc-lib/src/ast/compilation_unit.rs | 8 +- dmc-lib/src/ast/constructor.rs | 82 ++++++++++++++++++++ dmc-lib/src/ast/field.rs | 12 +++ dmc-lib/src/ast/function.rs | 6 +- dmc-lib/src/ast/negative_expression.rs | 3 + dmc-lib/src/ir/ir_allocate.rs | 26 +++++++ dmc-lib/src/ir/ir_assign.rs | 4 + dmc-lib/src/ir/ir_expression.rs | 76 +++++++++++++++--- dmc-lib/src/ir/ir_function.rs | 12 ++- dmc-lib/src/ir/ir_operation.rs | 9 +++ dmc-lib/src/ir/ir_set_field.rs | 98 ++++++++++++++++++++++++ dmc-lib/src/ir/ir_statement.rs | 19 +++++ dmc-lib/src/ir/ir_variable.rs | 15 ++++ dmc-lib/src/ir/mod.rs | 3 + dmc-lib/src/ir/util.rs | 22 ++++++ dmc-lib/src/symbol/class_symbol.rs | 4 + dmc-lib/src/symbol/expressible_symbol.rs | 2 + dmc-lib/src/symbol/field_symbol.rs | 10 +++ dvm-lib/src/instruction.rs | 41 ++++++++++ dvm-lib/src/vm/mod.rs | 23 ++++++ 22 files changed, 494 insertions(+), 38 deletions(-) create mode 100644 dmc-lib/src/ir/ir_allocate.rs create mode 100644 dmc-lib/src/ir/ir_set_field.rs create mode 100644 dmc-lib/src/ir/util.rs diff --git a/dm/src/repl.rs b/dm/src/repl.rs index a3918b4..0c134d6 100644 --- a/dm/src/repl.rs +++ b/dm/src/repl.rs @@ -6,18 +6,14 @@ use dmc_lib::ir::ir_return::IrReturn; use dmc_lib::ir::ir_statement::IrStatement; use dmc_lib::lexer::Lexer; use dmc_lib::parser::parse_expression; -use dmc_lib::source_range::SourceRange; -use dmc_lib::symbol::function_symbol::FunctionSymbol; use dmc_lib::symbol_table::SymbolTable; use dmc_lib::token::TokenKind; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; use dvm_lib::vm::value::Value; use dvm_lib::vm::{CallStack, DvmContext, call}; -use std::cell::RefCell; use std::io; use std::io::Write; -use std::rc::Rc; pub fn repl(register_count: usize) { let mut buffer = String::new(); @@ -128,19 +124,8 @@ fn compile_expression( ir_builder.finish_block(); let entry_block = ir_builder.get_block(entry_block_id); - // synthesize symbol - let fake_function_symbol = Rc::new(RefCell::new(FunctionSymbol::new( - "__repl", - SourceRange::new(0, 0), - false, - ))); - - fake_function_symbol - .borrow_mut() - .set_return_type_info(expression.type_info().clone()); - let mut ir_function = IrFunction::new( - fake_function_symbol, + "__repl".into(), &[], expression.type_info(), entry_block.clone(), diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index b970d11..e4c17ff 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -2,9 +2,11 @@ use crate::ast::constructor::Constructor; use crate::ast::field::Field; use crate::ast::function::Function; use crate::diagnostic::{Diagnostic, SecondaryLabel}; +use crate::ir::ir_function::IrFunction; use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; +use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; @@ -14,6 +16,7 @@ pub struct Class { constructor: Option, fields: Vec, functions: Vec, + class_symbol: Option>>, } impl Class { @@ -30,6 +33,7 @@ impl Class { constructor, fields, functions, + class_symbol: None, } } @@ -68,6 +72,9 @@ impl Class { } })?; + // save symbol for later + self.class_symbol = Some(class_symbol); + // 2. push scope symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name)); @@ -75,7 +82,8 @@ impl Class { let fields_diagnostics: Vec = self .fields .iter_mut() - .map(|field| field.gather_declared_names(symbol_table)) + .enumerate() + .map(|(field_index, field)| field.gather_declared_names(symbol_table, field_index)) .filter_map(Result::err) .flatten() .collect(); @@ -87,7 +95,9 @@ impl Class { // 4. gather constructor if let Some(constructor) = &mut self.constructor { let constructor_symbol = constructor.gather_declared_names(symbol_table)?; - class_symbol + self.class_symbol + .as_mut() + .unwrap() .borrow_mut() .set_constructor_symbol(Some(constructor_symbol)); } @@ -231,11 +241,29 @@ impl Class { Err(diagnostics) } } + + pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec { + let mut ir_functions: Vec = vec![]; + if let Some(constructor) = &self.constructor { + ir_functions.push(constructor.to_ir( + self.class_symbol.as_ref().unwrap(), + &self.fields, + symbol_table, + )) + } + + for function in &self.functions { + ir_functions.push(function.to_ir(symbol_table)); + } + + ir_functions + } } #[cfg(test)] mod tests { use super::*; + use crate::constants_table::ConstantsTable; use crate::parser::parse_compilation_unit; #[test] @@ -289,5 +317,13 @@ mod tests { panic!("{:?}", diagnostics); } } + + let mut ir_functions = compilation_unit.to_ir(&symbol_table); + let mut constants_table = ConstantsTable::new(); + for ir_function in &mut ir_functions { + let (_, stack_size) = ir_function.assign_registers(8); + let vm_function = ir_function.assemble(stack_size, &mut constants_table); + println!("{}", vm_function) + } } } diff --git a/dmc-lib/src/ast/compilation_unit.rs b/dmc-lib/src/ast/compilation_unit.rs index f3011c7..ed30e21 100644 --- a/dmc-lib/src/ast/compilation_unit.rs +++ b/dmc-lib/src/ast/compilation_unit.rs @@ -136,9 +136,15 @@ impl CompilationUnit { } pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec { + let mut functions: Vec = vec![]; self.functions .iter() .map(|f| f.to_ir(symbol_table)) - .collect() + .for_each(|f| functions.push(f)); + self.classes + .iter() + .flat_map(|c| c.to_ir(symbol_table)) + .for_each(|f| functions.push(f)); + functions } } diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index f4ba935..7daf92c 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -1,11 +1,26 @@ +use crate::ast::field::Field; +use crate::ast::ir_builder::IrBuilder; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; use crate::diagnostic::Diagnostic; +use crate::ir::ir_allocate::IrAllocate; +use crate::ir::ir_assign::IrAssign; +use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_function::IrFunction; +use crate::ir::ir_operation::IrOperation; +use crate::ir::ir_parameter::IrParameter; +use crate::ir::ir_set_field::IrSetField; +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::constructor_symbol::ConstructorSymbol; use crate::symbol::parameter_symbol::ParameterSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; +use crate::type_info::TypeInfo; use std::cell::RefCell; +use std::ops::Neg; use std::rc::Rc; pub struct Constructor { @@ -156,4 +171,71 @@ impl Constructor { Err(statements_diagnostics) } } + + pub fn to_ir( + &self, + class_symbol: &Rc>, + fields: &[Field], + symbol_table: &SymbolTable, + ) -> IrFunction { + let mut ir_builder = IrBuilder::new(); + + let parameters_count = self.parameters.len(); + let ir_parameters = self + .parameters + .iter() + .enumerate() + .map(|(i, parameter)| { + let parameter_symbol = parameter.parameter_symbol().borrow(); + let offset = (parameters_count as isize).neg() + i as isize; + Rc::new(IrParameter::new( + parameter_symbol.declared_name(), + parameter_symbol.type_info().clone(), + offset, + )) + }) + .collect::>(); + + let entry_block_id = ir_builder.new_block(); + + // first, allocate the object into a t var + let alloc_assign_destination = IrVariable::new_vr( + ir_builder.new_t_var().into(), + ir_builder.current_block().id(), + &TypeInfo::ClassInstance(class_symbol.clone()), + ); + let self_variable = Rc::new(RefCell::new(alloc_assign_destination)); + let alloc_assign = IrAssign::new( + self_variable.clone(), + IrOperation::Allocate(IrAllocate::new(class_symbol.borrow().declared_name_owned())), + ); + ir_builder + .current_block_mut() + .add_statement(IrStatement::Assign(alloc_assign)); + + // next, initialize fields that have an initializer in their declaration + for field in fields { + if let Some(initializer) = field.initializer() { + let ir_expression = initializer.to_ir(&mut ir_builder, symbol_table).unwrap(); + let ir_set_field = IrSetField::new( + &self_variable.clone(), + field.field_symbol().borrow().field_index(), + ir_expression, + ); + ir_builder + .current_block_mut() + .add_statement(IrStatement::SetField(ir_set_field)); + } + } + + ir_builder.finish_block(); + let entry_block = ir_builder.get_block(entry_block_id); + + IrFunction::new( + format!("{}::ctor", class_symbol.borrow().declared_name()).into(), // fake function symbol + &ir_parameters, // make params + &TypeInfo::ClassInstance(class_symbol.clone()), + entry_block.clone(), + ) + } } diff --git a/dmc-lib/src/ast/field.rs b/dmc-lib/src/ast/field.rs index 0e1b6bd..357850e 100644 --- a/dmc-lib/src/ast/field.rs +++ b/dmc-lib/src/ast/field.rs @@ -52,6 +52,7 @@ impl Field { pub fn gather_declared_names( &mut self, symbol_table: &mut SymbolTable, + field_index: usize, ) -> Result<(), Vec> { // 1. insert field symbol let to_insert = @@ -75,6 +76,13 @@ impl Field { // save for later self.field_symbol = Some(field_symbol); + // set field index on symbol + self.field_symbol + .as_ref() + .unwrap() + .borrow_mut() + .set_field_index(field_index); + // 2. gather type_use and initializer, if present if let Some(type_use) = &mut self.declared_type { type_use.gather_declared_names(symbol_table)?; @@ -181,4 +189,8 @@ impl Field { Err(diagnostics) } } + + pub fn field_symbol(&self) -> &Rc> { + self.field_symbol.as_ref().unwrap() + } } diff --git a/dmc-lib/src/ast/function.rs b/dmc-lib/src/ast/function.rs index 764ccae..94b2ac2 100644 --- a/dmc-lib/src/ast/function.rs +++ b/dmc-lib/src/ast/function.rs @@ -269,7 +269,11 @@ impl Function { let entry_block = builder.get_block(entry_block_id).clone(); IrFunction::new( - self.function_symbol.as_ref().unwrap().clone(), + self.function_symbol + .as_ref() + .unwrap() + .borrow() + .declared_name_owned(), // ok for now... but we need to start using the fqn builder.parameters(), return_type_info, entry_block, diff --git a/dmc-lib/src/ast/negative_expression.rs b/dmc-lib/src/ast/negative_expression.rs index 4aaa0ef..c87353b 100644 --- a/dmc-lib/src/ast/negative_expression.rs +++ b/dmc-lib/src/ast/negative_expression.rs @@ -74,6 +74,9 @@ impl NegativeExpression { .expect("Attempt to negate non-value expression"); match operand_as_ir { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(parameter) => { let destination = Rc::new(RefCell::new(IrVariable::new_vr( builder.new_t_var().into(), diff --git a/dmc-lib/src/ir/ir_allocate.rs b/dmc-lib/src/ir/ir_allocate.rs new file mode 100644 index 0000000..0d91666 --- /dev/null +++ b/dmc-lib/src/ir/ir_allocate.rs @@ -0,0 +1,26 @@ +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +pub struct IrAllocate { + class_fqn: Rc, +} + +impl IrAllocate { + pub fn new(class_fqn: Rc) -> Self { + Self { class_fqn } + } + + pub fn class_fqn(&self) -> &str { + &self.class_fqn + } + + pub fn class_fqn_owned(&self) -> Rc { + self.class_fqn.clone() + } +} + +impl Display for IrAllocate { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "alloc {}", self.class_fqn) + } +} diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index 9591fa7..9285cdf 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -109,6 +109,10 @@ impl Assemble for IrAssign { ir_call.assemble(builder, constants_table); builder.push(Instruction::Pop(Some(destination))); } + IrOperation::Allocate(ir_allocate) => builder.push(Instruction::Allocate( + ir_allocate.class_fqn_owned(), + destination, + )), } } } diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index c9252da..ab87b95 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -6,7 +6,8 @@ use crate::ir::ir_variable::{ use crate::ir::register_allocation::{OffsetCounter, VrUser}; use crate::type_info::TypeInfo; use dvm_lib::instruction::{ - AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand, + AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, + SetFieldOperand, SubtractOperand, }; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; @@ -14,6 +15,7 @@ use std::fmt::{Display, Formatter}; use std::rc::Rc; pub enum IrExpression { + Field(Rc>, usize), Parameter(Rc), Variable(Rc>), Int(i32), @@ -22,18 +24,11 @@ pub enum IrExpression { } impl IrExpression { - pub fn type_info(&self) -> TypeInfo { - match self { - IrExpression::Parameter(ir_parameter) => ir_parameter.type_info().clone(), - IrExpression::Variable(ir_variable) => ir_variable.borrow().type_info().clone(), - IrExpression::Int(_) => TypeInfo::Integer, - IrExpression::Double(_) => TypeInfo::Double, - IrExpression::String(_) => TypeInfo::String, - } - } - pub fn move_operand(&self, constants_table: &mut ConstantsTable) -> MoveOperand { match self { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(ir_parameter) => { MoveOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -56,6 +51,9 @@ impl IrExpression { pub fn push_operand(&self, constants_table: &mut ConstantsTable) -> PushOperand { match self { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(ir_parameter) => { PushOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -78,6 +76,9 @@ impl IrExpression { pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand { match self { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() { TypeInfo::Integer | TypeInfo::Double | TypeInfo::String => { AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) @@ -116,6 +117,9 @@ impl IrExpression { pub fn subtract_operand(&self) -> SubtractOperand { match self { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() { TypeInfo::Integer | TypeInfo::Double => SubtractOperand::Location( Location::StackFrameOffset(ir_parameter.stack_offset()), @@ -151,6 +155,9 @@ impl IrExpression { pub fn multiply_operand(&self) -> MultiplyOperand { match self { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(ir_parameter) => { MultiplyOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -172,6 +179,9 @@ impl IrExpression { pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand { match self { + IrExpression::Field(self_variable, _) => { + todo!() + } IrExpression::Parameter(ir_parameter) => { ReturnOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -193,11 +203,39 @@ impl IrExpression { } } } + + pub fn set_field_operand(&self, constants_table: &mut ConstantsTable) -> SetFieldOperand { + match self { + IrExpression::Field(self_variable, _) => { + todo!() + } + IrExpression::Parameter(ir_parameter) => { + SetFieldOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) + } + IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + SetFieldOperand::Location(Location::Register(vr_variable.assigned_register())) + } + IrVariableDescriptor::Stack(stack_variable) => { + SetFieldOperand::Location(Location::StackFrameOffset(stack_variable.offset())) + } + }, + IrExpression::Int(i) => SetFieldOperand::Int(*i), + IrExpression::Double(d) => SetFieldOperand::Double(*d), + IrExpression::String(s) => { + let constant_name = constants_table.get_or_insert(s); + SetFieldOperand::String(constant_name) + } + } + } } impl Display for IrExpression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { + IrExpression::Field(self_variable, field_index) => { + write!(f, "{}.{}", self_variable.borrow(), field_index) + } IrExpression::Parameter(ir_parameter) => { write!(f, "{}", ir_parameter) } @@ -219,11 +257,21 @@ impl Display for IrExpression { impl VrUser for IrExpression { fn vr_definitions(&self) -> HashSet { + // no defs for an expression HashSet::new() } fn vr_uses(&self) -> HashSet { match self { + IrExpression::Field(self_variable, field_index) => { + if let IrVariableDescriptor::VirtualRegister(vr_variable) = + self_variable.borrow().descriptor() + { + HashSet::from([vr_variable.clone()]) + } else { + HashSet::new() + } + } IrExpression::Parameter(_) => HashSet::new(), IrExpression::Variable(ir_variable) => { if let IrVariableDescriptor::VirtualRegister(vr_variable) = @@ -242,6 +290,9 @@ impl VrUser for IrExpression { fn propagate_spills(&mut self, spills: &HashSet) { match self { + IrExpression::Field(self_variable, field_index) => { + // no-op, no defs + } IrExpression::Parameter(_) => { // no-op } @@ -278,6 +329,9 @@ impl VrUser for IrExpression { assignments: &HashMap, ) { match self { + IrExpression::Field(self_variable, field_index) => { + // no-op + } IrExpression::Parameter(_) => { // no-op } diff --git a/dmc-lib/src/ir/ir_function.rs b/dmc-lib/src/ir/ir_function.rs index b183c9b..abb5d77 100644 --- a/dmc-lib/src/ir/ir_function.rs +++ b/dmc-lib/src/ir/ir_function.rs @@ -4,8 +4,6 @@ use crate::ir::ir_block::IrBlock; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::HasVrUsers; -use crate::symbol::Symbol; -use crate::symbol::function_symbol::FunctionSymbol; use crate::type_info::TypeInfo; use dvm_lib::vm::function::Function; use std::cell::RefCell; @@ -14,7 +12,7 @@ use std::fmt::Display; use std::rc::Rc; pub struct IrFunction { - function_symbol: Rc>, + fqn: Rc, parameters: Vec>, return_type_info: TypeInfo, entry: Rc>, @@ -22,13 +20,13 @@ pub struct IrFunction { impl IrFunction { pub fn new( - function_symbol: Rc>, + fqn: Rc, parameters: &[Rc], return_type_info: &TypeInfo, entry: Rc>, ) -> Self { Self { - function_symbol, + fqn, parameters: parameters.to_vec(), return_type_info: return_type_info.clone(), entry, @@ -47,7 +45,7 @@ impl IrFunction { self.entry.borrow().assemble(&mut builder, constants_table); let instructions = builder.take_instructions(); Function::new( - self.function_symbol.borrow().declared_name_owned(), + self.fqn.clone(), self.parameters.len(), stack_size, instructions, @@ -57,7 +55,7 @@ impl IrFunction { impl Display for IrFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "fn {}(", self.function_symbol.borrow().declared_name())?; + write!(f, "fn {}(", self.fqn)?; for (i, parameter) in self.parameters.iter().enumerate() { write!(f, "{}: {}", parameter, parameter.type_info())?; if i < self.parameters.len() - 1 { diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index 106ce26..ac8cd93 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -1,4 +1,5 @@ use crate::ir::ir_add::IrAdd; +use crate::ir::ir_allocate::IrAllocate; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_multiply::IrMultiply; @@ -14,6 +15,7 @@ pub enum IrOperation { Subtract(IrSubtract), Multiply(IrMultiply), Call(IrCall), + Allocate(IrAllocate), } impl Display for IrOperation { @@ -34,6 +36,9 @@ impl Display for IrOperation { IrOperation::Call(ir_call) => { write!(f, "{}", ir_call) } + IrOperation::Allocate(ir_allocate) => { + write!(f, "{}", ir_allocate) + } } } } @@ -46,6 +51,7 @@ impl VrUser for IrOperation { IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(), IrOperation::Multiply(ir_multiply) => ir_multiply.vr_definitions(), IrOperation::Call(ir_call) => ir_call.vr_definitions(), + IrOperation::Allocate(_) => HashSet::new(), } } @@ -56,6 +62,7 @@ impl VrUser for IrOperation { IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(), IrOperation::Multiply(ir_multiply) => ir_multiply.vr_uses(), IrOperation::Call(ir_call) => ir_call.vr_uses(), + IrOperation::Allocate(_) => HashSet::new(), } } @@ -76,6 +83,7 @@ impl VrUser for IrOperation { IrOperation::Call(ir_call) => { ir_call.propagate_spills(spills); } + IrOperation::Allocate(_) => (), } } @@ -99,6 +107,7 @@ impl VrUser for IrOperation { IrOperation::Call(ir_call) => { ir_call.propagate_register_assignments(assignments); } + IrOperation::Allocate(_) => (), } } diff --git a/dmc-lib/src/ir/ir_set_field.rs b/dmc-lib/src/ir/ir_set_field.rs new file mode 100644 index 0000000..de0a9ec --- /dev/null +++ b/dmc-lib/src/ir/ir_set_field.rs @@ -0,0 +1,98 @@ +use crate::constants_table::ConstantsTable; +use crate::ir::assemble::{Assemble, InstructionsBuilder}; +use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; +use crate::ir::util::propagate_spills; +use dvm_lib::instruction::{Instruction, Location}; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +pub struct IrSetField { + target_object: Rc>, + field_index: usize, + initializer: Box, +} + +impl IrSetField { + pub fn new( + target_object: &Rc>, + field_index: usize, + initializer: IrExpression, + ) -> Self { + Self { + target_object: target_object.clone(), + field_index, + initializer: initializer.into(), + } + } +} + +impl VrUser for IrSetField { + fn vr_definitions(&self) -> HashSet { + // only this, because the target_object is technically not a definition + self.initializer.vr_definitions() + } + + fn vr_uses(&self) -> HashSet { + let mut set = HashSet::new(); + match self.target_object.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + set.insert(vr_variable.clone()); + } + IrVariableDescriptor::Stack(_) => {} + } + set.extend(self.initializer.vr_uses()); + set + } + + fn propagate_spills(&mut self, spills: &HashSet) { + propagate_spills(&mut self.target_object, spills); + self.initializer.propagate_spills(spills); + } + + fn propagate_register_assignments( + &mut self, + _assignments: &HashMap, + ) { + // no definitions + } + + fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) { + // no definitions + } +} + +impl Assemble for IrSetField { + fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { + let destination = match self.target_object.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + Location::Register(vr_variable.assigned_register()) + } + IrVariableDescriptor::Stack(stack_variable) => { + Location::StackFrameOffset(stack_variable.offset()) + } + }; + + let set_field_operand = self.initializer.set_field_operand(constants_table); + builder.push(Instruction::SetField( + destination, + self.field_index, + set_field_operand, + )); + } +} + +impl Display for IrSetField { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}.{} = {}", + self.target_object.borrow(), + self.field_index, + self.initializer + ) + } +} diff --git a/dmc-lib/src/ir/ir_statement.rs b/dmc-lib/src/ir/ir_statement.rs index 55dd94c..8c222ef 100644 --- a/dmc-lib/src/ir/ir_statement.rs +++ b/dmc-lib/src/ir/ir_statement.rs @@ -3,6 +3,7 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_call::IrCall; use crate::ir::ir_return::IrReturn; +use crate::ir::ir_set_field::IrSetField; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::{OffsetCounter, VrUser}; use std::collections::{HashMap, HashSet}; @@ -12,6 +13,7 @@ pub enum IrStatement { Assign(IrAssign), Call(IrCall), Return(IrReturn), + SetField(IrSetField), } impl VrUser for IrStatement { @@ -20,6 +22,7 @@ impl VrUser for IrStatement { IrStatement::Assign(ir_assign) => ir_assign.vr_definitions(), IrStatement::Call(ir_call) => ir_call.vr_definitions(), IrStatement::Return(ir_return) => ir_return.vr_definitions(), + IrStatement::SetField(ir_set_field) => ir_set_field.vr_definitions(), } } @@ -28,6 +31,7 @@ impl VrUser for IrStatement { IrStatement::Assign(ir_assign) => ir_assign.vr_uses(), IrStatement::Call(ir_call) => ir_call.vr_uses(), IrStatement::Return(ir_return) => ir_return.vr_uses(), + IrStatement::SetField(ir_set_field) => ir_set_field.vr_uses(), } } @@ -42,6 +46,9 @@ impl VrUser for IrStatement { IrStatement::Return(ir_return) => { ir_return.propagate_spills(spills); } + IrStatement::SetField(ir_set_field) => { + ir_set_field.propagate_spills(spills); + } } } @@ -59,6 +66,9 @@ impl VrUser for IrStatement { IrStatement::Return(ir_return) => { ir_return.propagate_register_assignments(assignments); } + IrStatement::SetField(ir_set_field) => { + ir_set_field.propagate_register_assignments(assignments); + } } } @@ -73,6 +83,9 @@ impl VrUser for IrStatement { IrStatement::Return(ir_return) => { ir_return.propagate_stack_offsets(counter); } + IrStatement::SetField(ir_set_field) => { + ir_set_field.propagate_stack_offsets(counter); + } } } } @@ -89,6 +102,9 @@ impl Assemble for IrStatement { IrStatement::Return(ir_return) => { ir_return.assemble(builder, constants_table); } + IrStatement::SetField(ir_set_field) => { + ir_set_field.assemble(builder, constants_table); + } } } } @@ -105,6 +121,9 @@ impl Display for IrStatement { IrStatement::Return(ir_return) => { write!(f, "{}", ir_return) } + IrStatement::SetField(ir_set_field) => { + write!(f, "{}", ir_set_field) + } } } } diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index 40dce53..63b49b3 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -73,6 +73,13 @@ impl IrVariableDescriptor { IrVariableDescriptor::Stack(stack_variable) => stack_variable.name(), } } + + pub fn name_owned(&self) -> Rc { + match self { + IrVariableDescriptor::VirtualRegister(vr_variable) => vr_variable.name_owned(), + IrVariableDescriptor::Stack(stack_variable) => stack_variable.name_owned(), + } + } } #[derive(Clone, Hash, PartialEq, Eq)] @@ -95,6 +102,10 @@ impl IrVrVariableDescriptor { &self.name } + pub fn name_owned(&self) -> Rc { + self.name.clone() + } + pub fn block_id(&self) -> usize { self.block_id } @@ -139,6 +150,10 @@ impl IrStackVariableDescriptor { &self.name } + pub fn name_owned(&self) -> Rc { + self.name.clone() + } + pub fn set_offset(&mut self, offset: isize) { self.offset = Some(offset); } diff --git a/dmc-lib/src/ir/mod.rs b/dmc-lib/src/ir/mod.rs index c2771f8..e8b120a 100644 --- a/dmc-lib/src/ir/mod.rs +++ b/dmc-lib/src/ir/mod.rs @@ -1,5 +1,6 @@ mod assemble; pub mod ir_add; +pub mod ir_allocate; pub mod ir_assign; pub mod ir_block; pub mod ir_call; @@ -9,7 +10,9 @@ pub mod ir_multiply; pub mod ir_operation; pub mod ir_parameter; pub mod ir_return; +pub mod ir_set_field; pub mod ir_statement; pub mod ir_subtract; pub mod ir_variable; mod register_allocation; +mod util; diff --git a/dmc-lib/src/ir/util.rs b/dmc-lib/src/ir/util.rs new file mode 100644 index 0000000..eb8cde9 --- /dev/null +++ b/dmc-lib/src/ir/util.rs @@ -0,0 +1,22 @@ +use crate::ir::ir_variable::{ + IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor, +}; +use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; + +pub fn propagate_spills( + ir_variable: &mut Rc>, + spills: &HashSet, +) { + let mut borrowed_ir_variable = ir_variable.borrow_mut(); + if let IrVariableDescriptor::VirtualRegister(vr_variable) = borrowed_ir_variable.descriptor() { + if spills.contains(vr_variable) { + let name = vr_variable.name_owned(); + let block_id = vr_variable.block_id(); + borrowed_ir_variable.set_descriptor(IrVariableDescriptor::Stack( + IrStackVariableDescriptor::new(name, block_id), + )); + } + } +} diff --git a/dmc-lib/src/symbol/class_symbol.rs b/dmc-lib/src/symbol/class_symbol.rs index 6eb5929..1f5a7f8 100644 --- a/dmc-lib/src/symbol/class_symbol.rs +++ b/dmc-lib/src/symbol/class_symbol.rs @@ -39,6 +39,10 @@ impl ClassSymbol { self.constructor_symbol = constructor_symbol; } + pub fn fields(&self) -> &HashMap, Rc>> { + &self.fields + } + /// 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() diff --git a/dmc-lib/src/symbol/expressible_symbol.rs b/dmc-lib/src/symbol/expressible_symbol.rs index 53e0bc9..fb90f06 100644 --- a/dmc-lib/src/symbol/expressible_symbol.rs +++ b/dmc-lib/src/symbol/expressible_symbol.rs @@ -39,6 +39,8 @@ impl ExpressibleSymbol { todo!() } ExpressibleSymbol::Field(field_symbol) => { + // this, unfortunately, is going to need more context, because fields live longer + // than function calls todo!() } ExpressibleSymbol::Function(_) => { diff --git a/dmc-lib/src/symbol/field_symbol.rs b/dmc-lib/src/symbol/field_symbol.rs index 32b7809..05d4b6d 100644 --- a/dmc-lib/src/symbol/field_symbol.rs +++ b/dmc-lib/src/symbol/field_symbol.rs @@ -7,6 +7,7 @@ pub struct FieldSymbol { declared_name: Rc, declared_name_source_range: SourceRange, type_info: Option, + field_index: Option, } impl FieldSymbol { @@ -15,6 +16,7 @@ impl FieldSymbol { declared_name: declared_name.clone(), declared_name_source_range, type_info: None, + field_index: None, } } @@ -25,6 +27,14 @@ impl FieldSymbol { pub fn type_info(&self) -> &TypeInfo { self.type_info.as_ref().unwrap() } + + pub fn set_field_index(&mut self, field_index: usize) { + self.field_index = Some(field_index); + } + + pub fn field_index(&self) -> usize { + self.field_index.unwrap() + } } impl Symbol for FieldSymbol { diff --git a/dvm-lib/src/instruction.rs b/dvm-lib/src/instruction.rs index fca931f..194475a 100644 --- a/dvm-lib/src/instruction.rs +++ b/dvm-lib/src/instruction.rs @@ -7,6 +7,8 @@ pub type ConstantName = Rc; pub type FunctionName = Rc; pub type ArgCount = usize; pub type CallerPopCount = usize; +pub type ClassFqn = Rc; +pub type FieldIndex = usize; pub enum Instruction { Move(MoveOperand, Location), @@ -15,6 +17,10 @@ pub enum Instruction { InvokeStatic(FunctionName, ArgCount), InvokePlatformStatic(FunctionName, ArgCount), + Allocate(ClassFqn, Location), + GetField(Location, FieldIndex, Location), + SetField(Location, FieldIndex, SetFieldOperand), + Add(AddOperand, AddOperand, Location), Subtract(SubtractOperand, SubtractOperand, Location), Multiply(MultiplyOperand, MultiplyOperand, Location), @@ -64,6 +70,15 @@ impl Display for Instruction { Instruction::Return => { write!(f, "ret") } + Instruction::Allocate(class_fqn, location) => { + write!(f, "alloc {}, {}", class_fqn, location) + } + Instruction::GetField(source, field_index, destination) => { + write!(f, "getf {}.{}, {}", source, field_index, destination) + } + Instruction::SetField(target_location, field_index, operand) => { + write!(f, "setf {}.{}, {}", target_location, field_index, operand) + } } } } @@ -237,3 +252,29 @@ impl Display for ReturnOperand { } } } + +pub enum SetFieldOperand { + Location(Location), + Int(i32), + Double(f64), + String(Rc), +} + +impl Display for SetFieldOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + SetFieldOperand::Location(location) => { + write!(f, "{}", location) + } + SetFieldOperand::Int(i) => { + write!(f, "{}", i) + } + SetFieldOperand::Double(d) => { + write!(f, "{}", d) + } + SetFieldOperand::String(s) => { + write!(f, "{}", s) + } + } + } +} diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index 3bd3895..e1e1f61 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -318,6 +318,29 @@ pub fn call<'a>( call_stack.top_mut().increment_ip(); } + /* Object instructions */ + Instruction::Allocate(class_fqn, destination) => { + // let class = context.classes().get(class_fqn).expect("No such class loaded: {}") + // let object: Gc> = Object::new(class, heap) + // let value = Value::Object(object) + // put_value(registers, call_stack.top_mut(), destination, result) + todo!() + } + + Instruction::GetField(source, field_index, destination) => { + // let object = load_value(...).unwrap_object(); + // let field_value = object.fields()[field_index]; + // put_value(..., destination, field_value.clone()); + todo!() + } + + Instruction::SetField(target, field_index, operand) => { + // let new_value = to_value(operand); + // let object = load_value(... target).unwrap_object(); + // object.fields_mut()[field_index] = new_value; + todo!() + } + /* Add instructions */ Instruction::Add(left_operand, right_operand, destination) => { let left_value = add_operand_to_value(