135 lines
4.5 KiB
Rust
135 lines
4.5 KiB
Rust
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_multiply::IrMultiply;
|
|
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 std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
|
|
pub struct NegativeExpression {
|
|
operand: Box<Expression>,
|
|
source_range: SourceRange,
|
|
type_info: Option<TypeInfo>,
|
|
}
|
|
|
|
impl NegativeExpression {
|
|
pub fn new(operand: Expression, source_range: SourceRange) -> Self {
|
|
Self {
|
|
operand: operand.into(),
|
|
source_range,
|
|
type_info: None,
|
|
}
|
|
}
|
|
|
|
pub fn source_range(&self) -> &SourceRange {
|
|
&self.source_range
|
|
}
|
|
|
|
pub fn operand(&self) -> &Expression {
|
|
&self.operand
|
|
}
|
|
|
|
pub fn operand_mut(&mut self) -> &mut Expression {
|
|
&mut self.operand
|
|
}
|
|
|
|
pub fn gather_declared_names(
|
|
&mut self,
|
|
symbol_table: &mut SymbolTable,
|
|
) -> Result<(), Vec<Diagnostic>> {
|
|
self.operand.gather_declared_names(symbol_table)
|
|
}
|
|
|
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
self.operand.check_name_usages(symbol_table)
|
|
}
|
|
|
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
self.operand.type_check(symbol_table)?;
|
|
|
|
let type_info = self.operand.type_info();
|
|
if type_info.can_negate() {
|
|
self.type_info = Some(type_info.negate_result());
|
|
Ok(())
|
|
} else {
|
|
Err(vec![Diagnostic::new(
|
|
&format!("Cannot negate {}", type_info),
|
|
self.source_range.start(),
|
|
self.source_range.end(),
|
|
)])
|
|
}
|
|
}
|
|
|
|
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrExpression {
|
|
let operand_as_ir = self
|
|
.operand
|
|
.to_ir_expression(builder, symbol_table)
|
|
.expect("Attempt to negate non-value expression");
|
|
|
|
match operand_as_ir {
|
|
IrExpression::Parameter(parameter) => {
|
|
let destination = Rc::new(RefCell::new(IrVariable::new_vr(
|
|
builder.new_t_var().into(),
|
|
builder.current_block().id(),
|
|
parameter.type_info(),
|
|
)));
|
|
|
|
let rhs = match parameter.type_info() {
|
|
TypeInfo::Integer => IrExpression::Int(-1),
|
|
TypeInfo::Double => IrExpression::Double(-1.0),
|
|
_ => panic!("Trying to multiply with a non-integer/double"),
|
|
};
|
|
|
|
let operation =
|
|
IrOperation::Multiply(IrMultiply::new(IrExpression::Parameter(parameter), rhs));
|
|
|
|
let assign = IrAssign::new(destination.clone(), operation);
|
|
builder
|
|
.current_block_mut()
|
|
.add_statement(IrStatement::Assign(assign));
|
|
|
|
IrExpression::Variable(destination)
|
|
}
|
|
IrExpression::Variable(variable) => {
|
|
let destination = Rc::new(RefCell::new(IrVariable::new_vr(
|
|
builder.new_t_var().into(),
|
|
builder.current_block().id(),
|
|
variable.borrow().type_info(),
|
|
)));
|
|
|
|
let rhs = match variable.borrow().type_info() {
|
|
TypeInfo::Integer => IrExpression::Int(-1),
|
|
TypeInfo::Double => IrExpression::Double(-1.0),
|
|
_ => panic!("Trying to multiply with a non-integer/double"),
|
|
};
|
|
|
|
let operation =
|
|
IrOperation::Multiply(IrMultiply::new(IrExpression::Variable(variable), rhs));
|
|
|
|
let assign = IrAssign::new(destination.clone(), operation);
|
|
builder
|
|
.current_block_mut()
|
|
.add_statement(IrStatement::Assign(assign));
|
|
|
|
IrExpression::Variable(destination)
|
|
}
|
|
IrExpression::Int(i) => IrExpression::Int(i * -1),
|
|
IrExpression::Double(d) => IrExpression::Double(d * -1.0),
|
|
IrExpression::String(_) => {
|
|
panic!("Attempt to negate IrExpression::String")
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn type_info(&self) -> &TypeInfo {
|
|
self.type_info.as_ref().unwrap()
|
|
}
|
|
}
|