feat: typecheck while loops

master
Araozu 2024-08-29 10:11:05 -05:00
parent d4f34b62e2
commit 7091c81201
6 changed files with 91 additions and 27 deletions

View File

@ -28,6 +28,7 @@
- [x] Typecheck arrays
- [x] Typecheck if/else if/else
- [x] Typecheck for loops
- [x] Typecheck while loops
## v0.1.1

View File

@ -193,7 +193,54 @@ impl SemanticCheck for Expression<'_> {
// After all these checks, we are ok
Ok(())
}
Expression::Array(_) => unimplemented!("check for array"),
Expression::Array(arr) => {
// There is some duplicated logic here with
// the typechecking of an array in the impl
// of the trait Typed
// The first expression found determines the
// type of the array
// TODO: for now an array must have at least 1 element,
// if the array is empty there is no way to know its type.
// TODO: if the array is empty then its
// datatype should be determined by its usage.
if arr.exps.is_empty() {
return Err(MistiError::Semantic(SemanticError {
error_start: arr.start,
error_end: arr.end,
reason: format!(
"An array must have at least 1 element to determine its type. This will be fixed later."
),
}));
}
let mut expressions = arr.exps.iter();
let first_expr = expressions.next().unwrap();
let first_type = first_expr.get_type(scope)?;
// then check that every expression has the same type
for exp in expressions {
let exp_type = exp.get_type(scope)?;
if !exp_type.equals(&first_type) {
// TODO: subtyping
// error, found an item with a diferent datatype
let (error_start, error_end) = exp.get_position();
return Err(MistiError::Semantic(SemanticError {
error_start,
error_end,
reason: format!(
"All elements of an array must have the same datatype. Expected {:?}, got {:?}",
first_type,
exp_type,
),
}));
}
}
Ok(())
},
}
}
}

View File

@ -5,3 +5,4 @@ pub mod expression;
pub mod for_loop;
pub mod function_declaration;
pub mod top_level_declaration;
pub mod while_loop;

View File

@ -24,7 +24,7 @@ impl SemanticCheck for Statement<'_> {
Statement::FnDecl(f) => f.check_semantics(scope),
Statement::Conditional(c) => c.check_semantics(scope),
Statement::ForLoop(f) => f.check_semantics(scope),
Statement::WhileLoop(_) => unimplemented!("check for while loop"),
Statement::WhileLoop(w) => w.check_semantics(scope),
}
}
}

View File

@ -0,0 +1,36 @@
use crate::{
error_handling::{semantic_error::SemanticError, MistiError},
semantic::{
impls::SemanticCheck,
symbol_table::SymbolTable,
types::{Type, Typed},
},
syntax::ast::{loops::WhileLoop, Positionable},
};
impl SemanticCheck for WhileLoop<'_> {
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
// Check condition is a bool
let condition = &self.condition;
let condition_type = condition.get_type(scope)?;
if !condition_type.equals(&Type::Value("Bool".into())) {
let (error_start, error_end) = condition.get_position();
return Err(MistiError::Semantic(SemanticError {
error_start,
error_end,
reason: format!(
"Expected a condition of type Bool, found {:?}",
condition_type
),
}));
}
// TODO: Define scoping rules for while loops
// Check inner block
self.body.check_semantics(scope)?;
Ok(())
}
}

View File

@ -138,31 +138,10 @@ impl Typed for Expression<'_> {
}));
}
let mut expressions = arr.exps.iter();
let first_expr = expressions.next().unwrap();
let first_type = first_expr.get_type(scope)?;
// then check that every expression has the same type
for exp in expressions {
let exp_type = exp.get_type(scope)?;
if !exp_type.equals(&first_type) {
// TODO: subtyping
// error, found an item with a diferent datatype
let (error_start, error_end) = exp.get_position();
return Err(MistiError::Semantic(SemanticError {
error_start,
error_end,
reason: format!(
"All elements of an array must have the same datatype. Expected {:?}, got {:?}",
first_type,
exp_type,
),
}));
}
}
// return the Array type
// Just get the first type and use it
// Checking of the types of every element in the array
// is done by SemanticCheck
let first_type = arr.exps[0].get_type(scope)?;
Ok(Type::Generic("Array".into(), vec![first_type]))
}
}