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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
I32(i32),
|
Number(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -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 => {
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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!"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user