From 1a95efb5d856956fb5da1ddd102991882adc4ad4 Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Mon, 7 Dec 2020 12:27:26 +0100 Subject: [PATCH] Add basic conditionals; remove semicolons --- examples/fib.sb | 8 +++---- examples/greeter.sb | 4 ++-- examples/hello_world.sb | 2 +- examples/playground.sb | 12 ++++++++-- src/generator/js.rs | 20 +++++++++++++++- src/parser/mod.rs | 12 +++++++++- src/parser/tests.rs | 52 ++++++++++++++++++++--------------------- 7 files changed, 73 insertions(+), 37 deletions(-) diff --git a/examples/fib.sb b/examples/fib.sb index e6c6e76..367147f 100644 --- a/examples/fib.sb +++ b/examples/fib.sb @@ -1,12 +1,12 @@ main :: () { - let num = 10; - print(fib(num)); + let num = 10 + print(fib(num)) } fib :: (n) { if (n <= 1) { - return n; + return n } - return fib(n-1) + fib(n-2); + return fib(n-1) + fib(n-2) } \ No newline at end of file diff --git a/examples/greeter.sb b/examples/greeter.sb index 644a2d8..8405136 100644 --- a/examples/greeter.sb +++ b/examples/greeter.sb @@ -1,7 +1,7 @@ main :: () { - return greet("Garrit"); + return greet("Garrit") } greet :: (name) { - return "Hello " + name; + return "Hello " + name } \ No newline at end of file diff --git a/examples/hello_world.sb b/examples/hello_world.sb index 74a78e3..e78a028 100644 --- a/examples/hello_world.sb +++ b/examples/hello_world.sb @@ -1,4 +1,4 @@ main :: () { - return "Hello World"; + return "Hello World" } diff --git a/examples/playground.sb b/examples/playground.sb index 1edbc52..998f24e 100644 --- a/examples/playground.sb +++ b/examples/playground.sb @@ -1,3 +1,11 @@ main :: () { - -} \ No newline at end of file + return fib(3) + fib() +} + +fib :: (n) { + if n { + return n + } + + return 1 +} \ No newline at end of file diff --git a/src/generator/js.rs b/src/generator/js.rs index d8174b1..27af2a5 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -43,7 +43,9 @@ fn generate_statement(statement: Statement) -> String { Statement::Return(ret) => generate_return(ret), Statement::Declare(_, _) => todo!(), Statement::Exp(val) => generate_expression(val), - Statement::If(_, _, _) => todo!(), + Statement::If(expr, if_state, else_state) => { + generate_conditional(expr, *if_state, else_state.map(|x| *x)) + } Statement::While(_, _) => todo!(), } } @@ -59,6 +61,22 @@ fn generate_expression(expr: Expression) -> String { } } +fn generate_conditional( + expr: Expression, + if_state: Statement, + else_state: Option, +) -> String { + let expr_str = generate_expression(expr); + let if_str = generate_statement(if_state); + + let mut outcome = format!("if ({})", expr_str); + + outcome += "{\n"; + outcome += &if_str; + outcome += "}"; + outcome +} + fn generate_function_call(func: String, args: Vec) -> String { let formatted_args = args .into_iter() diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a70a7cd..0989c9c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -200,6 +200,7 @@ impl Parser { let state = match &token.kind { TokenKind::Keyword(Keyword::Let) => self.parse_declare(), TokenKind::Keyword(Keyword::Return) => self.parse_return(), + TokenKind::Keyword(Keyword::If) => self.parse_conditional_statement(), TokenKind::Identifier(_) => { let ident = self.match_identifier()?; if let Ok(_) = self.peek_token(TokenKind::BraceOpen) { @@ -213,7 +214,6 @@ impl Parser { TokenKind::Literal(_) => Ok(Statement::Exp(self.parse_expression()?)), _ => return Err(self.make_error(TokenKind::Unknown, token)), }; - self.match_token(TokenKind::SemiColon)?; state } @@ -303,6 +303,16 @@ impl Parser { } } + fn parse_conditional_statement(&mut self) -> Result { + self.match_keyword(Keyword::If)?; + let condition = self.parse_expression()?; + self.match_token(TokenKind::CurlyBracesOpen)?; + let state = self.parse_statement()?; + self.match_token(TokenKind::CurlyBracesClose)?; + + Ok(Statement::If(condition, Box::new(state), None)) + } + /// In some occurences a complex expression has been evaluated before a binary operation is encountered. /// The following expression is one such example: /// ``` diff --git a/src/parser/tests.rs b/src/parser/tests.rs index ec3aeac..157e3d5 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -13,7 +13,7 @@ fn test_parse_empty_function() { fn test_parse_function_with_return() { let raw = " main :: () { - return 1; + return 1 } "; let tokens = tokenize(raw); @@ -22,10 +22,10 @@ fn test_parse_function_with_return() { } #[test] -fn test_parse_missing_semicolon() { +fn test_parse_redundant_semicolon() { let raw = " main :: () { - return 1 + return 1; } "; let tokens = tokenize(raw); @@ -36,7 +36,7 @@ fn test_parse_missing_semicolon() { #[test] fn test_parse_no_function_context() { let raw = " - let x = 1; + let x = 1 "; let tokens = tokenize(raw); let tree = parse(tokens, Some(raw.to_string())); @@ -47,13 +47,13 @@ fn test_parse_no_function_context() { fn test_parse_multiple_functions() { let raw = " foo :: () { - let x = 2; - return x; + let x = 2 + return x } bar :: () { - let y = 5; - return y; + let y = 5 + return y } "; let tokens = tokenize(raw); @@ -65,8 +65,8 @@ fn test_parse_multiple_functions() { fn test_parse_variable_declaration() { let raw = " main :: () { - let x = 1; - return x; + let x = 1 + return x } "; let tokens = tokenize(raw); @@ -78,7 +78,7 @@ fn test_parse_variable_declaration() { fn test_parse_function_with_args() { let raw = " main :: (foo) { - return foo; + return foo } "; let tokens = tokenize(raw); @@ -90,11 +90,11 @@ fn test_parse_function_with_args() { fn test_parse_function_call() { let raw = " main :: (foo) { - foo(); + foo() } foo :: () { - foo(2); + foo(2) } "; let tokens = tokenize(raw); @@ -106,11 +106,11 @@ fn test_parse_function_call() { fn test_parse_return_function_call() { let raw = " main :: () { - return fib(2); + return fib(2) } fib :: () { - return fib(2); + return fib(2) } "; let tokens = tokenize(raw); @@ -122,11 +122,11 @@ fn test_parse_return_function_call() { fn test_parse_function_call_multiple_arguments() { let raw = " main :: () { - fib(1, 2, 3); + fib(1, 2, 3) } fib :: () { - return 2; + return 2 } "; let tokens = tokenize(raw); @@ -138,11 +138,11 @@ fn test_parse_function_call_multiple_arguments() { fn test_parse_nexted_function_call() { let raw = " main :: () { - fib(fib(2), 2); + fib(fib(2), 2) } fib :: (n) { - return 2; + return 2 } "; let tokens = tokenize(raw); @@ -154,7 +154,7 @@ fn test_parse_nexted_function_call() { fn test_parse_basic_ops() { let raw = " main :: () { - return 2 * 5; + return 2 * 5 } "; let tokens = tokenize(raw); @@ -166,7 +166,7 @@ fn test_parse_basic_ops() { fn test_parse_compound_ops() { let raw = " main :: () { - 2 * 5 / 3; + 2 * 5 / 3 } "; let tokens = tokenize(raw); @@ -178,7 +178,7 @@ fn test_parse_compound_ops() { fn test_parse_compound_ops_with_function_call() { let raw = " main :: () { - return 2 * fib(1) / 3; + return 2 * fib(1) / 3 } "; let tokens = tokenize(raw); @@ -190,7 +190,7 @@ fn test_parse_compound_ops_with_function_call() { fn test_parse_compound_ops_with_strings() { let raw = " main :: () { - return 2 * \"Hello\"; + return 2 * \"Hello\" } "; let tokens = tokenize(raw); @@ -202,7 +202,7 @@ fn test_parse_compound_ops_with_strings() { fn test_parse_compound_ops_with_identifier() { let raw = " main :: (n) { - return 2 * n; + return 2 * n } "; let tokens = tokenize(raw); @@ -215,7 +215,7 @@ fn test_parse_compound_ops_with_identifier() { fn test_parse_compound_ops_with_identifier_first() { let raw = " main :: (n) { - return n * 2; + return n * 2 } "; let tokens = tokenize(raw); @@ -227,7 +227,7 @@ fn test_parse_compound_ops_with_identifier_first() { fn test_parse_compound_ops_return() { let raw = " main :: (n) { - return 2 * n; + return 2 * n } "; let tokens = tokenize(raw);