141 lines
6.1 KiB
Rust
141 lines
6.1 KiB
Rust
// TODO: move this into ir, not parser
|
|
use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type};
|
|
use crate::common::{CompilerMsg, CompilerOutput};
|
|
|
|
impl IRUProgram {
|
|
pub fn validate(&self) -> CompilerOutput {
|
|
let mut output = CompilerOutput::new();
|
|
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
|
self.validate_fn(&f.instructions, &fd.ret, &mut output, false);
|
|
}
|
|
output
|
|
}
|
|
|
|
pub fn validate_fn(
|
|
&self,
|
|
instructions: &[IRUInstrInst],
|
|
ret: &Type,
|
|
output: &mut CompilerOutput,
|
|
breakable: bool,
|
|
) {
|
|
for i in instructions {
|
|
match &i.i {
|
|
IRUInstruction::Mv { dest, src } => {
|
|
let dest = self.get_var(dest.id);
|
|
let src = self.get_var(src.id);
|
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
|
}
|
|
IRUInstruction::Ref { dest, src } => todo!(),
|
|
IRUInstruction::LoadData { dest, src } => {
|
|
let dest = self.get_var(dest.id);
|
|
let src = self.get_data(*src);
|
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
|
}
|
|
IRUInstruction::LoadSlice { dest, src } => {
|
|
let dest = self.get_var(dest.id);
|
|
let src = self.get_data(*src);
|
|
let Type::Array(srcty, ..) = &src.ty else {
|
|
todo!()
|
|
};
|
|
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
|
|
}
|
|
IRUInstruction::LoadFn { dest, src } => todo!(),
|
|
IRUInstruction::Call { dest, f, args } => {
|
|
let destty = &self.get_var(dest.id).ty;
|
|
let f = self.get_var(f.id);
|
|
let Type::Fn { args: argtys, ret } = &f.ty else {
|
|
todo!()
|
|
};
|
|
output.check_assign(self, ret, destty, dest.span);
|
|
if args.len() != argtys.len() {
|
|
output.err(CompilerMsg {
|
|
msg: "Wrong number of arguments to function".to_string(),
|
|
spans: vec![dest.span],
|
|
});
|
|
}
|
|
for (argv, argt) in args.iter().zip(argtys) {
|
|
let dest = self.get_var(argv.id);
|
|
output.check_assign(self, argt, &dest.ty, argv.span);
|
|
}
|
|
}
|
|
IRUInstruction::AsmBlock { instructions, args } => {
|
|
// TODO
|
|
}
|
|
IRUInstruction::Ret { src } => {
|
|
let srcty = &self.get_var(src.id).ty;
|
|
output.check_assign(self, srcty, ret, src.span);
|
|
}
|
|
IRUInstruction::Construct { dest, fields } => {
|
|
let dest_def = self.get_var(dest.id);
|
|
let tyid = match dest_def.ty {
|
|
Type::Concrete(id) => id,
|
|
_ => {
|
|
output.err(CompilerMsg {
|
|
msg: "uhh type is not struct".to_string(),
|
|
spans: vec![dest.span],
|
|
});
|
|
continue;
|
|
}
|
|
};
|
|
let def = self.get_struct(tyid);
|
|
for (name, field) in &def.fields {
|
|
if let Some(var) = fields.get(name) {
|
|
let ety = &self.get_var(var.id).ty;
|
|
output.check_assign(self, &field.ty, ety, var.span);
|
|
} else {
|
|
output.err(CompilerMsg {
|
|
msg: format!("field '{name}' missing from struct"),
|
|
spans: vec![dest.span],
|
|
});
|
|
}
|
|
}
|
|
for name in fields.keys() {
|
|
if !def.fields.contains_key(name) {
|
|
output.err(CompilerMsg {
|
|
msg: format!("field '{name}' not in struct"),
|
|
spans: vec![dest.span],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
IRUInstruction::Access { dest, src, field } => {
|
|
let dest_def = self.get_var(dest.id);
|
|
let src_def = self.get_var(src.id);
|
|
let tyid = match src_def.ty {
|
|
Type::Concrete(id) => id,
|
|
_ => {
|
|
output.err(CompilerMsg {
|
|
msg: "uhh type is not struct".to_string(),
|
|
spans: vec![dest.span],
|
|
});
|
|
continue;
|
|
}
|
|
};
|
|
let def = self.get_struct(tyid);
|
|
let field = def.fields.get(field).expect(
|
|
"already validated during parse lowering... probably shouldn't be?",
|
|
);
|
|
output.check_assign(self, &field.ty, &dest_def.ty, i.span);
|
|
}
|
|
IRUInstruction::If { cond, body } => {
|
|
let cond = self.get_var(cond.id);
|
|
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span);
|
|
self.validate_fn(body, ret, output, breakable);
|
|
}
|
|
IRUInstruction::Loop { body } => {
|
|
self.validate_fn(body, ret, output, true);
|
|
}
|
|
IRUInstruction::Break => {
|
|
if !breakable {
|
|
output.err(CompilerMsg {
|
|
msg: "Can't break here (outside of loop)".to_string(),
|
|
spans: vec![i.span],
|
|
});
|
|
}
|
|
// TODO
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|