From c3bd60f475284389219bd443d9f63beb9fa1643e Mon Sep 17 00:00:00 2001 From: me Date: Thu, 25 Dec 2025 23:28:25 +0200 Subject: [PATCH] array access via variables and len --- src/interpret/interpret.rs | 34 +++++++++--- src/interpret/types.rs | 3 ++ src/lib.rs | 52 ++++++++++++++++++- .../ayin__tests__loop_sum_array.snap | 11 ++++ src/snapshots/ayin__tests__map_array.snap | 25 +++++++++ 5 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 src/snapshots/ayin__tests__loop_sum_array.snap create mode 100644 src/snapshots/ayin__tests__map_array.snap diff --git a/src/interpret/interpret.rs b/src/interpret/interpret.rs index 206be30..9cb5bca 100644 --- a/src/interpret/interpret.rs +++ b/src/interpret/interpret.rs @@ -149,10 +149,20 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result match eval_expr(expr_env, state, expr)? { ast::Value::Record(record) => Ok(state.variables.get(record.get(&field)?).clone()), - ast::Value::Vector(vec) if field.0.chars().all(char::is_numeric) => { - let index = field.0.parse::().unwrap(); - Ok(state.variables.get(vec.get(index)?).clone()) - } + ast::Value::Vector(vec) => match field { + _ if field.0.chars().all(char::is_numeric) => { + let index = field.0.parse::().unwrap(); + Ok(state.variables.get(vec.get(index)?).clone()) + } + _ if field.0 == "len" => Ok((vec.0.len() as i32).into()), + _ => match eval_expr(expr_env, state, &ast::Expr::Var(ast::Name(field.0.clone())))? + { + ast::Value::Int(index) => { + Ok(state.variables.get(vec.get(index as usize)?).clone()) + } + v => Err(Error::NotAnInt(v, Backtrace::capture())), + }, + }, v => Err(Error::NotARecord(v, Backtrace::capture())), }, ast::Expr::Var(var) => { @@ -416,10 +426,18 @@ fn eval_expr_shallow( } ast::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? { ast::Value::Record(record) => Ok(ast::Value::Ref(record.get(&field)?.clone())), - ast::Value::Vector(vec) if field.0.chars().all(char::is_numeric) => { - let index = field.0.parse::().unwrap(); - Ok(ast::Value::Ref(vec.get(index)?.clone())) - } + ast::Value::Vector(vec) => match field { + _ if field.0.chars().all(char::is_numeric) => { + let index = field.0.parse::().unwrap(); + Ok(ast::Value::Ref(vec.get(index)?.clone())) + } + _ => match eval_expr(expr_env, state, &ast::Expr::Var(ast::Name(field.0.clone())))? + { + ast::Value::Int(index) => Ok(ast::Value::Ref(vec.get(index as usize)?.clone())), + v => Err(Error::NotAnInt(v, Backtrace::capture())), + }, + }, + v => Err(Error::NotARecord(v, Backtrace::capture())), }, _ => eval_expr(expr_env, state, expr), diff --git a/src/interpret/types.rs b/src/interpret/types.rs index 0a77212..5bad70c 100644 --- a/src/interpret/types.rs +++ b/src/interpret/types.rs @@ -18,6 +18,7 @@ pub enum Error { NotARecord(ast::Value, Backtrace), NotAReference(ast::Expr, ast::Value, Backtrace), NotABoolean(ast::Value, Backtrace), + NotAnInt(ast::Value, Backtrace), OpError(ast::Value, ast::Op, ast::Value, Backtrace), MigrationError(ast::Value, String, Backtrace), ArgumentsMismatch(Backtrace), @@ -39,6 +40,7 @@ impl PartialEq for Error { a1 == a2 && b1 == b2 } (Error::NotABoolean(a1, _), Error::NotABoolean(a2, _)) => a1 == a2, + (Error::NotAnInt(a1, _), Error::NotAnInt(a2, _)) => a1 == a2, (Error::MigrationError(a1, b1, _), Error::MigrationError(a2, b2, _)) => { a1 == a2 && b1 == b2 } @@ -76,6 +78,7 @@ impl std::fmt::Display for Error { "Not a reference. Are you missing a `mut`? {a:?} {b:?}\n{c}" ), Error::NotABoolean(a, b) => write!(f, "Not a boolean {a:?}\n{b}"), + Error::NotAnInt(a, b) => write!(f, "Not an integer {a:?}\n{b}"), Error::ArgumentsMismatch(a) => write!(f, "Arguments mismatch\n{a}"), Error::OpError(a, b, c, d) => write!(f, "Op Error {a:?} {b:?} {c:?}\n{d}"), Error::MigrationError(a, b, c) => { diff --git a/src/lib.rs b/src/lib.rs index 213bdbc..475db5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,9 +76,9 @@ let counter = fn(a,b) { loop { if (a + count) >= b { break - }; + } count = count + 1 - }; + } count } @@ -90,6 +90,54 @@ let main = fn() { insta::assert_debug_snapshot!(result); } + #[test] + fn loop_sum_array() { + let program = " +let summarize = fn(a,b) { + let array = [1,2,3,4,5,6,7,8,9] + let mut sum = 0 + let mut index = 0 + loop { + if index >= array.len { + break + } + sum = sum + array.index + index = index + 1 + } + sum +} + +let main = fn() { + summarize(1,10) +} +"; + let result = run_main(program); + insta::assert_debug_snapshot!(result); + } + + #[test] + fn map_array() { + let program = " +let map = fn(f,array) { + let mut index = 0 + loop { + if index >= array.len { + break + } + array.index = f(array.index) + index = index + 1 + } + array +} + +let main = fn() { + map(fn (x) { x + 1 }, [1,2,3]) +} +"; + let result = run_main(program); + insta::assert_debug_snapshot!(result); + } + #[test] fn direction() { let program = " diff --git a/src/snapshots/ayin__tests__loop_sum_array.snap b/src/snapshots/ayin__tests__loop_sum_array.snap new file mode 100644 index 0000000..12709b0 --- /dev/null +++ b/src/snapshots/ayin__tests__loop_sum_array.snap @@ -0,0 +1,11 @@ +--- +source: src/lib.rs +expression: result +--- +Ok( + Value( + Int( + 45, + ), + ), +) diff --git a/src/snapshots/ayin__tests__map_array.snap b/src/snapshots/ayin__tests__map_array.snap new file mode 100644 index 0000000..52c5c4b --- /dev/null +++ b/src/snapshots/ayin__tests__map_array.snap @@ -0,0 +1,25 @@ +--- +source: src/lib.rs +expression: result +--- +Ok( + Vector( + [ + Value( + Int( + 2, + ), + ), + Value( + Int( + 3, + ), + ), + Value( + Int( + 4, + ), + ), + ], + ), +)