From 054fd32e8a2d59fdae899df07aba681d78f2afa4 Mon Sep 17 00:00:00 2001 From: Champii Date: Thu, 2 Jun 2022 19:12:19 +0200 Subject: [PATCH] Add return keyword --- src/lib/ast/tree.rs | 10 ++++++++++ src/lib/codegen/codegen_context.rs | 13 +++++++++++-- src/lib/hir/tree.rs | 15 +++++++++++++++ src/lib/parser/mod.rs | 5 ++++- src/lib/testcases/basic/early_return/main.rk | 4 ++++ src/lib/testcases/basic/early_return/main.rk.out | 1 + .../testcases/basic/early_return/main.rk.stdout | 0 src/lib/tests.rs | 4 ++++ 8 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 src/lib/testcases/basic/early_return/main.rk create mode 100644 src/lib/testcases/basic/early_return/main.rk.out create mode 100644 src/lib/testcases/basic/early_return/main.rk.stdout diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index 2b2c91fe..1f53aef2 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -468,11 +468,21 @@ impl Expression { } } + #[allow(dead_code)] + pub fn is_return(&self) -> bool { + matches!(&self, Expression::Return(_)) + } + #[allow(dead_code)] pub fn new_unary(unary: UnaryExpr) -> Expression { Expression::UnaryExpr(unary) } + #[allow(dead_code)] + pub fn new_return(expr: Expression) -> Expression { + Expression::Return(Box::new(expr)) + } + #[allow(dead_code)] pub fn new_binop(unary: UnaryExpr, operator: Operator, expr: Expression) -> Expression { Expression::BinopExpr(unary, operator, Box::new(expr)) diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index bcee76ec..4f669e54 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -322,9 +322,17 @@ impl<'a> CodegenContext<'a> { builder.position_at_end(basic_block); - let stmt = body + let first_return_idx = body .stmts .iter() + .position(|s| s.is_return()) + .unwrap_or(body.stmts.len()); + + let stmts = body.stmts.iter().take(first_return_idx + 1); + + // FIXME: Add warning here for unreachable statements + + let stmt = stmts .map(|stmt| self.lower_stmt(stmt, builder)) .last() .unwrap()?; @@ -545,7 +553,8 @@ impl<'a> CodegenContext<'a> { ExpressionKind::Return(expr) => { let val = self.lower_expression(expr, builder)?; - builder.build_return(Some(&val.as_basic_value_enum())); + // This is disabled because this is handled in lower_body + // builder.build_return(Some(&val.as_basic_value_enum())); val } diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index 099450ee..f76f1b3a 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -337,6 +337,13 @@ impl Statement { StatementKind::For(f) => f.get_hir_id(), } } + + pub fn is_return(&self) -> bool { + match &*self.kind { + StatementKind::Expression(expr) => expr.is_return(), + _ => false, + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -516,6 +523,14 @@ impl Expression { panic!("Not a literal"); } } + + pub fn is_return(&self) -> bool { + if let ExpressionKind::Return(_) = &*self.kind { + true + } else { + false + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 58c0d76a..8f8228ae 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -668,6 +668,10 @@ pub fn parse_assign_left_side(input: Parser) -> Res { pub fn parse_expression(input: Parser) -> Res { alt(( + map( + preceded(terminated(tag("return"), space1), parse_expression), + Expression::new_return, + ), map( tuple(( parse_unary, @@ -681,7 +685,6 @@ pub fn parse_expression(input: Parser) -> Res { map(parse_native_operator, |(op, id1, id2)| { Expression::new_native_operator(op, id1, id2) }), - // TODO: Return ))(input) } diff --git a/src/lib/testcases/basic/early_return/main.rk b/src/lib/testcases/basic/early_return/main.rk new file mode 100644 index 00000000..d17ac8b2 --- /dev/null +++ b/src/lib/testcases/basic/early_return/main.rk @@ -0,0 +1,4 @@ +main = + let a = 42 + return a + 28 diff --git a/src/lib/testcases/basic/early_return/main.rk.out b/src/lib/testcases/basic/early_return/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/early_return/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/early_return/main.rk.stdout b/src/lib/testcases/basic/early_return/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 33e5afc8..71b3fa14 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -106,6 +106,10 @@ fn testcases_basic_simple_struct_main() { run("testcases/basic/simple_struct/main.rk", include_str!("testcases/basic/simple_struct/main.rk"), include_str!("testcases/basic/simple_struct/main.rk.out"), include_str!("testcases/basic/simple_struct/main.rk.stdout")); } #[test] +fn testcases_basic_early_return_main() { + run("testcases/basic/early_return/main.rk", include_str!("testcases/basic/early_return/main.rk"), include_str!("testcases/basic/early_return/main.rk.out"), include_str!("testcases/basic/early_return/main.rk.stdout")); +} +#[test] fn testcases_basic_bool_false_main() { run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out"), include_str!("testcases/basic/bool_false/main.rk.stdout")); }