Compare commits
5 Commits
7e613b1b90
...
f0c84fe0c8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0c84fe0c8 | ||
|
|
4a0a6b8425 | ||
|
|
f9373a687f | ||
|
|
863c3fef5d | ||
|
|
5a123419bd |
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)]
|
||||
|
||||
223
dmc-lib/src/ast/binary_expression.rs
Normal file
223
dmc-lib/src/ast/binary_expression.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
83
dmc-lib/src/ast/ir_util.rs
Normal file
83
dmc-lib/src/ast/ir_util.rs
Normal 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()
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
43
dmc-lib/src/ast/util.rs
Normal 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)
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
88
dmc-lib/src/ir/ir_binary_operation.rs
Normal file
88
dmc-lib/src/ir/ir_binary_operation.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {}
|
||||
}
|
||||
|
||||
@ -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) {}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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) {}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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)]
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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(",") {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -42,6 +42,11 @@ pub enum TokenKind {
|
||||
RightArrow,
|
||||
Plus,
|
||||
Minus,
|
||||
Star,
|
||||
Slash,
|
||||
Modulo,
|
||||
LeftShift,
|
||||
RightShift,
|
||||
Class,
|
||||
Dot,
|
||||
SelfKw,
|
||||
|
||||
@ -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
11
examples/assign_field.dm
Normal file
@ -0,0 +1,11 @@
|
||||
class Foo
|
||||
mut bar = 21
|
||||
|
||||
ctor(_bar: Int)
|
||||
bar = _bar
|
||||
end
|
||||
end
|
||||
|
||||
fn main() -> Foo
|
||||
Foo(42)
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user