Compare commits

...

5 Commits

Author SHA1 Message Date
Jesse Brault
f0c84fe0c8 Parsing and lexing multiply, divide, modulo, shift operators. 2026-03-15 13:41:07 -05:00
Jesse Brault
4a0a6b8425 Clean up ir vr_user trait and implementations. 2026-03-15 13:16:21 -05:00
Jesse Brault
f9373a687f Refactor to use IrBinaryOperation. 2026-03-15 12:56:22 -05:00
Jesse Brault
863c3fef5d Refactor to use BinaryExpression. 2026-03-15 12:18:38 -05:00
Jesse Brault
5a123419bd Assign statements ir and fixing some things. 2026-03-14 19:53:06 -05:00
40 changed files with 838 additions and 899 deletions

View File

@ -114,7 +114,7 @@ fn compile_expression(
let mut ir_builder = IrBuilder::new();
let entry_block_id = ir_builder.new_block();
let maybe_ir_expression = expression.to_ir(&mut ir_builder, &symbol_table);
let maybe_ir_expression = expression.to_ir_expression(&mut ir_builder, &symbol_table);
// if Some, return the value
ir_builder

View File

@ -1,102 +0,0 @@
use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic;
use crate::ir::ir_add::IrAdd;
use crate::source_range::SourceRange;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
pub struct AddExpression {
lhs: Box<Expression>,
rhs: Box<Expression>,
source_range: SourceRange,
type_info: Option<TypeInfo>,
}
impl AddExpression {
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
Self {
lhs: lhs.into(),
rhs: rhs.into(),
source_range,
type_info: None,
}
}
pub fn lhs(&self) -> &Expression {
&self.lhs
}
pub fn rhs(&self) -> &Expression {
&self.rhs
}
pub fn gather_declared_names(
&mut self,
symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> {
let diagnostics: Vec<Diagnostic> = [self.lhs.as_mut(), self.rhs.as_mut()]
.iter_mut()
.map(|expression| expression.gather_declared_names(symbol_table))
.filter_map(Result::err)
.flatten()
.collect();
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
let diagnostics: Vec<Diagnostic> = [self.lhs.as_mut(), self.rhs.as_mut()]
.iter_mut()
.map(|expression| expression.check_name_usages(symbol_table))
.filter_map(Result::err)
.flatten()
.collect();
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
self.lhs.type_check(symbol_table)?;
self.rhs.type_check(symbol_table)?;
let lhs_type_info = self.lhs.type_info();
let rhs_type_info = self.rhs.type_info();
if lhs_type_info.can_add(rhs_type_info) {
self.type_info = Some(lhs_type_info.add_result(rhs_type_info));
Ok(())
} else {
Err(vec![Diagnostic::new(
&format!("Cannot add {} to {}", rhs_type_info, lhs_type_info),
self.source_range.start(),
self.source_range.end(),
)])
}
}
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrAdd {
let lhs_ir_expression = self
.lhs
.to_ir(builder, symbol_table)
.expect("Attempt to add non-expression");
let rhs_ir_expression = self
.rhs
.to_ir(builder, symbol_table)
.expect("Attempt to add non-expression");
IrAdd::new(lhs_ir_expression, rhs_ir_expression)
}
pub fn type_info(&self) -> &TypeInfo {
self.type_info.as_ref().unwrap()
}
pub fn source_range(&self) -> &SourceRange {
&self.source_range
}
}

View File

@ -1,6 +1,12 @@
use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::ast::ir_util::get_or_init_mut_field_pointer_variable;
use crate::diagnostic::{Diagnostic, SecondaryLabel};
use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE};
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_set_field::IrSetField;
use crate::ir::ir_statement::IrStatement;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol_table::SymbolTable;
pub struct AssignStatement {
@ -157,6 +163,38 @@ impl AssignStatement {
Err(diagnostics)
}
}
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
let destination_symbol = match &*self.destination {
Expression::Identifier(identifier) => identifier.expressible_symbol(),
_ => unreachable!("Destination must be a mutable L value"),
};
let ir_statement = match destination_symbol {
ExpressibleSymbol::Field(field_symbol) => {
let mut_field_pointer_variable =
get_or_init_mut_field_pointer_variable(builder, field_symbol).clone();
let ir_set_field = IrSetField::new(
&mut_field_pointer_variable,
self.value
.to_ir_expression(builder, symbol_table)
.expect("Attempt to convert non-value to value"),
);
IrStatement::SetField(ir_set_field)
}
ExpressibleSymbol::Variable(variable_symbol) => {
let vr_variable = variable_symbol.borrow().vr_variable().clone();
let ir_assign = IrAssign::new(
vr_variable,
self.value.to_ir_operation(builder, symbol_table),
);
IrStatement::Assign(ir_assign)
}
_ => unreachable!("Destination must be a mutable L value"),
};
builder.current_block_mut().add_statement(ir_statement);
}
}
#[cfg(test)]

View File

