Compiling fields getters/setters.

This commit is contained in:
Jesse Brault 2026-03-12 21:52:21 -05:00
parent 51a80bb5ed
commit 320cdcf805
22 changed files with 494 additions and 38 deletions

View File

@ -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(),

View File

@ -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<Constructor>,
fields: Vec<Field>,
functions: Vec<Function>,
class_symbol: Option<Rc<RefCell<ClassSymbol>>>,
}
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<Diagnostic> = 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<IrFunction> {
let mut ir_functions: Vec<IrFunction> = 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)
}
}
}

View File

@ -136,9 +136,15 @@ impl CompilationUnit {
}
pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec<IrFunction> {
let mut functions: Vec<IrFunction> = 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
}
}

View File

@ -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<RefCell<ClassSymbol>>,
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::<Vec<_>>();
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(),
)
}
}

View File

@ -52,6 +52,7 @@ impl Field {
pub fn gather_declared_names(
&mut self,
symbol_table: &mut SymbolTable,
field_index: usize,
) -> Result<(), Vec<Diagnostic>> {
// 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<RefCell<FieldSymbol>> {
self.field_symbol.as_ref().unwrap()
}
}

View File

@ -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,

View File

@ -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(),

View File

@ -0,0 +1,26 @@
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub struct IrAllocate {
class_fqn: Rc<str>,
}
impl IrAllocate {
pub fn new(class_fqn: Rc<str>) -> Self {
Self { class_fqn }
}
pub fn class_fqn(&self) -> &str {
&self.class_fqn
}
pub fn class_fqn_owned(&self) -> Rc<str> {
self.class_fqn.clone()
}
}
impl Display for IrAllocate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "alloc {}", self.class_fqn)
}
}

View File

@ -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,
)),
}
}
}

View File

@ -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<RefCell<IrVariable>>, usize),
Parameter(Rc<IrParameter>),
Variable(Rc<RefCell<IrVariable>>),
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<IrVrVariableDescriptor> {
// no defs for an expression
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
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<IrVrVariableDescriptor>) {
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<IrVrVariableDescriptor, usize>,
) {
match self {
IrExpression::Field(self_variable, field_index) => {
// no-op
}
IrExpression::Parameter(_) => {
// no-op
}

View File

@ -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<RefCell<FunctionSymbol>>,
fqn: Rc<str>,
parameters: Vec<Rc<IrParameter>>,
return_type_info: TypeInfo,
entry: Rc<RefCell<IrBlock>>,
@ -22,13 +20,13 @@ pub struct IrFunction {
impl IrFunction {
pub fn new(
function_symbol: Rc<RefCell<FunctionSymbol>>,
fqn: Rc<str>,
parameters: &[Rc<IrParameter>],
return_type_info: &TypeInfo,
entry: Rc<RefCell<IrBlock>>,
) -> 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 {

View File

@ -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(_) => (),
}
}

View File

@ -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<RefCell<IrVariable>>,
field_index: usize,
initializer: Box<IrExpression>,
}
impl IrSetField {
pub fn new(
target_object: &Rc<RefCell<IrVariable>>,
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<IrVrVariableDescriptor> {
// only this, because the target_object is technically not a definition
self.initializer.vr_definitions()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
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<IrVrVariableDescriptor>) {
propagate_spills(&mut self.target_object, spills);
self.initializer.propagate_spills(spills);
}
fn propagate_register_assignments(
&mut self,
_assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
// 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
)
}
}

View File

@ -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)
}
}
}
}

View File

@ -73,6 +73,13 @@ impl IrVariableDescriptor {
IrVariableDescriptor::Stack(stack_variable) => stack_variable.name(),
}
}
pub fn name_owned(&self) -> Rc<str> {
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<str> {
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<str> {
self.name.clone()
}
pub fn set_offset(&mut self, offset: isize) {
self.offset = Some(offset);
}

View File

@ -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;

22
dmc-lib/src/ir/util.rs Normal file
View File

@ -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<RefCell<IrVariable>>,
spills: &HashSet<IrVrVariableDescriptor>,
) {
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),
));
}
}
}

View File

@ -39,6 +39,10 @@ impl ClassSymbol {
self.constructor_symbol = constructor_symbol;
}
pub fn fields(&self) -> &HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
&self.fields
}
/// A value of `None` indicates that there is no declared constructor for this class.
pub fn constructor_symbol(&self) -> Option<&Rc<RefCell<ConstructorSymbol>>> {
self.constructor_symbol.as_ref()

View File

@ -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(_) => {

View File

@ -7,6 +7,7 @@ pub struct FieldSymbol {
declared_name: Rc<str>,
declared_name_source_range: SourceRange,
type_info: Option<TypeInfo>,
field_index: Option<usize>,
}
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 {

View File

@ -7,6 +7,8 @@ pub type ConstantName = Rc<str>;
pub type FunctionName = Rc<str>;
pub type ArgCount = usize;
pub type CallerPopCount = usize;
pub type ClassFqn = Rc<str>;
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<str>),
}
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)
}
}
}
}

View File

@ -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<GcCell<Object>> = 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(