deimos-lang/dmc-lib/src/ast/add_expression.rs
2026-03-09 16:35:32 -05:00

103 lines
3.0 KiB
Rust

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 {}", lhs_type_info, rhs_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
}
}