@ -0,0 +1,223 @@
use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic;
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator};
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::{diagnostics_result, handle_diagnostic, handle_diagnostics, maybe_return_diagnostics};
use std::cell::RefCell;
use std::rc::Rc;
pub enum BinaryOperation {
Multiply,
Divide,
Modulo,
Add,
Subtract,
LeftShift,
RightShift,
}
pub struct BinaryExpression {
lhs: Box<Expression>,
rhs: Box<Expression>,
op: BinaryOperation,
source_range: SourceRange,
type_info: Option<TypeInfo>,
}
impl BinaryExpression {
pub fn new(
lhs: Expression,
rhs: Expression,
op: BinaryOperation,
source_range: SourceRange,
) -> Self {
Self {
lhs: lhs.into(),
rhs: rhs.into(),
op,
source_range,
type_info: None,
}
}
pub fn lhs(&self) -> &Expression {
&self.lhs
}
pub fn rhs(&self) -> &Expression {
&self.rhs
}
pub fn op(&self) -> &BinaryOperation {
&self.op
}
pub fn source_range(&self) -> &SourceRange {
&self.source_range
}
pub fn type_info(&self) -> &TypeInfo {
self.type_info.as_ref().unwrap()
}
pub fn gather_declared_names(
&mut self,
symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> {
let diagnostics = [&mut self.lhs, &mut self.rhs]
.iter_mut()
.map(|expression| expression.gather_declared_names(symbol_table))
.filter_map(|result| result.err())
.flatten()
.collect::<Vec<Diagnostic>>();
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
let diagnostics: Vec<Diagnostic> = [&mut self.lhs, &mut self.rhs]
.iter_mut()
.map(|expression| expression.check_name_usages(symbol_table))
.filter_map(Result::err)
.flatten()
.collect();
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
fn check_op(
&mut self,
check: impl Fn(&TypeInfo, &TypeInfo) -> bool,
op_result: impl Fn(&TypeInfo, &TypeInfo) -> TypeInfo,
lazy_diagnostic_message: impl Fn(&TypeInfo, &TypeInfo) -> String,
) -> Result<(), Diagnostic> {
let lhs_type_info = self.lhs.type_info();
let rhs_type_info = self.rhs.type_info();
if check(lhs_type_info, rhs_type_info) {
self.type_info = Some(op_result(lhs_type_info, rhs_type_info));
Ok(())
} else {
let diagnostic = Diagnostic::new(
&lazy_diagnostic_message(lhs_type_info, rhs_type_info),
self.source_range.start(),
self.source_range.end(),
)
.with_primary_label_message("Incompatible types for addition.")
.with_reporter(file!(), line!())
.with_error_code(BINARY_INCOMPATIBLE_TYPES);
Err(diagnostic)
}
}
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
handle_diagnostics!(self.lhs.type_check(symbol_table), diagnostics);
handle_diagnostics!(self.rhs.type_check(symbol_table), diagnostics);
maybe_return_diagnostics!(diagnostics);
match &self.op {
BinaryOperation::Multiply => {
todo!()
}
BinaryOperation::Divide => {
todo!()
}
BinaryOperation::Modulo => {
todo!()
}
BinaryOperation::Add => {
handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_add(rhs),
|lhs, rhs| lhs.add_result(&rhs),
|lhs, rhs| format!("Incompatible types: cannot add {} to {}.", rhs, lhs)
),
diagnostics
);
}
BinaryOperation::Subtract => {
handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_subtract(rhs),
|lhs, rhs| lhs.subtract_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot subtract {} from {}.",
rhs, lhs
)
),
diagnostics
)
}
BinaryOperation::LeftShift => todo!(),
BinaryOperation::RightShift => todo!(),
}
diagnostics_result!(diagnostics)
}
pub fn to_ir_operation(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
) -> IrOperation {
let lhs = self
.lhs
.to_ir_expression(builder, symbol_table)
.expect("Attempt to use a non-value expression in binary expression.");
let rhs = self
.rhs
.to_ir_expression(builder, symbol_table)
.expect("Attempt to use a non-value expression in binary expression.");
let ir_binary_operation = match self.op {
BinaryOperation::Multiply => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Multiply)
}
BinaryOperation::Divide => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Divide),
BinaryOperation::Modulo => todo!(),
BinaryOperation::Add => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Add),
BinaryOperation::Subtract => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Subtract)
}
BinaryOperation::LeftShift => todo!(),
BinaryOperation::RightShift => todo!(),
};
IrOperation::Binary(ir_binary_operation)
}
pub fn to_ir_expression(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
) -> IrExpression {
let ir_operation = self.to_ir_operation(builder, symbol_table);
let t_var = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
self.type_info(),
);
let as_rc = Rc::new(RefCell::new(t_var));
let ir_assign = IrAssign::new(as_rc.clone(), ir_operation);
builder
.current_block_mut()
.add_statement(IrStatement::Assign(ir_assign));
IrExpression::Variable(as_rc)
}
}

View File

