136 lines
4.0 KiB
Rust
136 lines
4.0 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_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)
|
|
}
|
|
}
|