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> {
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 {
Expression::Identifier(ident) => {
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::Char(_) => Some(self.assert_type(Type::Char, 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()))
}
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 {
BinaryOperation::And | BinaryOperation::Or => {
@ -163,19 +247,25 @@ impl<'a> TypeChecker<'a> {
self.compare_expr_type(&unary.inner, expected, unary.inner.span())
}
UnaryOperation::Negate => {
/* match expected {
Type::IntegerType(
IntegerType::I8
| IntegerType::I16
| IntegerType::I32
| IntegerType::I64
| IntegerType::I128,
) => {},
Type::Field | Type::Group => {}
_ => self.handler.emit_err(
TypeCheckerError::type_is_not_negatable(expected.clone(), unary.inner.span()).into(),
),
} */
// -128i8
// -(-128i16 + 3i16) = 125i16
match expected.as_ref() {
Some(
Type::IntegerType(
IntegerType::I8
| IntegerType::I16
| IntegerType::I32
| IntegerType::I64
| IntegerType::I128,
)
| Type::Field
| Type::Group,
) => 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())
}
},

View File

@ -25,9 +25,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// statements should always have some parent block
let parent = self.parent.unwrap();
if let Some(func) = self.symbol_table.lookup_fn(&parent) {
self.compare_expr_type(&input.expression, Some(func.output.clone()), input.expression.span());
}
// Would never be None.
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
}
@ -59,7 +59,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
fn visit_assign(&mut self, input: &'a AssignStatement) -> VisitResult {
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 {
Declaration::Const => self
.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 {
self.handler.emit_err(
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

View File

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

View File

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