diff --git a/src/ast/types.rs b/src/ast/types.rs index 777e5e8..e582c52 100644 --- a/src/ast/types.rs +++ b/src/ast/types.rs @@ -102,6 +102,7 @@ pub enum Value { Ref(Ref), Closure { env: EnvName, expr: Box }, PrimitiveFunc(Name), + Return(Box), } /// A mutable variable. diff --git a/src/interpret/interpret.rs b/src/interpret/interpret.rs index 5d09773..0dc7f27 100644 --- a/src/interpret/interpret.rs +++ b/src/interpret/interpret.rs @@ -101,21 +101,29 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result { let mut block_env = expr_env.clone(); - if let Some(last) = statements.iter().try_fold(None, |_, statement| { - let result = eval_statement(&mut block_env, state, statement)?; - match result { - StatementResult::Result(result) => { - Ok::, Error>(Some(result)) + let mut result = ast::UNIT_VALUE; + for statement in statements { + let r = eval_statement(&mut block_env, state, statement)?; + match r { + StatementResult::Result(ast::Value::Return(r)) => { + result = ast::Value::Return(r); + break; } - StatementResult::Return(result) => { - Ok::, Error>(Some(result)) + StatementResult::Return(ast::Value::Return(r)) => { + result = ast::Value::Return(r); + break; + } + StatementResult::Result(r) => { + result = r; + } + StatementResult::Return(r) => { + result = ast::Value::Return(Box::new(r)); + break; } } - })? { - Ok(last) - } else { - Err(Error::LastStatementNotAnExpr(Backtrace::capture())) } + + Ok(result) } ast::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? { ast::Value::Record(record) => Ok(state.variables.get(record.get(&field)?).clone()), @@ -148,7 +156,10 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result Ok(*r), + v => Ok(v), + } } e => Err(Error::NotAFunction(e, Backtrace::capture())), }, diff --git a/src/lib.rs b/src/lib.rs index b5e18b4..3a9b34c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,69 @@ pub mod ast; pub mod interpret; pub mod parser; pub mod runtime; + +pub fn run_main(code: &str) -> Result { + match parser::parse_file(code.into()) { + Err(err) => Err(format!("Error: {err:?}")), + Ok(program) => match interpret::run(program, "main".into(), vec![]) { + Ok(v) => Ok(v), + Err(err) => Err(format!("{}", err)), + }, + } +} + +#[cfg(test)] +mod tests { + use super::run_main; + + #[test] + fn int_108() { + let program = " +let main = fn() { + 108 +} +"; + let result = run_main(program); + insta::assert_debug_snapshot!(result); + } + #[test] + fn let_add_3() { + let program = " +let main = fn() { + let a = 1; + let b = 2; + a + b +} +"; + let result = run_main(program); + insta::assert_debug_snapshot!(result); + } + #[test] + fn let_if_4() { + let program = " +let main = fn() { + let a = 1; + let b = if a > 0 { 3 } else { 5 }; + a + b +} +"; + let result = run_main(program); + insta::assert_debug_snapshot!(result); + } + + #[test] + fn bor_onearm_4() { + let program = " +let main = fn() { + let a = 1; + let b = 2 | 3; + if true { + return a + b; + }; + return a; +} +"; + let result = run_main(program); + insta::assert_debug_snapshot!(result); + } +} diff --git a/src/parser/types.rs b/src/parser/types.rs index c835a2f..ddf780e 100644 --- a/src/parser/types.rs +++ b/src/parser/types.rs @@ -105,7 +105,7 @@ impl Tokens { if let Some(_end) = self.next_if(end) { Ok(Some(result)) } else { - // println!("{:#?}", self); + println!("{:#?}", self); Err(Error::UnexpectedTokenForParser( format!("between end {start:#?} and {end:#?}"), self.next(), diff --git a/src/snapshots/ayin__tests__bor_onearm_4.snap b/src/snapshots/ayin__tests__bor_onearm_4.snap new file mode 100644 index 0000000..c4230c2 --- /dev/null +++ b/src/snapshots/ayin__tests__bor_onearm_4.snap @@ -0,0 +1,9 @@ +--- +source: src/lib.rs +expression: result +--- +Ok( + Int( + 4, + ), +) diff --git a/src/snapshots/ayin__tests__int_108.snap b/src/snapshots/ayin__tests__int_108.snap new file mode 100644 index 0000000..aa607b5 --- /dev/null +++ b/src/snapshots/ayin__tests__int_108.snap @@ -0,0 +1,9 @@ +--- +source: src/lib.rs +expression: result +--- +Ok( + Int( + 108, + ), +) diff --git a/src/snapshots/ayin__tests__let_add_3.snap b/src/snapshots/ayin__tests__let_add_3.snap new file mode 100644 index 0000000..ca8446c --- /dev/null +++ b/src/snapshots/ayin__tests__let_add_3.snap @@ -0,0 +1,9 @@ +--- +source: src/lib.rs +expression: result +--- +Ok( + Int( + 3, + ), +) diff --git a/src/snapshots/ayin__tests__let_if_4.snap b/src/snapshots/ayin__tests__let_if_4.snap new file mode 100644 index 0000000..c4230c2 --- /dev/null +++ b/src/snapshots/ayin__tests__let_if_4.snap @@ -0,0 +1,9 @@ +--- +source: src/lib.rs +expression: result +--- +Ok( + Int( + 4, + ), +)