had to handle negation of signed integers

This commit is contained in:
gluax 2022-05-04 14:50:33 -07:00
parent 2c252f7878
commit 67fd130c0c
4 changed files with 124 additions and 26 deletions

View File

@ -39,7 +39,7 @@ fn return_incorrect_type(t1: Option<Type>, t2: Option<Type>, expected: Option<Ty
} }
impl<'a> TypeChecker<'a> { impl<'a> TypeChecker<'a> {
pub(crate) fn compare_expr_type(&self, expr: &Expression, expected: Option<Type>, span: &Span) -> Option<Type> { pub(crate) fn compare_expr_type(&mut self, expr: &Expression, expected: Option<Type>, span: &Span) -> Option<Type> {
match expr { match expr {
Expression::Identifier(ident) => { Expression::Identifier(ident) => {
if let Some(var) = self.symbol_table.lookup_variable(&ident.name) { if let Some(var) = self.symbol_table.lookup_variable(&ident.name) {
@ -55,11 +55,95 @@ impl<'a> TypeChecker<'a> {
ValueExpression::Boolean(_, _) => Some(self.assert_type(Type::Boolean, expected, value.span())), ValueExpression::Boolean(_, _) => Some(self.assert_type(Type::Boolean, expected, value.span())),
ValueExpression::Char(_) => Some(self.assert_type(Type::Char, expected, value.span())), ValueExpression::Char(_) => Some(self.assert_type(Type::Char, expected, value.span())),
ValueExpression::Field(_, _) => Some(self.assert_type(Type::Field, expected, value.span())), ValueExpression::Field(_, _) => Some(self.assert_type(Type::Field, expected, value.span())),
ValueExpression::Integer(type_, _, _) => { ValueExpression::Integer(type_, str_content, _) => {
match type_ {
IntegerType::I8 => {
let int = if self.negate {
self.negate = false;
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i8>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", value.span()).into());
}
}
IntegerType::I16 => {
let int = if self.negate {
self.negate = false;
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i16>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", value.span()).into());
}
}
IntegerType::I32 => {
let int = if self.negate {
self.negate = false;
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i32>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", value.span()).into());
}
}
IntegerType::I64 => {
let int = if self.negate {
self.negate = false;
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i64>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", value.span()).into());
}
}
IntegerType::I128 => {
let int = if self.negate {
self.negate = false;
format!("-{str_content}")
} else {
str_content.clone()
};
if int.parse::<i128>().is_err() {
self.handler
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", value.span()).into());
}
}
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", value.span()).into()),
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", value.span()).into()),
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", value.span()).into()),
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", value.span()).into()),
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
.handler
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", value.span()).into()),
_ => {}
}
Some(self.assert_type(Type::IntegerType(*type_), expected, value.span())) Some(self.assert_type(Type::IntegerType(*type_), expected, value.span()))
} }
ValueExpression::Group(_) => Some(self.assert_type(Type::Group, expected, value.span())), ValueExpression::Group(_) => Some(self.assert_type(Type::Group, expected, value.span())),
ValueExpression::String(_, _) => None, ValueExpression::String(_, _) => unreachable!("String types are not reachable"),
}, },
Expression::Binary(binary) => match binary.op { Expression::Binary(binary) => match binary.op {
BinaryOperation::And | BinaryOperation::Or => { BinaryOperation::And | BinaryOperation::Or => {
@ -163,19 +247,25 @@ impl<'a> TypeChecker<'a> {
self.compare_expr_type(&unary.inner, expected, unary.inner.span()) self.compare_expr_type(&unary.inner, expected, unary.inner.span())
} }
UnaryOperation::Negate => { UnaryOperation::Negate => {
/* match expected { // -128i8
// -(-128i16 + 3i16) = 125i16
match expected.as_ref() {
Some(
Type::IntegerType( Type::IntegerType(
IntegerType::I8 IntegerType::I8
| IntegerType::I16 | IntegerType::I16
| IntegerType::I32 | IntegerType::I32
| IntegerType::I64 | IntegerType::I64
| IntegerType::I128, | IntegerType::I128,
) => {}, )
Type::Field | Type::Group => {} | Type::Field
_ => self.handler.emit_err( | Type::Group,
TypeCheckerError::type_is_not_negatable(expected.clone(), unary.inner.span()).into(), ) => self.negate = !self.negate,
), Some(t) => self
} */ .handler
.emit_err(TypeCheckerError::type_is_not_negatable(t, unary.inner.span()).into()),
_ => {}
};
self.compare_expr_type(&unary.inner, expected, unary.inner.span()) self.compare_expr_type(&unary.inner, expected, unary.inner.span())
} }
}, },

View File

@ -25,9 +25,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// statements should always have some parent block // statements should always have some parent block
let parent = self.parent.unwrap(); let parent = self.parent.unwrap();
if let Some(func) = self.symbol_table.lookup_fn(&parent) { // Would never be None.
self.compare_expr_type(&input.expression, Some(func.output.clone()), input.expression.span()); let func_output_type = self.symbol_table.lookup_fn(&parent).map(|f| f.output.clone());
} self.compare_expr_type(&input.expression, func_output_type, input.expression.span());
VisitResult::VisitChildren VisitResult::VisitChildren
} }
@ -59,7 +59,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
fn visit_assign(&mut self, input: &'a AssignStatement) -> VisitResult { fn visit_assign(&mut self, input: &'a AssignStatement) -> VisitResult {
let var_name = &input.assignee.identifier.name; let var_name = &input.assignee.identifier.name;
if let Some(var) = self.symbol_table.lookup_variable(var_name) { let var_type = if let Some(var) = self.symbol_table.lookup_variable(var_name) {
match &var.declaration { match &var.declaration {
Declaration::Const => self Declaration::Const => self
.handler .handler
@ -70,11 +70,17 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
_ => {} _ => {}
} }
self.compare_expr_type(&input.value, Some(var.type_.clone()), input.value.span()); Some(var.type_.clone())
} else { } else {
self.handler.emit_err( self.handler.emit_err(
TypeCheckerError::unknown_sym("variable", &input.assignee.identifier.name, &input.assignee.span).into(), TypeCheckerError::unknown_sym("variable", &input.assignee.identifier.name, &input.assignee.span).into(),
) );
None
};
if var_type.is_some() {
self.compare_expr_type(&input.value, var_type, input.value.span());
} }
VisitResult::VisitChildren VisitResult::VisitChildren

View File

@ -24,6 +24,7 @@ pub struct TypeChecker<'a> {
pub(crate) symbol_table: &'a mut SymbolTable<'a>, pub(crate) symbol_table: &'a mut SymbolTable<'a>,
pub(crate) handler: &'a Handler, pub(crate) handler: &'a Handler,
pub(crate) parent: Option<Symbol>, pub(crate) parent: Option<Symbol>,
pub(crate) negate: bool,
} }
const ARITHMATIC_TYPES: &[Type] = &[ const ARITHMATIC_TYPES: &[Type] = &[
@ -74,6 +75,7 @@ impl<'a> TypeChecker<'a> {
symbol_table, symbol_table,
handler, handler,
parent: None, parent: None,
negate: false,
} }
} }

View File

@ -123,12 +123,12 @@ create_messages!(
help: None, help: None,
} }
/// For when a type is does not exist. /// For when an integer is not in a valid range.
@formatted @formatted
unknown_type { invalid_int_value {
args: (), args: (value: impl Display, type_: impl Display),
msg: format!( msg: format!(
"The type", "The value {value} is not a valid `{type_}`",
), ),
help: None, help: None,
} }