From 94a3e34776eea78669e362f5d6278b3e9929feb9 Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Sat, 6 Feb 2021 21:33:57 +0100 Subject: [PATCH] feat: break and continue --- TODO | 2 +- examples/playground.sb | 11 +++++++++-- src/generator/c.rs | 2 ++ src/generator/js.rs | 10 ++++++++++ src/lexer/mod.rs | 2 ++ src/parser/node_type.rs | 2 ++ src/parser/rules.rs | 12 ++++++++++++ src/parser/tests.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 78 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index 95bc756..66f427e 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ # Bugs +- Generated nested expressions should include braces # Cleanups - Improve error reporting (See ./util/string_util::highlight_position_in_file) @@ -7,7 +8,6 @@ # Features - Nested arrays like [[1, 2, 3], [1, 2, 3]] -- Break and Continue keywords - Type inference - Multi-file support - Argument overloading diff --git a/examples/playground.sb b/examples/playground.sb index 84d1e07..e7a49a3 100644 --- a/examples/playground.sb +++ b/examples/playground.sb @@ -1,4 +1,11 @@ fn main() { - let x = (1 + 2 * (3 + 2)) - println(x) + let arr = [1, 2, 3] + + for x in arr { + if x == 2 { + break + } else { + println(x) + } + } } \ No newline at end of file diff --git a/src/generator/c.rs b/src/generator/c.rs index e3b2e85..7b1ba2f 100644 --- a/src/generator/c.rs +++ b/src/generator/c.rs @@ -115,6 +115,8 @@ fn generate_statement(statement: Statement) -> String { Statement::Block(_) => generate_block(statement), Statement::While(expr, body) => generate_while_loop(expr, *body), Statement::For(ident, expr, body) => todo!(), + Statement::Continue => todo!(), + Statement::Break => todo!(), }; format!("{}\n", state) diff --git a/src/generator/js.rs b/src/generator/js.rs index a034c18..91525bd 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -90,6 +90,8 @@ fn generate_statement(statement: Statement) -> String { Statement::Block(_) => generate_block(statement, None), Statement::While(expr, body) => generate_while_loop(expr, *body), Statement::For(ident, expr, body) => generate_for_loop(ident, expr, *body), + Statement::Continue => generate_continue(), + Statement::Break => generate_break(), }; format!("{};\n", state) @@ -140,6 +142,14 @@ fn generate_for_loop(ident: Variable, expr: Expression, body: Statement) -> Stri out_str } +fn generate_break() -> String { + "break;\n".into() +} + +fn generate_continue() -> String { + "continue;\n".into() +} + fn generate_array(elements: Vec) -> String { let mut out_str = String::from("["); diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index f280650..d3f6eb1 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -335,6 +335,8 @@ impl Cursor<'_> { c if c == "while" => Keyword::While, c if c == "for" => Keyword::For, c if c == "in" => Keyword::In, + c if c == "break" => Keyword::Break, + c if c == "continue" => Keyword::Continue, _ => Keyword::Unknown, } } diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index 10dce50..b3efba3 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -72,6 +72,8 @@ pub enum Statement { If(Expression, Box, Option>), While(Expression, Box), For(Variable, Expression, Box), + Break, + Continue, Exp(Expression), } diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 41ff117..1239a1d 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -122,6 +122,8 @@ impl Parser { TokenKind::Keyword(Keyword::Return) => self.parse_return(), TokenKind::Keyword(Keyword::If) => self.parse_conditional_statement(), TokenKind::Keyword(Keyword::While) => self.parse_while_loop(), + TokenKind::Keyword(Keyword::Break) => self.parse_break(), + TokenKind::Keyword(Keyword::Continue) => self.parse_continue(), TokenKind::Keyword(Keyword::For) => self.parse_for_loop(), TokenKind::Identifier(_) => { let ident = self.match_identifier()?; @@ -305,6 +307,16 @@ impl Parser { Ok(Statement::While(expr, Box::new(body))) } + fn parse_break(&mut self) -> Result { + self.match_keyword(Keyword::Break)?; + Ok(Statement::Break) + } + + fn parse_continue(&mut self) -> Result { + self.match_keyword(Keyword::Continue)?; + Ok(Statement::Continue) + } + fn parse_for_loop(&mut self) -> Result { self.match_keyword(Keyword::For)?; diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 0ac88c3..d4049b9 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -706,3 +706,43 @@ fn test_simple_nested_expression() { let tree = parse(tokens, Some(raw.to_string())); assert!(tree.is_ok()); } + +#[test] +fn test_continue() { + let raw = " + fn main() { + let arr = [1, 2, 3] + + for x in arr { + if x == 2 { + continue + } else { + println(x) + } + } + } + "; + let tokens = tokenize(raw); + let tree = parse(tokens, Some(raw.to_string())); + assert!(tree.is_ok()); +} + +#[test] +fn test_break() { + let raw = " + fn main() { + let arr = [1, 2, 3] + + for x in arr { + if x == 2 { + break + } else { + println(x) + } + } + } + "; + let tokens = tokenize(raw); + let tree = parse(tokens, Some(raw.to_string())); + assert!(tree.is_ok()); +}