use slot_arena::SlotArena;
use crate::{
codemap::{Span, Spanned},
diag::SemaDiagnostics,
syntax::ast,
types::{FuncSig, Type},
value::Value,
Context,
};
use super::{scope::Scope, IntermediateExpr, Unit};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Air {
pub funcs: SlotArena<Func>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Expr {
Const(Type, Value),
Call(Type, Box<Call>),
}
impl Expr {
pub fn type_of(&self) -> Type {
match self {
Self::Const(ty, _) => ty.clone(),
Self::Call(ty, _) => ty.clone(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FuncDef {
pub insts: Vec<Stmnt>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Func {
pub signature: FuncSig,
pub signature_span: Option<Span>,
pub extern_name: Option<String>,
pub def: Option<FuncDef>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Return {
pub value: Option<Expr>,
}
impl Return {
pub fn from_ast(
cx: &mut Context,
unit: &mut Unit,
scope: &mut Scope,
stmnt: &ast::Return,
) -> Result<Self, ()> {
let (signature_span, expected_return_type) = {
let func = unit.funcs.get(unit.current_func);
(func.signature_span, func.signature.returns.clone())
};
let value = match &stmnt.value {
Some(value) => Some({
let expr = IntermediateExpr::verify(cx, unit, scope, value)?;
expr.clone().coerce(&expected_return_type).ok_or_else(|| {
cx.return_type_mismatch(
&expected_return_type.name(),
&expr.default_type().expect("must have a type").name(),
stmnt.span(),
signature_span,
)
})?
}),
None => {
cx.return_type_mismatch(
&expected_return_type.name(),
"void",
stmnt.span(),
signature_span,
);
return Err(());
}
};
Ok(Self { value })
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Call {
pub callee: Expr,
pub params: Vec<Expr>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Stmnt {
Return(Return),
Call(Call),
}