deimos-lang/dmc-lib/src/ast/negative_expression.rs

176 lines
5.7 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_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::class_symbol::ClassSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
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 init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.operand.init_scopes(symbol_table, container_scope);
}
pub fn check_field_initializer_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.operand
.check_field_initializer_names(symbol_table, class_symbol)
}
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.operand
.check_constructor_local_names(symbol_table, class_symbol)
}
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.operand
.check_method_local_names(symbol_table, class_symbol)
}
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
self.operand.check_static_fn_local_names(symbol_table)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.operand.type_check(symbol_table, types_table)?;
let type_info = self.operand.type_info(symbol_table, types_table);
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,
types_table: &TypesTable,
) -> IrExpression {
let operand_as_ir = self
.operand
.to_ir_expression(builder, symbol_table, types_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::Binary(IrBinaryOperation::new(
IrExpression::Parameter(parameter),
rhs,
IrBinaryOperator::Multiply,
));
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::Binary(IrBinaryOperation::new(
IrExpression::Variable(variable),
rhs,
IrBinaryOperator::Multiply,
));
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()
}
}