@ -5,7 +5,6 @@ use crate::diagnostic::Diagnostic;
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_table::SymbolTable;
@ -176,7 +175,7 @@ impl Call {
let arguments: Vec<IrExpression> = self
.arguments
.iter()
.map(|argument| argument.to_ir(builder, symbol_table))
.map(|argument| argument.to_ir_expression(builder, symbol_table))
.inspect(|expression| {
if expression.is_none() {
panic!("Attempt to pass non-expression")

View File

@ -200,13 +200,19 @@ impl Constructor {
.iter()
.enumerate()
.map(|(i, parameter)| {
let parameter_symbol = parameter.parameter_symbol().borrow();
let mut parameter_symbol = parameter.parameter_symbol().borrow_mut();
let offset = (parameters_count as isize).neg() + i as isize;
Rc::new(IrParameter::new(
let ir_parameter = Rc::new(IrParameter::new(
parameter_symbol.declared_name(),
parameter_symbol.type_info().clone(),
offset,
))
));
// make sure to save ir_parameter to symbol so others can access it
let to_save = ir_parameter.clone();
parameter_symbol.set_ir_parameter(to_save);
ir_parameter
})
.collect::<Vec<_>>();
@ -219,6 +225,11 @@ impl Constructor {
&TypeInfo::ClassInstance(class_symbol.clone()),
);
let self_variable = Rc::new(RefCell::new(alloc_assign_destination));
// save self variable so statements can assign stuff to self's fields
ir_builder
.set_self_parameter_or_variable(IrParameterOrVariable::Variable(self_variable.clone()));
let alloc_assign = IrAssign::new(
self_variable.clone(),
IrOperation::Allocate(IrAllocate::new(class_symbol.borrow().declared_name_owned())),
@ -252,16 +263,18 @@ impl Constructor {
// save the mut ref to the builder for other uses if needed
ir_builder
.field_mut_pointer_variables_mut()
.insert(field_mut_ref_variable_name.clone(), field_mut_ref_variable);
.insert(field.declared_name_owned(), field_mut_ref_variable); // n.b. field name, not t var name
// now write the initializer result to the field
let field_mut_ref_variable = ir_builder
.field_mut_pointer_variables()
.get(&field_mut_ref_variable_name)
.get(field.declared_name())
.unwrap()
.clone();
let ir_expression = initializer.to_ir(&mut ir_builder, symbol_table).unwrap();
let ir_expression = initializer
.to_ir_expression(&mut ir_builder, symbol_table)
.unwrap();
let ir_set_field = IrSetField::new(
&field_mut_ref_variable, // dumb that we clone it and then ref it
ir_expression,
@ -272,6 +285,11 @@ impl Constructor {
}
}
// do "declared" statements of constructor
for statement in &self.statements {
statement.to_ir(&mut ir_builder, symbol_table, false);
}
// return complete self object
let ir_return_statement = IrStatement::Return(IrReturn::new(Some(IrExpression::Variable(
self_variable.clone(),

View File

@ -1,4 +1,4 @@
use crate::ast::add_expression::AddExpression;
use crate::ast::binary_expression::BinaryExpression;
use crate::ast::call::Call;
use crate::ast::double_literal::DoubleLiteral;
use crate::ast::identifier::Identifier;
@ -6,7 +6,6 @@ use crate::ast::integer_literal::IntegerLiteral;
use crate::ast::ir_builder::IrBuilder;
use crate::ast::negative_expression::NegativeExpression;
use crate::ast::string_literal::StringLiteral;
use crate::ast::subtract_expression::SubtractExpression;
use crate::diagnostic::Diagnostic;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
@ -20,8 +19,7 @@ use std::cell::RefCell;
use std::rc::Rc;
pub enum Expression {
Add(AddExpression),
Subtract(SubtractExpression),
Binary(BinaryExpression),
Negative(NegativeExpression),
Call(Call),
Identifier(Identifier),
@ -36,9 +34,8 @@ impl Expression {
symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> {
match self {
Expression::Add(add_expression) => add_expression.gather_declared_names(symbol_table),
Expression::Subtract(subtract_expression) => {
subtract_expression.gather_declared_names(symbol_table)
Expression::Binary(binary_expression) => {
binary_expression.gather_declared_names(symbol_table)
}
Expression::Negative(negative_expression) => {
negative_expression.gather_declared_names(symbol_table)
@ -53,9 +50,8 @@ impl Expression {
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
match self {
Expression::Add(add_expression) => add_expression.check_name_usages(symbol_table),
Expression::Subtract(subtract_expression) => {
subtract_expression.check_name_usages(symbol_table)
Expression::Binary(binary_expression) => {
binary_expression.check_name_usages(symbol_table)
}
Expression::Negative(negative_expression) => {
negative_expression.check_name_usages(symbol_table)
@ -70,10 +66,7 @@ impl Expression {
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
match self {
Expression::Add(add_expression) => add_expression.type_check(symbol_table),
Expression::Subtract(subtract_expression) => {
subtract_expression.type_check(symbol_table)
}
Expression::Binary(binary_expression) => binary_expression.type_check(symbol_table),
Expression::Negative(negative_expression) => {
negative_expression.type_check(symbol_table)
}
@ -87,8 +80,7 @@ impl Expression {
pub fn type_info(&self) -> &TypeInfo {
match self {
Expression::Add(add_expression) => add_expression.type_info(),
Expression::Subtract(subtract_expression) => subtract_expression.type_info(),
Expression::Binary(binary_expression) => binary_expression.type_info(),
Expression::Negative(negative_expression) => negative_expression.type_info(),
Expression::Call(call) => call.return_type_info(),
Expression::Identifier(identifier) => identifier.type_info(),
@ -100,8 +92,7 @@ impl Expression {
pub fn source_range(&self) -> &SourceRange {
match self {
Expression::Add(additive_expression) => additive_expression.source_range(),
Expression::Subtract(subtract_expression) => subtract_expression.source_range(),
Expression::Binary(binary_expression) => binary_expression.source_range(),
Expression::Negative(negative_expression) => negative_expression.source_range(),
Expression::Call(call) => call.source_range(),
Expression::Identifier(identifier) => identifier.source_range(),
@ -111,12 +102,43 @@ impl Expression {
}
}
pub fn to_ir(
pub fn to_ir_operation(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
) -> IrOperation {
match self {
Expression::Binary(binary_expression) => {
binary_expression.to_ir_operation(builder, symbol_table)
}
Expression::Call(call) => IrOperation::Call(call.to_ir(builder, symbol_table)),
Expression::Integer(integer_literal) => {
IrOperation::Load(IrExpression::Int(integer_literal.value()))
}
Expression::Double(double_literal) => {
IrOperation::Load(IrExpression::Double(double_literal.value()))
}
Expression::String(string_literal) => {
IrOperation::Load(IrExpression::String(string_literal.content().into()))
}
Expression::Identifier(identifier) => {
IrOperation::Load(identifier.expressible_symbol().ir_expression(builder))
}
Expression::Negative(negative_expression) => {
IrOperation::Load(negative_expression.to_ir(builder, symbol_table))
}
}
}
pub fn to_ir_expression(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
) -> Option<IrExpression> {
match self {
Expression::Binary(binary_expression) => {
Some(binary_expression.to_ir_expression(builder, symbol_table))
}
Expression::Call(call) => {
let ir_call = call.to_ir(builder, symbol_table);
if matches!(call.return_type_info(), TypeInfo::Void) {
@ -151,23 +173,6 @@ impl Expression {
let expressible_symbol = identifier.expressible_symbol();
Some(expressible_symbol.ir_expression(builder))
}
Expression::Add(additive_expression) => {
let ir_add = additive_expression.to_ir(builder, symbol_table);
let t_var = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
additive_expression.type_info(),
);
let as_rc = Rc::new(RefCell::new(t_var));
let assign = IrAssign::new(as_rc.clone(), IrOperation::Add(ir_add));
builder
.current_block_mut()
.add_statement(IrStatement::Assign(assign));
Some(IrExpression::Variable(as_rc))
}
Expression::Subtract(subtract_expression) => {
Some(subtract_expression.to_ir_expression(builder, symbol_table))
}
Expression::Negative(negative_expression) => {
Some(negative_expression.to_ir(builder, symbol_table))
}

View File

@ -62,7 +62,7 @@ impl ExpressionStatement {
symbol_table: &SymbolTable,
should_return_value: bool,
) {
let ir_expression = self.expression.to_ir(builder, symbol_table);
let ir_expression = self.expression.to_ir_expression(builder, symbol_table);
if ir_expression.is_some() && should_return_value {
builder
.current_block_mut()

View File

@ -42,6 +42,10 @@ impl Field {
&self.declared_name
}
pub fn declared_name_owned(&self) -> Rc<str> {
self.declared_name.clone()
}
pub fn declared_name_source_range(&self) -> &SourceRange {
&self.declared_name_source_range
}

View File

@ -0,0 +1,83 @@
use crate::ast::ir_builder::IrBuilder;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_get_field_ref::IrGetFieldRef;
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::symbol::Symbol;
use crate::symbol::field_symbol::FieldSymbol;
use std::cell::RefCell;
use std::rc::Rc;
pub fn get_or_init_field_pointer_variable<'a>(
builder: &'a mut IrBuilder,
field_symbol: &Rc<RefCell<FieldSymbol>>,
) -> &'a Rc<RefCell<IrVariable>> {
// This following should work because blocks are flat in the ir; if a variable is defined in the
// ir block from this point forward, it's available to all subsequent blocks.
if !builder
.field_pointer_variables()
.contains_key(field_symbol.borrow().declared_name())
{
let field_ref_variable = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
field_symbol.borrow().type_info(),
);
let as_rc = Rc::new(RefCell::new(field_ref_variable));
let to_insert = as_rc.clone();
let self_parameter_or_variable = builder.self_parameter_or_variable().clone();
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
as_rc,
IrOperation::GetFieldRef(IrGetFieldRef::new(
self_parameter_or_variable.clone(),
field_symbol.borrow().field_index(),
)),
)));
builder
.field_pointer_variables_mut()
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
}
builder
.field_pointer_variables()
.get(field_symbol.borrow().declared_name())
.unwrap()
}
pub fn get_or_init_mut_field_pointer_variable<'a>(
builder: &'a mut IrBuilder,
field_symbol: &Rc<RefCell<FieldSymbol>>,
) -> &'a Rc<RefCell<IrVariable>> {
if !builder
.field_mut_pointer_variables()
.contains_key(field_symbol.borrow().declared_name())
{
let mut_field_pointer_variable = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
field_symbol.borrow().type_info(),
);
let as_rc = Rc::new(RefCell::new(mut_field_pointer_variable));
let to_insert = as_rc.clone();
let self_parameter_or_variable = builder.self_parameter_or_variable().clone();
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
as_rc,
IrOperation::GetFieldRefMut(IrGetFieldRefMut::new(
self_parameter_or_variable.clone(),
field_symbol.borrow().field_index(),
)),
)));
builder
.field_mut_pointer_variables_mut()
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
}
builder
.field_mut_pointer_variables()
.get(field_symbol.borrow().declared_name())
.unwrap()
}

View File

@ -2,8 +2,6 @@ use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange;
@ -106,28 +104,7 @@ impl LetStatement {
}
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
let init_operation = match self.initializer() {
Expression::Call(call) => IrOperation::Call(call.to_ir(builder, symbol_table)),
Expression::Integer(integer_literal) => {
IrOperation::Load(IrExpression::Int(integer_literal.value()))
}
Expression::Double(double_literal) => {
IrOperation::Load(IrExpression::Double(double_literal.value()))
}
Expression::String(string_literal) => {
IrOperation::Load(IrExpression::String(string_literal.content().into()))
}
Expression::Identifier(identifier) => {
IrOperation::Load(identifier.expressible_symbol().ir_expression(builder))
}
Expression::Add(additive_expression) => {
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
}
Expression::Subtract(subtract_expression) => {
IrOperation::Subtract(subtract_expression.to_ir_subtract(builder, symbol_table))
}
Expression::Negative(_) => todo!(),
};
let init_operation = self.initializer.to_ir_operation(builder, symbol_table);
let destination_symbol =
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);

View File

@ -1,5 +1,5 @@
pub mod add_expression;
pub mod assign_statement;
pub mod binary_expression;
pub mod call;
pub mod class;
pub mod compilation_unit;
@ -16,10 +16,11 @@ pub mod function;
pub mod identifier;
pub mod integer_literal;
pub mod ir_builder;
pub(crate) mod ir_util;
pub mod let_statement;
pub mod negative_expression;
pub mod parameter;
pub mod statement;
pub mod string_literal;
pub mod subtract_expression;
pub mod type_use;
mod util;

View File

@ -2,8 +2,8 @@ use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator};
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_multiply::IrMultiply;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
@ -70,7 +70,7 @@ impl NegativeExpression {
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrExpression {
let operand_as_ir = self
.operand
.to_ir(builder, symbol_table)
.to_ir_expression(builder, symbol_table)
.expect("Attempt to negate non-value expression");
match operand_as_ir {
@ -87,8 +87,11 @@ impl NegativeExpression {
_ => panic!("Trying to multiply with a non-integer/double"),
};
let operation =
IrOperation::Multiply(IrMultiply::new(IrExpression::Parameter(parameter), rhs));
let operation = IrOperation::Binary(IrBinaryOperation::new(
IrExpression::Parameter(parameter),
rhs,
IrBinaryOperator::Multiply,
));
let assign = IrAssign::new(destination.clone(), operation);
builder
@ -110,8 +113,11 @@ impl NegativeExpression {
_ => panic!("Trying to multiply with a non-integer/double"),
};
let operation =
IrOperation::Multiply(IrMultiply::new(IrExpression::Variable(variable), rhs));
let operation = IrOperation::Binary(IrBinaryOperation::new(
IrExpression::Variable(variable),
rhs,
IrBinaryOperator::Multiply,
));
let assign = IrAssign::new(destination.clone(), operation);
builder

View File

@ -66,7 +66,7 @@ impl Statement {
expression_statement.to_ir(builder, symbol_table, should_return_value);
}
Statement::Assign(assign_statement) => {
todo!()
assign_statement.to_ir(builder, symbol_table);
}
}
}

View File

@ -1,135 +0,0 @@
use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_subtract::IrSubtract;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use std::cell::RefCell;
use std::rc::Rc;
pub struct SubtractExpression {
lhs: Box<Expression>,
rhs: Box<Expression>,
source_range: SourceRange,
type_info: Option<TypeInfo>,
}
impl SubtractExpression {
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
Self {
lhs: lhs.into(),
rhs: rhs.into(),
source_range,
type_info: None,
}
}
pub fn lhs(&self) -> &Expression {
&self.lhs
}
pub fn rhs(&self) -> &Expression {
&self.rhs
}
pub fn gather_declared_names(
&mut self,
symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> {
let diagnostics = [&mut self.lhs, &mut self.rhs]
.iter_mut()
.map(|expression| expression.gather_declared_names(symbol_table))
.filter_map(|result| result.err())
.flatten()
.collect::<Vec<Diagnostic>>();
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
let diagnostics: Vec<Diagnostic> = [&mut self.lhs, &mut self.rhs]
.iter_mut()
.map(|expression| expression.check_name_usages(symbol_table))
.filter_map(Result::err)
.flatten()
.collect();
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
self.lhs.type_check(symbol_table)?;
self.rhs.type_check(symbol_table)?;
let lhs_type_info = self.lhs.type_info();
let rhs_type_info = self.rhs.type_info();
if lhs_type_info.can_subtract(rhs_type_info) {
self.type_info = Some(lhs_type_info.add_result(rhs_type_info));
Ok(())
} else {
Err(vec![Diagnostic::new(
&format!(
"Incompatible types: cannot subtract {} from {}",
rhs_type_info, lhs_type_info
), // n.b. order
self.lhs.source_range().start(),
self.lhs.source_range().end(),
)])
}
}
pub fn type_info(&self) -> &TypeInfo {
self.type_info.as_ref().unwrap()
}
pub fn source_range(&self) -> &SourceRange {
&self.source_range
}
pub fn to_ir_subtract(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
) -> IrSubtract {
let lhs = self
.lhs
.to_ir(builder, symbol_table)
.expect("Attempt to subtract non-expression");
let rhs = self
.rhs
.to_ir(builder, symbol_table)
.expect("Attempt to subtract non-expression");
IrSubtract::new(lhs, rhs)
}
pub fn to_ir_expression(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
) -> IrExpression {
let ir_subtract = self.to_ir_subtract(builder, symbol_table);
let t_var = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
self.type_info(),
);
let as_rc = Rc::new(RefCell::new(t_var));
let assign = IrAssign::new(as_rc.clone(), IrOperation::Subtract(ir_subtract));
builder
.current_block_mut()
.add_statement(IrStatement::Assign(assign));
IrExpression::Variable(as_rc)
}
}

43
dmc-lib/src/ast/util.rs Normal file
View File

@ -0,0 +1,43 @@
#[macro_export]
macro_rules! handle_diagnostic {
( $result: expr, $diagnostics: expr ) => {
match $result {
Ok(_) => {}
Err(diagnostic) => {
$diagnostics.push(diagnostic);
}
}
};
}
#[macro_export]
macro_rules! handle_diagnostics {
( $result: expr, $diagnostics: expr ) => {
match $result {
Ok(_) => {}
Err(mut result_diagnostics) => {
$diagnostics.append(&mut result_diagnostics);
}
}
};
}
#[macro_export]
macro_rules! maybe_return_diagnostics {
( $diagnostics: expr ) => {
if !$diagnostics.is_empty() {
return Err($diagnostics);
}
};
}
#[macro_export]
macro_rules! diagnostics_result {
( $diagnostics: expr ) => {
if $diagnostics.is_empty() {
Ok(())
} else {
Err($diagnostics)
}
};
}

View File

@ -1,5 +1,6 @@
pub type ErrorCode = usize;
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
pub const ASSIGN_MISMATCHED_TYPES: ErrorCode = 16;
pub const ASSIGN_NO_L_VALUE: ErrorCode = 17;
pub const ASSIGN_LHS_IMMUTABLE: ErrorCode = 18;

View File

@ -1,75 +0,0 @@
use crate::constants_table::ConstantsTable;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use dvm_lib::instruction::AddOperand;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
pub struct IrAdd {
left: Box<IrExpression>,
right: Box<IrExpression>,
}
impl IrAdd {
pub fn new(left: IrExpression, right: IrExpression) -> Self {
Self {
left: left.into(),
right: right.into(),
}
}
pub fn left(&self) -> &IrExpression {
&self.left
}
pub fn right(&self) -> &IrExpression {
&self.right
}
pub fn operand_pair(&self, constants_table: &mut ConstantsTable) -> (AddOperand, AddOperand) {
(
self.left.add_operand(constants_table),
self.right.add_operand(constants_table),
)
}
}
impl Display for IrAdd {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} + {}", self.left, self.right)
}
}
impl VrUser for IrAdd {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
[self.left.as_ref(), self.right.as_ref()]
.iter()
.flat_map(|e| e.vr_definitions())
.collect()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
[self.left.as_ref(), self.right.as_ref()]
.iter()
.flat_map(|e| e.vr_uses())
.collect()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
self.left.propagate_spills(spills);
self.right.propagate_spills(spills);
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
self.left.propagate_register_assignments(assignments);
self.right.propagate_register_assignments(assignments);
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// no-op, no definitions here
}
}

View File

@ -3,6 +3,7 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_operation::IrOperation;
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;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
@ -25,12 +26,10 @@ impl IrAssign {
impl VrUser for IrAssign {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
match self.destination.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_descriptor) => {
HashSet::from([vr_descriptor.clone()])
}
IrVariableDescriptor::Stack(_) => HashSet::new(),
}
self.destination
.borrow()
.descriptor()
.vr_variable_descriptors()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
@ -38,20 +37,7 @@ impl VrUser for IrAssign {
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
let borrowed_destination = self.destination.borrow();
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
borrowed_destination.descriptor()
{
if spills.contains(vr_variable) {
let replacement = IrVariable::new_stack(
vr_variable.name().into(),
vr_variable.block_id(),
borrowed_destination.type_info().clone(),
);
drop(borrowed_destination);
self.destination.replace(replacement);
}
}
propagate_spills(&mut self.destination, spills);
}
fn propagate_register_assignments(
@ -66,7 +52,6 @@ impl VrUser for IrAssign {
vr_variable.set_assigned_register(assignments[vr_variable]);
}
}
self.initializer.propagate_register_assignments(assignments);
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
@ -112,17 +97,8 @@ impl Assemble for IrAssign {
let move_operand = ir_expression.move_operand(constants_table);
builder.push(Instruction::Move(move_operand, destination));
}
IrOperation::Add(ir_add) => {
let (left, right) = ir_add.operand_pair(constants_table);
builder.push(Instruction::Add(left, right, destination));
}
IrOperation::Subtract(ir_subtract) => {
let (left, right) = ir_subtract.operand_pair();
builder.push(Instruction::Subtract(left, right, destination));
}
IrOperation::Multiply(ir_multiply) => {
let (left, right) = ir_multiply.operand_pair();
builder.push(Instruction::Multiply(left, right, destination));
IrOperation::Binary(ir_binary_operation) => {
ir_binary_operation.assemble_assign(builder, constants_table, destination);
}
IrOperation::Call(ir_call) => {
ir_call.assemble(builder, constants_table);

View File

@ -0,0 +1,88 @@
use crate::constants_table::ConstantsTable;
use crate::ir::assemble::InstructionsBuilder;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::VrUser;
use dvm_lib::instruction::{Instruction, Location};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
pub enum IrBinaryOperator {
Multiply,
Divide,
Add,
Subtract,
}
pub struct IrBinaryOperation {
left: Box<IrExpression>,
right: Box<IrExpression>,
op: IrBinaryOperator,
}
impl IrBinaryOperation {
pub fn new(left: IrExpression, right: IrExpression, op: IrBinaryOperator) -> Self {
Self {
left: left.into(),
right: right.into(),
op,
}
}
pub fn assemble_assign(
&self,
builder: &mut InstructionsBuilder,
constants_table: &mut ConstantsTable,
destination: Location,
) {
let instruction = match &self.op {
IrBinaryOperator::Multiply => Instruction::Multiply(
self.left.multiply_operand(),
self.right.multiply_operand(),
destination,
),
IrBinaryOperator::Divide => {
todo!()
}
IrBinaryOperator::Add => Instruction::Add(
self.left.add_operand(constants_table),
self.right.add_operand(constants_table),
destination,
),
IrBinaryOperator::Subtract => Instruction::Subtract(
self.left.subtract_operand(),
self.right.subtract_operand(),
destination,
),
};
builder.push(instruction);
}
}
impl Display for IrBinaryOperation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.op {
IrBinaryOperator::Multiply => {
write!(f, "{} * {}", self.left, self.right)
}
IrBinaryOperator::Divide => {
write!(f, "{} / {}", self.left, self.right)
}
IrBinaryOperator::Add => {
write!(f, "{} + {}", self.left, self.right)
}
IrBinaryOperator::Subtract => {
write!(f, "{} - {}", self.left, self.right)
}
}
}
}
impl VrUser for IrBinaryOperation {
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
[self.left.as_ref(), self.right.as_ref()]
.iter()
.flat_map(|e| e.vr_uses())
.collect()
}
}

View File

@ -2,9 +2,9 @@ use crate::constants_table::ConstantsTable;
use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use crate::ir::register_allocation::VrUser;
use dvm_lib::instruction::Instruction;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
@ -25,32 +25,9 @@ impl IrCall {
}
impl VrUser for IrCall {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
self.arguments.iter().flat_map(|a| a.vr_uses()).collect()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
for argument in &mut self.arguments {
argument.propagate_spills(spills);
}
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
for argument in &mut self.arguments {
argument.propagate_register_assignments(assignments);
}
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// no-op, because no definitions here
}
}
impl Assemble for IrCall {

View File

@ -1,16 +1,14 @@
use crate::constants_table::ConstantsTable;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_variable::{
IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor,
};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::VrUser;
use crate::type_info::TypeInfo;
use dvm_lib::instruction::{
AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand,
SetFieldOperand, SubtractOperand,
};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
@ -231,11 +229,6 @@ 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::Parameter(_) => HashSet::new(),
@ -253,71 +246,4 @@ impl VrUser for IrExpression {
IrExpression::String(_) => HashSet::new(),
}
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
match self {
IrExpression::Parameter(_) => {
// no-op
}
IrExpression::Variable(ir_variable) => {
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
ir_variable.borrow().descriptor()
{
if spills.contains(&vr_variable) {
ir_variable
.borrow_mut()
.set_descriptor(IrVariableDescriptor::Stack(
IrStackVariableDescriptor::new(
vr_variable.name().into(),
vr_variable.block_id(),
),
));
}
}
}
IrExpression::Int(_) => {
// no-op
}
IrExpression::Double(_) => {
// no-op
}
IrExpression::String(_) => {
// no-op
}
}
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
match self {
IrExpression::Parameter(_) => {
// no-op
}
IrExpression::Variable(ir_variable) => {
let mut borrowed = ir_variable.borrow_mut();
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
borrowed.descriptor_mut()
{
if assignments.contains_key(vr_variable) {
vr_variable.set_assigned_register(assignments[vr_variable]);
}
}
}
IrExpression::Int(_) => {
// no-op
}
IrExpression::Double(_) => {
// no-op
}
IrExpression::String(_) => {
// no-op
}
}
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// no-op
}
}

View File

@ -1,7 +1,7 @@
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::collections::{HashMap, HashSet};
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
pub struct IrGetFieldRef {
@ -37,21 +37,7 @@ impl Display for IrGetFieldRef {
}
impl VrUser for IrGetFieldRef {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
self.self_parameter_or_variable().vr_uses()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
}

View File

@ -1,7 +1,7 @@
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::collections::{HashMap, HashSet};
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
pub struct IrGetFieldRefMut {
@ -38,21 +38,7 @@ impl Display for IrGetFieldRefMut {
}
impl VrUser for IrGetFieldRefMut {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
self.self_parameter_or_variable.vr_uses()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
}

View File

@ -1,67 +0,0 @@
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use dvm_lib::instruction::MultiplyOperand;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
pub struct IrMultiply {
left: Box<IrExpression>,
right: Box<IrExpression>,
}
impl IrMultiply {
pub fn new(left: IrExpression, right: IrExpression) -> Self {
Self {
left: left.into(),
right: right.into(),
}
}
pub fn operand_pair(&self) -> (MultiplyOperand, MultiplyOperand) {
(self.left.multiply_operand(), self.right.multiply_operand())
}
}
impl Display for IrMultiply {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} * {}", self.left, self.right)
}
}
impl VrUser for IrMultiply {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
[&self.left, &self.right]
.iter()
.flat_map(|ir_expression| ir_expression.vr_definitions())
.collect()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
[&self.left, &self.right]
.iter()
.flat_map(|ir_expression| ir_expression.vr_uses())
.collect()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
[&mut self.left, &mut self.right]
.iter_mut()
.for_each(|ir_expression| ir_expression.propagate_spills(spills));
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
[&mut self.left, &mut self.right]
.iter_mut()
.for_each(|ir_expression| ir_expression.propagate_register_assignments(assignments));
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
[&mut self.left, &mut self.right]
.iter_mut()
.for_each(|ir_expression| ir_expression.propagate_stack_offsets(counter));
}
}

View File

@ -1,15 +1,13 @@
use crate::ir::ir_add::IrAdd;
use crate::ir::ir_allocate::IrAllocate;
use crate::ir::ir_binary_operation::IrBinaryOperation;
use crate::ir::ir_call::IrCall;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_get_field_ref::IrGetFieldRef;
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_multiply::IrMultiply;
use crate::ir::ir_read_field::IrReadField;
use crate::ir::ir_subtract::IrSubtract;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::collections::{HashMap, HashSet};
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
pub enum IrOperation {
@ -17,9 +15,7 @@ pub enum IrOperation {
GetFieldRefMut(IrGetFieldRefMut),
ReadField(IrReadField),
Load(IrExpression),
Add(IrAdd),
Subtract(IrSubtract),
Multiply(IrMultiply),
Binary(IrBinaryOperation),
Call(IrCall),
Allocate(IrAllocate),
}
@ -39,14 +35,8 @@ impl Display for IrOperation {
IrOperation::Load(ir_expression) => {
write!(f, "{}", ir_expression)
}
IrOperation::Add(ir_add) => {
write!(f, "{}", ir_add)
}
IrOperation::Subtract(ir_subtract) => {
write!(f, "{}", ir_subtract)
}
IrOperation::Multiply(ir_multiply) => {
write!(f, "{}", ir_multiply)
IrOperation::Binary(ir_binary_operation) => {
write!(f, "{}", ir_binary_operation)
}
IrOperation::Call(ir_call) => {
write!(f, "{}", ir_call)
@ -59,86 +49,15 @@ impl Display for IrOperation {
}
impl VrUser for IrOperation {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
match self {
IrOperation::GetFieldRef(_) => HashSet::new(),
IrOperation::GetFieldRefMut(_) => HashSet::new(),
IrOperation::ReadField(_) => HashSet::new(),
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
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(),
}
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
match self {
IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(),
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => ir_get_field_ref_mut.vr_uses(),
IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(),
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
IrOperation::Add(ir_add) => ir_add.vr_uses(),
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(),
IrOperation::Multiply(ir_multiply) => ir_multiply.vr_uses(),
IrOperation::Binary(ir_binary) => ir_binary.vr_uses(),
IrOperation::Call(ir_call) => ir_call.vr_uses(),
IrOperation::Allocate(_) => HashSet::new(),
}
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
match self {
IrOperation::GetFieldRef(_) => {}
IrOperation::GetFieldRefMut(_) => {}
IrOperation::ReadField(_) => {}
IrOperation::Load(ir_expression) => {
ir_expression.propagate_spills(spills);
}
IrOperation::Add(ir_add) => {
ir_add.propagate_spills(spills);
}
IrOperation::Subtract(ir_subtract) => {
ir_subtract.propagate_spills(spills);
}
IrOperation::Multiply(ir_multiply) => {
ir_multiply.propagate_spills(spills);
}
IrOperation::Call(ir_call) => {
ir_call.propagate_spills(spills);
}
IrOperation::Allocate(_) => (),
}
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
match self {
IrOperation::GetFieldRef(_) => {}
IrOperation::GetFieldRefMut(_) => {}
IrOperation::ReadField(_) => {}
IrOperation::Load(ir_expression) => {
ir_expression.propagate_register_assignments(assignments);
}
IrOperation::Add(ir_add) => {
ir_add.propagate_register_assignments(assignments);
}
IrOperation::Subtract(ir_subtract) => {
ir_subtract.propagate_register_assignments(assignments);
}
IrOperation::Multiply(ir_multiply) => {
ir_multiply.propagate_register_assignments(assignments);
}
IrOperation::Call(ir_call) => {
ir_call.propagate_register_assignments(assignments);
}
IrOperation::Allocate(_) => (),
}
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// no-op
}
}

View File

@ -1,7 +1,8 @@
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_variable::IrVariable;
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use dvm_lib::instruction::Location;
use std::cell::RefCell;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
@ -22,6 +23,17 @@ impl IrParameterOrVariable {
}
}
}
pub fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
if let IrParameterOrVariable::Variable(ir_variable) = &self {
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
ir_variable.borrow().descriptor()
{
return HashSet::from([vr_variable.clone()]);
}
}
HashSet::new()
}
}
impl Display for IrParameterOrVariable {

View File

@ -1,7 +1,7 @@
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use crate::ir::register_allocation::VrUser;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
@ -26,10 +26,6 @@ impl Display for IrReadField {
}
impl VrUser for IrReadField {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
let mut set = HashSet::new();
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
@ -39,14 +35,4 @@ impl VrUser for IrReadField {
}
set
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
}

View File

@ -2,9 +2,9 @@ use crate::constants_table::ConstantsTable;
use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use crate::ir::register_allocation::VrUser;
use dvm_lib::instruction::Instruction;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
pub struct IrReturn {
@ -18,10 +18,6 @@ impl IrReturn {
}
impl VrUser for IrReturn {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
if let Some(ir_expression) = self.value.as_ref() {
ir_expression.vr_uses()
@ -29,25 +25,6 @@ impl VrUser for IrReturn {
HashSet::new()
}
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
if let Some(ir_expression) = self.value.as_mut() {
ir_expression.propagate_spills(spills);
}
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
if let Some(ir_expression) = self.value.as_mut() {
ir_expression.propagate_register_assignments(assignments);
}
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// no-op
}
}
impl Assemble for IrReturn {

View File

@ -2,11 +2,10 @@ 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 crate::ir::register_allocation::VrUser;
use dvm_lib::instruction::Instruction;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
@ -25,11 +24,6 @@ impl IrSetField {
}
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.field_ref_variable.borrow().descriptor() {
@ -41,22 +35,6 @@ impl VrUser for IrSetField {
set.extend(self.initializer.vr_uses());
set
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
propagate_spills(&mut self.field_ref_variable, 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 {

View File

@ -1,63 +0,0 @@
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use dvm_lib::instruction::SubtractOperand;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
pub struct IrSubtract {
left: Box<IrExpression>,
right: Box<IrExpression>,
}
impl IrSubtract {
pub fn new(left: IrExpression, right: IrExpression) -> Self {
Self {
left: left.into(),
right: right.into(),
}
}
pub fn operand_pair(&self) -> (SubtractOperand, SubtractOperand) {
(self.left.subtract_operand(), self.right.subtract_operand())
}
}
impl VrUser for IrSubtract {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
[&self.left, &self.right]
.iter()
.flat_map(|expression| expression.vr_definitions())
.collect()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
[&self.left, &self.right]
.iter()
.flat_map(|expression| expression.vr_uses())
.collect()
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
self.left.propagate_spills(spills);
self.right.propagate_spills(spills);
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
self.left.propagate_register_assignments(assignments);
self.right.propagate_register_assignments(assignments);
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// no-op
}
}
impl Display for IrSubtract {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} - {}", self.left, self.right)
}
}

View File

@ -1,5 +1,6 @@
use crate::type_info::TypeInfo;
use dvm_lib::instruction::Location;
use std::collections::HashSet;
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::rc::Rc;
@ -90,6 +91,14 @@ impl IrVariableDescriptor {
IrVariableDescriptor::Stack(stack_variable) => stack_variable.as_location(),
}
}
pub fn vr_variable_descriptors(&self) -> HashSet<IrVrVariableDescriptor> {
if let IrVariableDescriptor::VirtualRegister(register_variable) = self {
HashSet::from([register_variable.clone()])
} else {
HashSet::new()
}
}
}
#[derive(Clone, Hash, PartialEq, Eq)]

View File

@ -1,7 +1,7 @@
mod assemble;
pub mod ir_add;
pub mod ir_allocate;
pub mod ir_assign;
pub mod ir_binary_operation;
pub mod ir_block;
pub mod ir_call;
pub mod ir_class;
@ -9,7 +9,6 @@ pub mod ir_expression;
pub mod ir_function;
pub mod ir_get_field_ref;
pub mod ir_get_field_ref_mut;
pub mod ir_multiply;
pub mod ir_operation;
pub mod ir_parameter;
pub mod ir_parameter_or_variable;
@ -17,7 +16,6 @@ pub mod ir_read_field;
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;

View File

@ -135,14 +135,26 @@ pub trait HasVrUsers {
}
pub trait VrUser {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor>;
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor>;
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>);
fn propagate_spills(&mut self, _spills: &HashSet<IrVrVariableDescriptor>) {
// default no-op
}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
);
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter);
_assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
// default no-op
}
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
// default no-op
}
}
pub struct OffsetCounter {

View File

@ -46,8 +46,18 @@ impl<'a> Lexer<'a> {
self.position + 1,
TokenKind::RightParentheses,
)
} else if chunk.starts_with("*") {
Token::new(self.position, self.position + 1, TokenKind::Star)
} else if chunk.starts_with("/") {
Token::new(self.position, self.position + 1, TokenKind::Slash)
} else if chunk.starts_with("%") {
Token::new(self.position, self.position + 1, TokenKind::Modulo)
} else if chunk.starts_with("+") {
Token::new(self.position, self.position + 1, TokenKind::Plus)
} else if chunk.starts_with("<<") {
Token::new(self.position, self.position + 2, TokenKind::LeftShift)
} else if chunk.starts_with(">>") {
Token::new(self.position, self.position + 2, TokenKind::RightShift)
} else if chunk.starts_with("=") {
Token::new(self.position, self.position + 1, TokenKind::Equals)
} else if chunk.starts_with(",") {

View File

@ -1,5 +1,5 @@
use crate::ast::add_expression::AddExpression;
use crate::ast::assign_statement::AssignStatement;
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
use crate::ast::call::Call;
use crate::ast::class::Class;
use crate::ast::compilation_unit::CompilationUnit;
@ -17,7 +17,6 @@ use crate::ast::negative_expression::NegativeExpression;
use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement;
use crate::ast::string_literal::StringLiteral;
use crate::ast::subtract_expression::SubtractExpression;
use crate::ast::type_use::TypeUse;
use crate::diagnostic::Diagnostic;
use crate::lexer::Lexer;
@ -663,28 +662,119 @@ impl<'a> Parser<'a> {
}
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
self.additive_expression()
self.shift_expression()
}
fn shift_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.additive_expression()?;
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::LeftShift => {
self.advance(); // left shift
let rhs = self.additive_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::LeftShift,
source_range,
));
}
TokenKind::RightShift => {
self.advance(); // right shift
let rhs = self.additive_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::RightShift,
source_range,
));
}
_ => break,
}
}
Ok(result)
}
fn additive_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.prefix_expression()?;
let mut result = self.multiplicative_expression()?;
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::Plus => {
self.advance(); // plus
let rhs = self.prefix_expression()?;
let rhs = self.multiplicative_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Add(AddExpression::new(result, rhs, source_range));
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Add,
source_range,
));
}
TokenKind::Minus => {
self.advance(); // minus
let rhs = self.multiplicative_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Subtract,
source_range,
));
}
_ => break,
}
}
Ok(result)
}
fn multiplicative_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.prefix_expression()?;
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::Star => {
self.advance(); // multiply
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result =
Expression::Subtract(SubtractExpression::new(result, rhs, source_range));
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Multiply,
source_range,
));
}
TokenKind::Slash => {
self.advance(); // slash
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Divide,
source_range,
))
}
TokenKind::Modulo => {
self.advance(); // modulo
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Modulo,
source_range,
));
}
_ => break,
}
@ -952,6 +1042,31 @@ mod smoke_tests {
",
);
}
#[test]
fn simple_multiply() {
smoke_test("fn main() 1 * 2 end");
}
#[test]
fn simple_divide() {
smoke_test("fn main() 1 / 2 end");
}
#[test]
fn simple_modulo() {
smoke_test("fn main() 1 % 2 end");
}
#[test]
fn simple_left_shift() {
smoke_test("fn main() 2 << 1 end");
}
#[test]
fn simple_right_shift() {
smoke_test("fn main() 4 >> 1 end");
}
}
#[cfg(test)]
@ -1055,14 +1170,15 @@ mod concrete_tests {
fn add_negative() {
let expression = assert_expression("1 + -1");
match expression {
Expression::Add(add_expression) => {
match add_expression.lhs() {
Expression::Binary(binary_expression) => {
assert!(matches!(binary_expression.op(), BinaryOperation::Add));
match binary_expression.lhs() {
Expression::Integer(integer_literal) => {
assert_eq!(integer_literal.value(), 1);
}
_ => panic!("Expected integer literal"),
}
match add_expression.rhs() {
match binary_expression.rhs() {
Expression::Negative(negative_expression) => {
match negative_expression.operand() {
Expression::Integer(integer_literal) => {
@ -1082,14 +1198,15 @@ mod concrete_tests {
fn simple_subtract() {
let expression = assert_expression("1 - 1");
match expression {
Expression::Subtract(subtract_expression) => {
match subtract_expression.lhs() {
Expression::Binary(binary_expression) => {
assert!(matches!(binary_expression.op(), BinaryOperation::Subtract));
match binary_expression.lhs() {
Expression::Integer(integer_literal) => {
assert_eq!(integer_literal.value(), 1);
}
_ => panic!("Expected integer literal"),
}
match subtract_expression.rhs() {
match binary_expression.rhs() {
Expression::Integer(integer_literal) => {
assert_eq!(integer_literal.value(), 1);
}

View File

@ -1,7 +1,7 @@
use crate::ast::ir_builder::IrBuilder;
use crate::ast::ir_util::get_or_init_field_pointer_variable;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_get_field_ref::IrGetFieldRef;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_read_field::IrReadField;
use crate::ir::ir_statement::IrStatement;
@ -79,34 +79,6 @@ impl ExpressibleSymbol {
todo!()
}
ExpressibleSymbol::Field(field_symbol) => {
// This following should work because blocks are flat in the ir; if a variable is
// defined in the ir block from this point forward, it's available to all subsequent
// blocks.
if !builder
.field_pointer_variables()
.contains_key(field_symbol.borrow().declared_name())
{
let field_ref_variable = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
field_symbol.borrow().type_info(),
);
let as_rc = Rc::new(RefCell::new(field_ref_variable));
let to_insert = as_rc.clone();
let self_parameter_or_variable = builder.self_parameter_or_variable().clone();
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
as_rc,
IrOperation::GetFieldRef(IrGetFieldRef::new(
self_parameter_or_variable.clone(),
field_symbol.borrow().field_index(),
)),
)));
builder
.field_pointer_variables_mut()
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
}
// now we need to read the field into a variable and return an expression pointing
// to that variable
let read_destination = IrVariable::new_vr(
@ -116,11 +88,7 @@ impl ExpressibleSymbol {
);
let read_destination_as_rc = Rc::new(RefCell::new(read_destination));
let ir_read_field = IrReadField::new(
builder
.field_pointer_variables()
.get(field_symbol.borrow().declared_name())
.unwrap()
.clone(),
get_or_init_field_pointer_variable(builder, field_symbol).clone(),
);
builder
.current_block_mut()

View File

@ -42,6 +42,11 @@ pub enum TokenKind {
RightArrow,
Plus,
Minus,
Star,
Slash,
Modulo,
LeftShift,
RightShift,
Class,
Dot,
SelfKw,

View File

@ -248,6 +248,48 @@ mod e2e_tests {
assert_eq!(o.fields().len(), 1);
assert_eq!(o.fields()[0].unwrap_int(), 42);
}
#[test]
fn simple_assign() {
assert_result(
"
fn assign() -> Int
let mut x = 21
x = x + x
x
end
",
"assign",
&vec![],
Value::Int(42),
);
}
#[test]
fn assign_field() {
let context = prepare_context(
"
class Foo
mut bar = 21
ctor(_bar: Int)
bar = _bar
end
end
fn foo() -> Foo
Foo(42)
end
",
);
let result = get_result(&context, "foo", &vec![]);
assert!(result.is_some());
let value = result.unwrap();
assert!(matches!(value, Value::Object(_)));
let o = value.unwrap_object().borrow();
assert_eq!(o.fields().len(), 1);
assert_eq!(o.fields()[0].unwrap_int(), 42);
}
}
#[cfg(test)]

11
examples/assign_field.dm Normal file
View File

@ -0,0 +1,11 @@
class Foo
mut bar = 21
ctor(_bar: Int)
bar = _bar
end
end
fn main() -> Foo
Foo(42)
end