feat: typecheck while loops
This commit is contained in:
parent
d4f34b62e2
commit
7091c81201
@ -28,6 +28,7 @@
|
|||||||
- [x] Typecheck arrays
|
- [x] Typecheck arrays
|
||||||
- [x] Typecheck if/else if/else
|
- [x] Typecheck if/else if/else
|
||||||
- [x] Typecheck for loops
|
- [x] Typecheck for loops
|
||||||
|
- [x] Typecheck while loops
|
||||||
|
|
||||||
|
|
||||||
## v0.1.1
|
## v0.1.1
|
||||||
|
@ -193,7 +193,54 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
// After all these checks, we are ok
|
// After all these checks, we are ok
|
||||||
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 for_loop;
|
||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod top_level_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::FnDecl(f) => f.check_semantics(scope),
|
||||||
Statement::Conditional(c) => c.check_semantics(scope),
|
Statement::Conditional(c) => c.check_semantics(scope),
|
||||||
Statement::ForLoop(f) => f.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();
|
// Just get the first type and use it
|
||||||
let first_expr = expressions.next().unwrap();
|
// Checking of the types of every element in the array
|
||||||
let first_type = first_expr.get_type(scope)?;
|
// is done by SemanticCheck
|
||||||
|
let first_type = arr.exps[0].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
|
|
||||||
Ok(Type::Generic("Array".into(), vec![first_type]))
|
Ok(Type::Generic("Array".into(), vec![first_type]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user