diff --git a/reid/src/ast/mod.rs b/reid/src/ast/mod.rs index 72154ba..b7ca580 100644 --- a/reid/src/ast/mod.rs +++ b/reid/src/ast/mod.rs @@ -13,7 +13,7 @@ pub enum TypeKind { #[derive(Debug, Clone)] pub enum Literal { - I32(i32), + Number(u64), } #[derive(Debug, Clone)] diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index df057f1..171313d 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -58,7 +58,7 @@ impl Parse for PrimaryExpression { Expression(Kind::VariableName(v.clone()), stream.get_range().unwrap()) } Token::DecimalValue(v) => Expression( - Kind::Literal(Literal::I32(v.parse().unwrap())), + Kind::Literal(Literal::Number(v.parse().unwrap())), stream.get_range().unwrap(), ), Token::ParenOpen => { diff --git a/reid/src/ast/process.rs b/reid/src/ast/process.rs index a963274..43bfc7e 100644 --- a/reid/src/ast/process.rs +++ b/reid/src/ast/process.rs @@ -240,7 +240,7 @@ impl ast::BinaryOperator { impl ast::Literal { fn mir(&self) -> mir::Literal { match *self { - ast::Literal::I32(v) => mir::Literal::I32(v), + ast::Literal::Number(v) => mir::Literal::Vague(mir::VagueLiteral::Number(v)), } } } diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index c411415..58fec08 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -297,6 +297,7 @@ impl mir::Literal { InstructionKind::Constant(match *self { mir::Literal::I32(val) => ConstValue::I32(val), mir::Literal::I16(val) => ConstValue::I16(val), + mir::Literal::Vague(_) => panic!("Got vague literal!"), }) } } diff --git a/reid/src/lib.rs b/reid/src/lib.rs index 72e3108..84c86cc 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -53,6 +53,7 @@ pub fn compile(source: &str) -> Result { dbg!(&mir_module); let state = mir_module.typecheck(); + dbg!(&mir_module); dbg!(&state); if !state.errors.is_empty() { return Err(ReidError::TypeCheckErrors(state.errors)); diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 2090ebe..f638a1a 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -51,6 +51,8 @@ pub enum TypeKind { pub enum VagueType { #[error("Unknown")] Unknown, + #[error("Number")] + Number, } impl TypeKind { @@ -88,6 +90,12 @@ impl TypeKind { pub enum Literal { I32(i32), I16(i16), + Vague(VagueLiteral), +} + +#[derive(Debug, Clone, Copy)] +pub enum VagueLiteral { + Number(u64), } impl Literal { @@ -95,6 +103,7 @@ impl Literal { match self { Literal::I32(_) => TypeKind::I32, Literal::I16(_) => TypeKind::I16, + Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number), } } } diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index e8a99ed..ab6646e 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -175,7 +175,9 @@ impl FunctionDefinition { let return_type = self.return_type.clone(); let inferred = match &mut self.kind { - FunctionDefinitionKind::Local(block, _) => block.typecheck(state, scope), + FunctionDefinitionKind::Local(block, _) => { + block.typecheck(state, scope, Some(return_type), Some(return_type)) + } FunctionDefinitionKind::Extern => Ok(Vague(Unknown)), }; @@ -188,13 +190,24 @@ impl FunctionDefinition { } impl Block { - fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result { + fn typecheck( + &mut self, + state: &mut State, + scope: &mut Scope, + soft_hint: Option, + hard_hint: Option, + ) -> Result { let mut scope = scope.inner(); for statement in &mut self.statements { match &mut statement.0 { StmtKind::Let(variable_reference, expression) => { - let res = expression.typecheck(state, &mut scope); + let res = expression.typecheck( + state, + &mut scope, + Some(variable_reference.0), + hard_hint, + ); // If expression resolution itself was erronous, resolve as // Unknown. @@ -224,14 +237,14 @@ impl Block { } StmtKind::Import(_) => todo!(), StmtKind::Expression(expression) => { - let res = expression.typecheck(state, &mut scope); + let res = expression.typecheck(state, &mut scope, soft_hint, hard_hint); state.ok(res, expression.1); } } } if let Some((_, expr)) = &mut self.return_expression { - let res = expr.typecheck(state, &mut scope); + let res = expr.typecheck(state, &mut scope, hard_hint, hard_hint); Ok(state.or_else(res, Vague(Unknown), expr.1)) } else { Ok(Void) @@ -240,7 +253,13 @@ impl Block { } impl Expression { - fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result { + fn typecheck( + &mut self, + state: &mut State, + scope: &mut Scope, + soft_hint: Option, + hard_hint: Option, + ) -> Result { match &mut self.0 { ExprKind::Variable(var_ref) => { let existing = state.or_else( @@ -262,15 +281,19 @@ impl Expression { Ok(var_ref.0) } - ExprKind::Literal(literal) => Ok(literal.as_type()), + ExprKind::Literal(literal) => { + *literal = literal.try_coerce(soft_hint)?; + Ok(literal.as_type()) + } ExprKind::BinOp(op, lhs, rhs) => { // TODO make sure lhs and rhs can actually do this binary // operation once relevant - let lhs_res = lhs.typecheck(state, scope); - let rhs_res = rhs.typecheck(state, scope); + let lhs_res = lhs.typecheck(state, scope, soft_hint, hard_hint); // TODO let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1); + let rhs_res = rhs.typecheck(state, scope, Some(lhs_type), hard_hint); // TODO let rhs_type = state.or_else(rhs_res, Vague(Unknown), rhs.1); - lhs_type.binop_type(&op, &rhs_type) + let res = lhs_type.binop_type(&op, &rhs_type)?; + Ok(res) } ExprKind::FunctionCall(function_call) => { let true_function = scope @@ -289,7 +312,8 @@ impl Expression { for (param, true_param_t) in function_call.parameters.iter_mut().zip(true_params_iter) { - let param_res = param.typecheck(state, scope); + let param_res = + param.typecheck(state, scope, Some(true_param_t), hard_hint); let param_t = state.or_else(param_res, Vague(Unknown), param.1); state.ok(param_t.collapse_into(&true_param_t), param.1); } @@ -306,21 +330,39 @@ impl Expression { } ExprKind::If(IfExpression(cond, lhs, rhs)) => { // TODO make sure cond_res is Boolean here - let cond_res = cond.typecheck(state, scope); + let cond_res = cond.typecheck(state, scope, Some(Bool), hard_hint); 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, soft_hint, hard_hint); let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta); let rhs_type = if let Some(rhs) = rhs { - let res = rhs.typecheck(state, scope); + let res = rhs.typecheck(state, scope, soft_hint, hard_hint); state.or_else(res, Vague(Unknown), rhs.meta) } else { Vague(Unknown) }; lhs_type.collapse_into(&rhs_type) } - ExprKind::Block(block) => block.typecheck(state, scope), + ExprKind::Block(block) => block.typecheck(state, scope, soft_hint, hard_hint), + } + } +} + +impl Literal { + fn try_coerce(self, hint: Option) -> Result { + if let Some(hint) = hint { + use Literal as L; + use VagueLiteral as VagueL; + Ok(match (self, hint) { + (L::I32(_), I32) => self, + (L::I16(_), I16) => self, + (L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32), + (L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16), + _ => Err(ErrorKind::TypesIncompatible(self.as_type(), hint))?, + }) + } else { + Ok(self) } } }