Add some security checks, typecheck for condition to be a boolean
This commit is contained in:
parent
a366d22470
commit
9b68ecb614
@ -1,6 +1,6 @@
|
|||||||
// Main
|
// Main
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
return fibonacci(3);
|
return (fibonacci(3) < 5) + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fibonacci
|
// Fibonacci
|
||||||
|
@ -183,6 +183,7 @@ impl mir::Expression {
|
|||||||
pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
mir::ExprKind::Variable(varref) => {
|
mir::ExprKind::Variable(varref) => {
|
||||||
|
varref.0.is_known().expect("variable type unknown");
|
||||||
let v = scope
|
let v = scope
|
||||||
.stack_values
|
.stack_values
|
||||||
.get(&varref.1)
|
.get(&varref.1)
|
||||||
@ -191,6 +192,17 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
|
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
|
||||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
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 lhs = lhs_exp.codegen(scope).expect("lhs has no return value");
|
||||||
let rhs = rhs_exp.codegen(scope).expect("rhs has no return value");
|
let rhs = rhs_exp.codegen(scope).expect("rhs has no return value");
|
||||||
Some(match binop {
|
Some(match binop {
|
||||||
@ -202,16 +214,17 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
mir::BinaryOperator::Mult => todo!(),
|
mir::BinaryOperator::Mult => todo!(),
|
||||||
mir::BinaryOperator::And => todo!(),
|
mir::BinaryOperator::And => todo!(),
|
||||||
mir::BinaryOperator::Logic(l) => {
|
mir::BinaryOperator::Logic(l) => scope
|
||||||
let ret_type = lhs_exp.return_type().expect("No ret type in lhs?");
|
.block
|
||||||
scope
|
.build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs))
|
||||||
.block
|
.unwrap(),
|
||||||
.build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs))
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mir::ExprKind::FunctionCall(call) => {
|
mir::ExprKind::FunctionCall(call) => {
|
||||||
|
call.return_type
|
||||||
|
.is_known()
|
||||||
|
.expect("function return type unknown");
|
||||||
|
|
||||||
let params = call
|
let params = call
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
@ -293,6 +306,7 @@ impl TypeKind {
|
|||||||
match &self {
|
match &self {
|
||||||
TypeKind::I32 => Type::I32,
|
TypeKind::I32 => Type::I32,
|
||||||
TypeKind::I16 => Type::I16,
|
TypeKind::I16 => Type::I16,
|
||||||
|
TypeKind::Bool => Type::Bool,
|
||||||
TypeKind::Void => panic!("Void not a supported type"),
|
TypeKind::Void => panic!("Void not a supported type"),
|
||||||
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@ pub enum TypeKind {
|
|||||||
I32,
|
I32,
|
||||||
#[error("i16")]
|
#[error("i16")]
|
||||||
I16,
|
I16,
|
||||||
|
#[error("bool")]
|
||||||
|
Bool,
|
||||||
#[error("void")]
|
#[error("void")]
|
||||||
Void,
|
Void,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
@ -51,12 +53,35 @@ pub enum VagueType {
|
|||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypeKind {
|
||||||
|
pub fn is_known(&self) -> Result<TypeKind, VagueType> {
|
||||||
|
if let TypeKind::Vague(vague) = self {
|
||||||
|
Err(*vague)
|
||||||
|
} else {
|
||||||
|
Ok(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
pub fn signed(&self) -> bool {
|
pub fn signed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
TypeKind::Void => false,
|
||||||
|
TypeKind::Vague(_) => false,
|
||||||
_ => true,
|
_ => 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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -171,12 +171,10 @@ impl FunctionDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let return_type = self.return_type.clone();
|
let return_type = self.return_type.clone();
|
||||||
dbg!(&return_type);
|
|
||||||
let inferred = match &self.kind {
|
let inferred = match &self.kind {
|
||||||
FunctionDefinitionKind::Local(block, _) => block.typecheck(state, scope),
|
FunctionDefinitionKind::Local(block, _) => block.typecheck(state, scope),
|
||||||
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
|
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
|
||||||
};
|
};
|
||||||
dbg!(&inferred);
|
|
||||||
|
|
||||||
match inferred {
|
match inferred {
|
||||||
Ok(t) => try_collapse(&return_type, &t)
|
Ok(t) => try_collapse(&return_type, &t)
|
||||||
@ -295,7 +293,8 @@ impl Expression {
|
|||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
// TODO make sure cond_res is Boolean here
|
// TODO make sure cond_res is Boolean here
|
||||||
let cond_res = cond.typecheck(state, scope);
|
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_res = lhs.typecheck(state, scope);
|
||||||
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta);
|
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta);
|
||||||
@ -314,11 +313,7 @@ impl Expression {
|
|||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
||||||
if let Vague(vague) = self {
|
self.is_known().map_err(ErrorKind::TypeIsVague)
|
||||||
Err(ErrorKind::TypeIsVague(*vague))
|
|
||||||
} else {
|
|
||||||
Ok(*self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user