diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eb891..cff4b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - [x] Typecheck arrays - [x] Typecheck if/else if/else - [x] Typecheck for loops +- [x] Typecheck while loops ## v0.1.1 diff --git a/src/semantic/checks/expression.rs b/src/semantic/checks/expression.rs index e154fc2..452eb03 100644 --- a/src/semantic/checks/expression.rs +++ b/src/semantic/checks/expression.rs @@ -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(()) + }, } } } diff --git a/src/semantic/checks/mod.rs b/src/semantic/checks/mod.rs index 89c49a2..bd623e5 100644 --- a/src/semantic/checks/mod.rs +++ b/src/semantic/checks/mod.rs @@ -5,3 +5,4 @@ pub mod expression; pub mod for_loop; pub mod function_declaration; pub mod top_level_declaration; +pub mod while_loop; diff --git a/src/semantic/checks/top_level_declaration.rs b/src/semantic/checks/top_level_declaration.rs index 878cda4..353b54d 100644 --- a/src/semantic/checks/top_level_declaration.rs +++ b/src/semantic/checks/top_level_declaration.rs @@ -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), } } } diff --git a/src/semantic/checks/while_loop.rs b/src/semantic/checks/while_loop.rs new file mode 100644 index 0000000..22ad9e6 --- /dev/null +++ b/src/semantic/checks/while_loop.rs @@ -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(()) + } +} diff --git a/src/semantic/types/expression.rs b/src/semantic/types/expression.rs index a85b2d1..39db649 100644 --- a/src/semantic/types/expression.rs +++ b/src/semantic/types/expression.rs @@ -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])) } }