deimos-lang/dmc-lib/src/ast/call.rs
2026-03-08 01:27:09 -06:00

161 lines
5.3 KiB
Rust

use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::diagnostic::Diagnostic;
use crate::ir::ir_call::IrCall;
use crate::ir::ir_expression::IrExpression;
use crate::source_range::SourceRange;
use crate::symbol::{ExpressibleSymbol, FunctionSymbol};
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use std::cell::RefCell;
use std::rc::Rc;
pub struct Call {
callee: Box<Expression>,
arguments: Vec<Expression>,
source_range: SourceRange,
}
impl Call {
pub fn new(callee: Expression, arguments: Vec<Expression>, source_range: SourceRange) -> Self {
Self {
callee: callee.into(),
arguments,
source_range,
}
}
pub fn callee(&self) -> &Expression {
&self.callee
}
pub fn arguments(&self) -> Vec<&Expression> {
self.arguments.iter().collect()
}
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![];
diagnostics.append(&mut self.callee.gather_declared_names(symbol_table));
for argument in &mut self.arguments {
diagnostics.append(&mut argument.gather_declared_names(symbol_table));
}
diagnostics
}
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![];
diagnostics.append(&mut self.callee.check_name_usages(symbol_table));
for argument in &mut self.arguments {
diagnostics.append(&mut argument.check_name_usages(symbol_table));
}
diagnostics
}
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![];
diagnostics.append(&mut self.callee.type_check(symbol_table));
for argument in &mut self.arguments {
diagnostics.append(&mut argument.type_check(symbol_table));
}
// check that callee is callable
let function_symbol = match self.callee.type_info() {
TypeInfo::Function(function_symbol) => function_symbol,
_ => {
diagnostics.push(Diagnostic::new(
"Receiver is not callable",
self.callee.source_range().start(),
self.callee.source_range().end(),
));
return diagnostics;
}
};
// check arguments length
let function_symbol_ref = function_symbol.borrow();
let parameters = function_symbol_ref.parameters();
if parameters.len() != self.arguments.len() {
diagnostics.push(Diagnostic::new(
&format!(
"Wrong number of arguments; expected {} but found {}",
parameters.len(),
self.arguments.len()
),
self.source_range.start(),
self.source_range.end(),
));
}
if !diagnostics.is_empty() {
return diagnostics;
}
// check argument types
for i in 0..parameters.len() {
let parameter = &parameters[i];
let argument = &self.arguments[i];
if !parameter
.borrow()
.type_info()
.is_assignable_from(&argument.type_info())
{
diagnostics.push(Diagnostic::new(
&format!(
"Mismatched types; expected {} but found {}",
parameter.borrow().type_info(),
argument.type_info()
),
argument.source_range().start(),
argument.source_range().end(),
))
}
}
diagnostics
}
pub fn type_info(&self) -> TypeInfo {
match self.callee.type_info() {
TypeInfo::Function(function_symbol) => function_symbol.borrow().return_type(),
_ => panic!(),
}
}
fn get_callee_symbol(&self) -> Rc<RefCell<FunctionSymbol>> {
match self.callee() {
Expression::Identifier(identifier) => {
let expressible_symbol = identifier.expressible_symbol();
match expressible_symbol {
ExpressibleSymbol::Function(function_symbol) => function_symbol.clone(),
_ => panic!("Calling things other than functions not yet supported."),
}
}
_ => panic!("Calling things other than identifiers not yet supported."),
}
}
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrCall {
let arguments: Vec<IrExpression> = self
.arguments
.iter()
.map(|argument| argument.to_ir(builder, symbol_table))
.inspect(|expression| {
if expression.is_none() {
panic!("Attempt to pass non-expression")
}
})
.map(Option::unwrap)
.collect();
let function_symbol = self.get_callee_symbol();
IrCall::new(
function_symbol.borrow().name_owned(),
arguments,
function_symbol.clone(),
)
}
pub fn source_range(&self) -> &SourceRange {
&self.source_range
}
}