Make AST contain only abstract Numbers

This commit is contained in:
Sofia 2025-07-08 00:48:28 +03:00
parent 95b3ffe8ef
commit 9b9fcd4ec4
7 changed files with 71 additions and 18 deletions

View File

@ -13,7 +13,7 @@ pub enum TypeKind {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Literal { pub enum Literal {
I32(i32), Number(u64),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -58,7 +58,7 @@ impl Parse for PrimaryExpression {
Expression(Kind::VariableName(v.clone()), stream.get_range().unwrap()) Expression(Kind::VariableName(v.clone()), stream.get_range().unwrap())
} }
Token::DecimalValue(v) => Expression( Token::DecimalValue(v) => Expression(
Kind::Literal(Literal::I32(v.parse().unwrap())), Kind::Literal(Literal::Number(v.parse().unwrap())),
stream.get_range().unwrap(), stream.get_range().unwrap(),
), ),
Token::ParenOpen => { Token::ParenOpen => {

View File

@ -240,7 +240,7 @@ impl ast::BinaryOperator {
impl ast::Literal { impl ast::Literal {
fn mir(&self) -> mir::Literal { fn mir(&self) -> mir::Literal {
match *self { match *self {
ast::Literal::I32(v) => mir::Literal::I32(v), ast::Literal::Number(v) => mir::Literal::Vague(mir::VagueLiteral::Number(v)),
} }
} }
} }

View File

@ -297,6 +297,7 @@ impl mir::Literal {
InstructionKind::Constant(match *self { InstructionKind::Constant(match *self {
mir::Literal::I32(val) => ConstValue::I32(val), mir::Literal::I32(val) => ConstValue::I32(val),
mir::Literal::I16(val) => ConstValue::I16(val), mir::Literal::I16(val) => ConstValue::I16(val),
mir::Literal::Vague(_) => panic!("Got vague literal!"),
}) })
} }
} }

View File

@ -53,6 +53,7 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
dbg!(&mir_module); dbg!(&mir_module);
let state = mir_module.typecheck(); let state = mir_module.typecheck();
dbg!(&mir_module);
dbg!(&state); dbg!(&state);
if !state.errors.is_empty() { if !state.errors.is_empty() {
return Err(ReidError::TypeCheckErrors(state.errors)); return Err(ReidError::TypeCheckErrors(state.errors));

View File

@ -51,6 +51,8 @@ pub enum TypeKind {
pub enum VagueType { pub enum VagueType {
#[error("Unknown")] #[error("Unknown")]
Unknown, Unknown,
#[error("Number")]
Number,
} }
impl TypeKind { impl TypeKind {
@ -88,6 +90,12 @@ impl TypeKind {
pub enum Literal { pub enum Literal {
I32(i32), I32(i32),
I16(i16), I16(i16),
Vague(VagueLiteral),
}
#[derive(Debug, Clone, Copy)]
pub enum VagueLiteral {
Number(u64),
} }
impl Literal { impl Literal {
@ -95,6 +103,7 @@ impl Literal {
match self { match self {
Literal::I32(_) => TypeKind::I32, Literal::I32(_) => TypeKind::I32,
Literal::I16(_) => TypeKind::I16, Literal::I16(_) => TypeKind::I16,
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
} }
} }
} }

View File

@ -175,7 +175,9 @@ impl FunctionDefinition {
let return_type = self.return_type.clone(); let return_type = self.return_type.clone();
let inferred = match &mut self.kind { 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)), FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
}; };
@ -188,13 +190,24 @@ impl FunctionDefinition {
} }
impl Block { impl Block {
fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result<TypeKind, ErrorKind> { fn typecheck(
&mut self,
state: &mut State,
scope: &mut Scope,
soft_hint: Option<TypeKind>,
hard_hint: Option<TypeKind>,
) -> Result<TypeKind, ErrorKind> {
let mut scope = scope.inner(); let mut scope = scope.inner();
for statement in &mut self.statements { for statement in &mut self.statements {
match &mut statement.0 { match &mut statement.0 {
StmtKind::Let(variable_reference, expression) => { 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 // If expression resolution itself was erronous, resolve as
// Unknown. // Unknown.
@ -224,14 +237,14 @@ impl Block {
} }
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => todo!(),
StmtKind::Expression(expression) => { 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); state.ok(res, expression.1);
} }
} }
} }
if let Some((_, expr)) = &mut self.return_expression { 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)) Ok(state.or_else(res, Vague(Unknown), expr.1))
} else { } else {
Ok(Void) Ok(Void)
@ -240,7 +253,13 @@ impl Block {
} }
impl Expression { impl Expression {
fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result<TypeKind, ErrorKind> { fn typecheck(
&mut self,
state: &mut State,
scope: &mut Scope,
soft_hint: Option<TypeKind>,
hard_hint: Option<TypeKind>,
) -> Result<TypeKind, ErrorKind> {
match &mut self.0 { match &mut self.0 {
ExprKind::Variable(var_ref) => { ExprKind::Variable(var_ref) => {
let existing = state.or_else( let existing = state.or_else(
@ -262,15 +281,19 @@ impl Expression {
Ok(var_ref.0) 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) => { ExprKind::BinOp(op, lhs, rhs) => {
// TODO make sure lhs and rhs can actually do this binary // TODO make sure lhs and rhs can actually do this binary
// operation once relevant // operation once relevant
let lhs_res = lhs.typecheck(state, scope); let lhs_res = lhs.typecheck(state, scope, soft_hint, hard_hint); // TODO
let rhs_res = rhs.typecheck(state, scope);
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1); 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); 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) => { ExprKind::FunctionCall(function_call) => {
let true_function = scope let true_function = scope
@ -289,7 +312,8 @@ impl Expression {
for (param, true_param_t) in for (param, true_param_t) in
function_call.parameters.iter_mut().zip(true_params_iter) 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); let param_t = state.or_else(param_res, Vague(Unknown), param.1);
state.ok(param_t.collapse_into(&true_param_t), 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)) => { 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, Some(Bool), hard_hint);
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1); let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
state.ok(cond_t.collapse_into(&Bool), 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 lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta);
let rhs_type = if let Some(rhs) = rhs { 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) state.or_else(res, Vague(Unknown), rhs.meta)
} else { } else {
Vague(Unknown) Vague(Unknown)
}; };
lhs_type.collapse_into(&rhs_type) 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<TypeKind>) -> Result<Self, ErrorKind> {
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)
} }
} }
} }