Make AST contain only abstract Numbers
This commit is contained in:
parent
95b3ffe8ef
commit
9b9fcd4ec4
@ -13,7 +13,7 @@ pub enum TypeKind {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Literal {
|
||||
I32(i32),
|
||||
Number(u64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -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 => {
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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!"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
|
||||
dbg!(&mir_module);
|
||||
|
||||
let state = mir_module.typecheck();
|
||||
dbg!(&mir_module);
|
||||
dbg!(&state);
|
||||
if !state.errors.is_empty() {
|
||||
return Err(ReidError::TypeCheckErrors(state.errors));
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<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();
|
||||
|
||||
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<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 {
|
||||
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<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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user