From 9b68ecb614ebc841a9318ee4183af373339f0bf5 Mon Sep 17 00:00:00 2001 From: sofia Date: Mon, 7 Jul 2025 23:25:07 +0300 Subject: [PATCH] Add some security checks, typecheck for condition to be a boolean --- reid/examples/reid/fibonacci.reid | 2 +- reid/src/codegen.rs | 28 +++++++++++++++++++++------- reid/src/mir/mod.rs | 25 +++++++++++++++++++++++++ reid/src/mir/typecheck.rs | 11 +++-------- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/reid/examples/reid/fibonacci.reid b/reid/examples/reid/fibonacci.reid index b287c6f..a7f597f 100644 --- a/reid/examples/reid/fibonacci.reid +++ b/reid/examples/reid/fibonacci.reid @@ -1,6 +1,6 @@ // Main fn main() -> i32 { - return fibonacci(3); + return (fibonacci(3) < 5) + 5; } // Fibonacci diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index a7572f2..c411415 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -183,6 +183,7 @@ impl mir::Expression { pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option { match &self.0 { mir::ExprKind::Variable(varref) => { + varref.0.is_known().expect("variable type unknown"); let v = scope .stack_values .get(&varref.1) @@ -191,6 +192,17 @@ impl mir::Expression { } mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)), mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => { + lhs_exp + .return_type() + .expect("No ret type in lhs?") + .is_known() + .expect("lhs ret type is unknown"); + rhs_exp + .return_type() + .expect("No ret type in rhs?") + .is_known() + .expect("rhs ret type is unknown"); + let lhs = lhs_exp.codegen(scope).expect("lhs has no return value"); let rhs = rhs_exp.codegen(scope).expect("rhs has no return value"); Some(match binop { @@ -202,16 +214,17 @@ impl mir::Expression { } mir::BinaryOperator::Mult => todo!(), mir::BinaryOperator::And => todo!(), - mir::BinaryOperator::Logic(l) => { - let ret_type = lhs_exp.return_type().expect("No ret type in lhs?"); - scope - .block - .build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs)) - .unwrap() - } + mir::BinaryOperator::Logic(l) => scope + .block + .build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs)) + .unwrap(), }) } mir::ExprKind::FunctionCall(call) => { + call.return_type + .is_known() + .expect("function return type unknown"); + let params = call .parameters .iter() @@ -293,6 +306,7 @@ impl TypeKind { match &self { TypeKind::I32 => Type::I32, TypeKind::I16 => Type::I16, + TypeKind::Bool => Type::Bool, TypeKind::Void => panic!("Void not a supported type"), TypeKind::Vague(_) => panic!("Tried to compile a vague type!"), } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 8af706d..2090ebe 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -39,6 +39,8 @@ pub enum TypeKind { I32, #[error("i16")] I16, + #[error("bool")] + Bool, #[error("void")] Void, #[error(transparent)] @@ -51,12 +53,35 @@ pub enum VagueType { Unknown, } +impl TypeKind { + pub fn is_known(&self) -> Result { + if let TypeKind::Vague(vague) = self { + Err(*vague) + } else { + Ok(*self) + } + } +} + impl TypeKind { pub fn signed(&self) -> bool { match self { + TypeKind::Void => false, + TypeKind::Vague(_) => false, _ => true, } } + + pub fn is_maths(&self) -> bool { + use TypeKind::*; + match &self { + I32 => true, + I16 => true, + Bool => true, + Vague(_) => false, + Void => false, + } + } } #[derive(Debug, Clone, Copy)] diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index fc3e43e..65aa18a 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -171,12 +171,10 @@ impl FunctionDefinition { } let return_type = self.return_type.clone(); - dbg!(&return_type); let inferred = match &self.kind { FunctionDefinitionKind::Local(block, _) => block.typecheck(state, scope), FunctionDefinitionKind::Extern => Ok(Vague(Unknown)), }; - dbg!(&inferred); match inferred { Ok(t) => try_collapse(&return_type, &t) @@ -295,7 +293,8 @@ impl Expression { ExprKind::If(IfExpression(cond, lhs, rhs)) => { // TODO make sure cond_res is Boolean here let cond_res = cond.typecheck(state, scope); - state.ok(cond_res, cond.1); + let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1); + state.ok(cond_t.collapse_into(&Bool), cond.1); let lhs_res = lhs.typecheck(state, scope); let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta); @@ -314,11 +313,7 @@ impl Expression { impl TypeKind { fn assert_known(&self) -> Result { - if let Vague(vague) = self { - Err(ErrorKind::TypeIsVague(*vague)) - } else { - Ok(*self) - } + self.is_known().map_err(ErrorKind::TypeIsVague) } }