Browse Source

Add basic conditionals; remove semicolons

github-actions
Garrit Franke 2 years ago
parent
commit
1a95efb5d8
  1. 8
      examples/fib.sb
  2. 4
      examples/greeter.sb
  3. 2
      examples/hello_world.sb
  4. 12
      examples/playground.sb
  5. 20
      src/generator/js.rs
  6. 12
      src/parser/mod.rs
  7. 52
      src/parser/tests.rs

8
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)
}

4
examples/greeter.sb

@ -1,7 +1,7 @@
main :: () {
return greet("Garrit");
return greet("Garrit")
}
greet :: (name) {
return "Hello " + name;
return "Hello " + name
}

2
examples/hello_world.sb

@ -1,4 +1,4 @@
main :: () {
return "Hello World";
return "Hello World"
}

12
examples/playground.sb

@ -1,3 +1,11 @@
main :: () {
}
return fib(3) + fib()
}
fib :: (n) {
if n {
return n
}
return 1
}

20
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<Statement>,
) -> 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<Expression>) -> String {
let formatted_args = args
.into_iter()

12
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<Statement, String> {
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:
/// ```

52
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);

Loading…
Cancel
Save