diff --git a/CHANGELOG.md b/CHANGELOG.md index 224fec6..15cadd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - [x] Parse conditionals - [x] Parse arrays - [x] Parse for loops +- [x] Parse while loops ## v0.1.1 diff --git a/src/lexic/scanner/identifier.rs b/src/lexic/scanner/identifier.rs index f5a25d1..dc97090 100755 --- a/src/lexic/scanner/identifier.rs +++ b/src/lexic/scanner/identifier.rs @@ -12,7 +12,6 @@ fn str_is_keyword(s: &String) -> Option { "for" => Some(TokenType::FOR), "in" => Some(TokenType::IN), "while" => Some(TokenType::WHILE), - "loop" => Some(TokenType::LOOP), "match" => Some(TokenType::MATCH), "case" => Some(TokenType::CASE), _ => None, diff --git a/src/lexic/token.rs b/src/lexic/token.rs index 0254ff3..9bbe4bf 100755 --- a/src/lexic/token.rs +++ b/src/lexic/token.rs @@ -29,7 +29,6 @@ pub enum TokenType { FOR, IN, WHILE, - LOOP, MATCH, CASE, } diff --git a/src/semantic/checks/top_level_declaration.rs b/src/semantic/checks/top_level_declaration.rs index 0bcfc02..8551a61 100644 --- a/src/semantic/checks/top_level_declaration.rs +++ b/src/semantic/checks/top_level_declaration.rs @@ -23,7 +23,8 @@ impl SemanticCheck for Statement<'_> { Statement::Binding(b) => b.check_semantics(scope), Statement::FnDecl(f) => f.check_semantics(scope), Statement::Conditional(_) => unimplemented!("check conditional"), - Statement::ForLoop(_) => unimplemented!("check for loop"), + Statement::ForLoop(_) => unimplemented!("check for for loop"), + Statement::WhileLoop(_) => unimplemented!("check for while loop"), } } } diff --git a/src/syntax/ast/loops.rs b/src/syntax/ast/loops.rs index 05656e3..6efdb95 100644 --- a/src/syntax/ast/loops.rs +++ b/src/syntax/ast/loops.rs @@ -1,6 +1,6 @@ use crate::lexic::token::Token; -use super::Block; +use super::{Block, Expression}; #[derive(Debug)] pub struct ForLoop<'a> { @@ -13,3 +13,15 @@ pub struct ForLoop<'a> { pub value: &'a Token, pub body: Block<'a>, } + +#[derive(Debug)] +pub struct WhileLoop<'a> { + /// the start position of the + /// `for` keyword + pub loop_start: usize, + /// the position of the closing bracket + pub loop_end: usize, + pub condition: Expression<'a>, + pub body: Block<'a>, +} + diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index 2e45ba3..baccbd5 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -1,7 +1,7 @@ use crate::lexic::token::Token; use self::functions::FunctionCall; -use loops::ForLoop; +use loops::{ForLoop, WhileLoop}; use var_binding::VariableBinding; pub mod functions; @@ -36,6 +36,7 @@ pub enum Statement<'a> { // TODO: Implement conditionals as expressions Conditional(Conditional<'a>), ForLoop(ForLoop<'a>), + WhileLoop(WhileLoop<'a>), } #[derive(Debug)] diff --git a/src/syntax/parsers/mod.rs b/src/syntax/parsers/mod.rs index 8aa291f..5c519c1 100644 --- a/src/syntax/parsers/mod.rs +++ b/src/syntax/parsers/mod.rs @@ -6,3 +6,4 @@ pub mod for_loop; pub mod function_declaration; pub mod module; pub mod statement; +pub mod while_loop; diff --git a/src/syntax/parsers/statement.rs b/src/syntax/parsers/statement.rs index d42f158..18b2409 100644 --- a/src/syntax/parsers/statement.rs +++ b/src/syntax/parsers/statement.rs @@ -2,7 +2,7 @@ use crate::{ lexic::token::Token, syntax::{ ast::{ - loops::ForLoop, var_binding::VariableBinding, Conditional, FunctionDeclaration, + loops::{ForLoop, WhileLoop}, var_binding::VariableBinding, Conditional, FunctionDeclaration, Statement, }, parseable::{Parseable, ParsingError, ParsingResult}, @@ -51,6 +51,13 @@ impl<'a> Parseable<'a> for Statement<'a> { _ => {} } + // Try to parse a while loop + match WhileLoop::try_parse(tokens, current_pos) { + Ok((prod, next)) => return Ok((Statement::WhileLoop(prod), next)), + Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)), + _ => {} + } + // Here nothing was parsed. Err(ParsingError::Unmatched) } diff --git a/src/syntax/parsers/while_loop.rs b/src/syntax/parsers/while_loop.rs new file mode 100644 index 0000000..d898986 --- /dev/null +++ b/src/syntax/parsers/while_loop.rs @@ -0,0 +1,75 @@ +use crate::{ + error_handling::SyntaxError, lexic::token::{Token, TokenType}, syntax::{ + ast::{loops::WhileLoop, Block, Expression, Positionable}, + parseable::{Parseable, ParsingError, ParsingResult}, utils::parse_token_type, + } +}; + +impl<'a> Parseable<'a> for WhileLoop<'a> { + type Item = WhileLoop<'a>; + + fn try_parse(tokens: &'a Vec, current_pos: usize) -> ParsingResult<'a, Self::Item> { + // while keyword + let (while_keyword, next) = match parse_token_type(tokens, current_pos, TokenType::WHILE) { + Ok(tuple) => tuple, + _ => return Err(ParsingError::Unmatched), + }; + + // condition expression + let (condition, next) = match Expression::try_parse(tokens, next) { + Ok(t) => t, + Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)), + Err(ParsingError::Mismatch(e)) => { + return Err(ParsingError::Err(SyntaxError { + error_start: e.position, + error_end: e.get_end_position(), + reason: format!( + "Expected an expression after the `while` keyword, found {}", + e.value + ), + })) + } + Err(ParsingError::Unmatched) => { + return Err(ParsingError::Err(SyntaxError { + error_start: while_keyword.position, + error_end: while_keyword.get_end_position(), + reason: format!("Expected an identifier after the `while` keyword"), + })) + } + }; + + // body + let (body, next) = match Block::try_parse(tokens, next) { + Ok(t) => t, + Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)), + Err(ParsingError::Mismatch(e)) => { + return Err(ParsingError::Err(SyntaxError { + error_start: e.position, + error_end: e.get_end_position(), + reason: format!( + "Expected a block after the condition, found {}", + e.value + ), + })) + } + Err(ParsingError::Unmatched) => { + return Err(ParsingError::Err(SyntaxError { + error_start: while_keyword.position, + error_end: while_keyword.get_end_position(), + reason: format!("Expected a block after the condition"), + })) + } + }; + + // return + + let (_, loop_end) = body.get_position(); + let while_loop = WhileLoop { + loop_start: while_keyword.position, + loop_end, + condition, + body, + }; + Ok((while_loop, next)) + } +}