Browse Source

Add basic conditionals; remove semicolons

github-actions
Garrit Franke 3 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 :: () { main :: () {
let num = 10; let num = 10
print(fib(num)); print(fib(num))
} }
fib :: (n) { fib :: (n) {
if (n <= 1) { 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 :: () { main :: () {
return greet("Garrit"); return greet("Garrit")
} }
greet :: (name) { greet :: (name) {
return "Hello " + name; return "Hello " + name
} }

2
examples/hello_world.sb

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

12
examples/playground.sb

@ -1,3 +1,11 @@
main :: () { 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::Return(ret) => generate_return(ret),
Statement::Declare(_, _) => todo!(), Statement::Declare(_, _) => todo!(),
Statement::Exp(val) => generate_expression(val), 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!(), 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 { fn generate_function_call(func: String, args: Vec<Expression>) -> String {
let formatted_args = args let formatted_args = args
.into_iter() .into_iter()

12
src/parser/mod.rs

@ -200,6 +200,7 @@ impl Parser {
let state = match &token.kind { let state = match &token.kind {
TokenKind::Keyword(Keyword::Let) => self.parse_declare(), TokenKind::Keyword(Keyword::Let) => self.parse_declare(),
TokenKind::Keyword(Keyword::Return) => self.parse_return(), TokenKind::Keyword(Keyword::Return) => self.parse_return(),
TokenKind::Keyword(Keyword::If) => self.parse_conditional_statement(),
TokenKind::Identifier(_) => { TokenKind::Identifier(_) => {
let ident = self.match_identifier()?; let ident = self.match_identifier()?;
if let Ok(_) = self.peek_token(TokenKind::BraceOpen) { if let Ok(_) = self.peek_token(TokenKind::BraceOpen) {
@ -213,7 +214,6 @@ impl Parser {
TokenKind::Literal(_) => Ok(Statement::Exp(self.parse_expression()?)), TokenKind::Literal(_) => Ok(Statement::Exp(self.parse_expression()?)),
_ => return Err(self.make_error(TokenKind::Unknown, token)), _ => return Err(self.make_error(TokenKind::Unknown, token)),
}; };
self.match_token(TokenKind::SemiColon)?;
state 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. /// In some occurences a complex expression has been evaluated before a binary operation is encountered.
/// The following expression is one such example: /// 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() { fn test_parse_function_with_return() {
let raw = " let raw = "
main :: () { main :: () {
return 1; return 1
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -22,10 +22,10 @@ fn test_parse_function_with_return() {
} }
#[test] #[test]
fn test_parse_missing_semicolon() { fn test_parse_redundant_semicolon() {
let raw = " let raw = "
main :: () { main :: () {
return 1 return 1;
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -36,7 +36,7 @@ fn test_parse_missing_semicolon() {
#[test] #[test]
fn test_parse_no_function_context() { fn test_parse_no_function_context() {
let raw = " let raw = "
let x = 1; let x = 1
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string())); let tree = parse(tokens, Some(raw.to_string()));
@ -47,13 +47,13 @@ fn test_parse_no_function_context() {
fn test_parse_multiple_functions() { fn test_parse_multiple_functions() {
let raw = " let raw = "
foo :: () { foo :: () {
let x = 2; let x = 2
return x; return x
} }
bar :: () { bar :: () {
let y = 5; let y = 5
return y; return y
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -65,8 +65,8 @@ fn test_parse_multiple_functions() {
fn test_parse_variable_declaration() { fn test_parse_variable_declaration() {
let raw = " let raw = "
main :: () { main :: () {
let x = 1; let x = 1
return x; return x
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -78,7 +78,7 @@ fn test_parse_variable_declaration() {
fn test_parse_function_with_args() { fn test_parse_function_with_args() {
let raw = " let raw = "
main :: (foo) { main :: (foo) {
return foo; return foo
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -90,11 +90,11 @@ fn test_parse_function_with_args() {
fn test_parse_function_call() { fn test_parse_function_call() {
let raw = " let raw = "
main :: (foo) { main :: (foo) {
foo(); foo()
} }
foo :: () { foo :: () {
foo(2); foo(2)
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -106,11 +106,11 @@ fn test_parse_function_call() {
fn test_parse_return_function_call() { fn test_parse_return_function_call() {
let raw = " let raw = "
main :: () { main :: () {
return fib(2); return fib(2)
} }
fib :: () { fib :: () {
return fib(2); return fib(2)
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -122,11 +122,11 @@ fn test_parse_return_function_call() {
fn test_parse_function_call_multiple_arguments() { fn test_parse_function_call_multiple_arguments() {
let raw = " let raw = "
main :: () { main :: () {
fib(1, 2, 3); fib(1, 2, 3)
} }
fib :: () { fib :: () {
return 2; return 2
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -138,11 +138,11 @@ fn test_parse_function_call_multiple_arguments() {
fn test_parse_nexted_function_call() { fn test_parse_nexted_function_call() {
let raw = " let raw = "
main :: () { main :: () {
fib(fib(2), 2); fib(fib(2), 2)
} }
fib :: (n) { fib :: (n) {
return 2; return 2
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -154,7 +154,7 @@ fn test_parse_nexted_function_call() {
fn test_parse_basic_ops() { fn test_parse_basic_ops() {
let raw = " let raw = "
main :: () { main :: () {
return 2 * 5; return 2 * 5
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -166,7 +166,7 @@ fn test_parse_basic_ops() {
fn test_parse_compound_ops() { fn test_parse_compound_ops() {
let raw = " let raw = "
main :: () { main :: () {
2 * 5 / 3; 2 * 5 / 3
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -178,7 +178,7 @@ fn test_parse_compound_ops() {
fn test_parse_compound_ops_with_function_call() { fn test_parse_compound_ops_with_function_call() {
let raw = " let raw = "
main :: () { main :: () {
return 2 * fib(1) / 3; return 2 * fib(1) / 3
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -190,7 +190,7 @@ fn test_parse_compound_ops_with_function_call() {
fn test_parse_compound_ops_with_strings() { fn test_parse_compound_ops_with_strings() {
let raw = " let raw = "
main :: () { main :: () {
return 2 * \"Hello\"; return 2 * \"Hello\"
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -202,7 +202,7 @@ fn test_parse_compound_ops_with_strings() {
fn test_parse_compound_ops_with_identifier() { fn test_parse_compound_ops_with_identifier() {
let raw = " let raw = "
main :: (n) { main :: (n) {
return 2 * n; return 2 * n
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -215,7 +215,7 @@ fn test_parse_compound_ops_with_identifier() {
fn test_parse_compound_ops_with_identifier_first() { fn test_parse_compound_ops_with_identifier_first() {
let raw = " let raw = "
main :: (n) { main :: (n) {
return n * 2; return n * 2
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);
@ -227,7 +227,7 @@ fn test_parse_compound_ops_with_identifier_first() {
fn test_parse_compound_ops_return() { fn test_parse_compound_ops_return() {
let raw = " let raw = "
main :: (n) { main :: (n) {
return 2 * n; return 2 * n
} }
"; ";
let tokens = tokenize(raw); let tokens = tokenize(raw);

Loading…
Cancel
Save