feat: typecheck while loops
This commit is contained in:
parent
d4f34b62e2
commit
7091c81201
@ -28,6 +28,7 @@
|
||||
- [x] Typecheck arrays
|
||||
- [x] Typecheck if/else if/else
|
||||
- [x] Typecheck for loops
|
||||
- [x] Typecheck while loops
|
||||
|
||||
|
||||
## v0.1.1
|
||||
|
@ -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(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,3 +5,4 @@ pub mod expression;
|
||||
pub mod for_loop;
|
||||
pub mod function_declaration;
|
||||
pub mod top_level_declaration;
|
||||
pub mod while_loop;
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
src/semantic/checks/while_loop.rs
Normal file
36
src/semantic/checks/while_loop.rs
Normal 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(())
|
||||
}
|
||||
}
|
@ -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]))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user