diff --git a/src/interpreter.rs b/src/interpreter.rs index d2c4d88..15ebcef 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -106,6 +106,7 @@ impl Interpreter { body, } => { let arity = parameters.len(); + let body = body.clone(); let closure = move |parent_environment: Rc>, arguments: &Vec| @@ -119,7 +120,17 @@ impl Interpreter { .define(String::from(¶meters[i].lexeme), argument.clone()); } - closure_interpreter.interpret_statements(body.clone())?; + for i in 0..(body.len()) { + closure_interpreter.interpret_statements(vec![body[i].clone()])?; + + if let Statement::Return { + keyword: _, + value: _, + } = &body[i] + { + return closure_interpreter.environment.borrow_mut().get("return"); + } + } Ok(LiteralValue::Nil) }; @@ -133,8 +144,15 @@ impl Interpreter { }, ); } - Statement::Return { keyword, value } => { - todo!() + Statement::Return { keyword: _, value } => { + let response = match value { + Some(val) => val.evaluate(self.environment.clone())?, + _ => LiteralValue::Nil, + }; + + self.environment + .borrow_mut() + .define(String::from("return"), response); } }; } diff --git a/src/tests/cases/fun_empty_return.lox b/src/tests/cases/fun_empty_return.lox new file mode 100644 index 0000000..7989941 --- /dev/null +++ b/src/tests/cases/fun_empty_return.lox @@ -0,0 +1,10 @@ + var a=0; + +fun printA(a) { + print a; + return; +} + +var b = printA(a); + +print b; diff --git a/src/tests/cases/funreturn.lox b/src/tests/cases/funreturn.lox new file mode 100644 index 0000000..5890c4f --- /dev/null +++ b/src/tests/cases/funreturn.lox @@ -0,0 +1,5 @@ +fun add(a,b) { + return a+b; +} + +print add(2,3); diff --git a/src/tests/expression_tests.rs b/src/tests/expression_tests.rs index 7386d6d..c6bb208 100644 --- a/src/tests/expression_tests.rs +++ b/src/tests/expression_tests.rs @@ -435,8 +435,8 @@ mod tests { sources .iter() .map(|source| { - let closure = move |parent_environment: Rc>, - arguments: &Vec| + let closure = move |_parent_environment: Rc>, + _arguments: &Vec| -> Result { Ok(LiteralValue::IntValue(2)) }; diff --git a/src/tests/interpreter_tests.rs b/src/tests/interpreter_tests.rs index 7b269d1..ed3f76d 100644 --- a/src/tests/interpreter_tests.rs +++ b/src/tests/interpreter_tests.rs @@ -297,7 +297,7 @@ mod tests { } #[test] - fn expression_with_function_statement__test() { + fn expression_with_function_statement_test() { let source = " var a=0; @@ -337,4 +337,79 @@ mod tests { Ok(LiteralValue::Nil) ); } + + #[test] + fn test_function_with_return() { + let source = " + var a=0; + + fun addOne(a) { + return a + 1; + } + + var b = addOne(a); + "; + let mut scanner = Scanner::new(source); + let tokens = scanner.scan_tokens().unwrap(); + + let mut parser = Parser::new(tokens); + let statements = parser.parse().unwrap(); + + let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); + let result = interpreter.interpret_statements(statements); + + assert!(result.is_ok()); + + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 3 + ); + assert_eq!( + interpreter.environment.borrow().get("a"), + Ok(LiteralValue::IntValue(0)) + ); + assert_eq!( + interpreter.environment.borrow().get("b"), + Ok(LiteralValue::IntValue(1)) + ); + } + + #[test] + fn test_function_with_empty_return() { + let source = " + var a=0; + + fun printA(a) { + print a; + return; + } + + var b = printA(a); + "; + let mut scanner = Scanner::new(source); + let tokens = scanner.scan_tokens().unwrap(); + + let mut parser = Parser::new(tokens); + let statements = parser.parse().unwrap(); + + let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); + let result = interpreter.interpret_statements(statements); + + assert!(result.is_ok()); + + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 3 + ); + assert_eq!( + interpreter.environment.borrow().get("a"), + Ok(LiteralValue::IntValue(0)) + ); + assert_eq!( + interpreter.environment.borrow().get("b"), + Ok(LiteralValue::Nil) + ); + } } diff --git a/src/tests/main_tests.rs b/src/tests/main_tests.rs index 820365f..2a751a0 100644 --- a/src/tests/main_tests.rs +++ b/src/tests/main_tests.rs @@ -86,6 +86,25 @@ mod tests { assert_eq!(lines[0], "3"); } + #[test] + fn function_with_return() { + let lines = test_file("./src/tests/cases/funreturn.lox"); + + assert_eq!(lines.len(), 1); + + assert_eq!(lines[0], "5"); + } + + #[test] + fn function_with_empty_return() { + let lines = test_file("./src/tests/cases/fun_empty_return.lox"); + + assert_eq!(lines.len(), 2); + + assert_eq!(lines[0], "0"); + assert_eq!(lines[1], "nil"); + } + fn test_file(file_path: &str) -> Vec { let output = Command::new("cargo") .args(["run", file_path])