array access via variables and len

This commit is contained in:
me 2025-12-25 23:28:25 +02:00
parent baf2c40ac4
commit c3bd60f475
5 changed files with 115 additions and 10 deletions

View file

@ -149,10 +149,20 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
} }
ast::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? { ast::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? {
ast::Value::Record(record) => Ok(state.variables.get(record.get(&field)?).clone()), ast::Value::Record(record) => Ok(state.variables.get(record.get(&field)?).clone()),
ast::Value::Vector(vec) if field.0.chars().all(char::is_numeric) => { ast::Value::Vector(vec) => match field {
_ if field.0.chars().all(char::is_numeric) => {
let index = field.0.parse::<usize>().unwrap(); let index = field.0.parse::<usize>().unwrap();
Ok(state.variables.get(vec.get(index)?).clone()) 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())), v => Err(Error::NotARecord(v, Backtrace::capture())),
}, },
ast::Expr::Var(var) => { 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::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::Record(record) => Ok(ast::Value::Ref(record.get(&field)?.clone())),
ast::Value::Vector(vec) if field.0.chars().all(char::is_numeric) => { ast::Value::Vector(vec) => match field {
_ if field.0.chars().all(char::is_numeric) => {
let index = field.0.parse::<usize>().unwrap(); let index = field.0.parse::<usize>().unwrap();
Ok(ast::Value::Ref(vec.get(index)?.clone())) 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())), v => Err(Error::NotARecord(v, Backtrace::capture())),
}, },
_ => eval_expr(expr_env, state, expr), _ => eval_expr(expr_env, state, expr),

View file

@ -18,6 +18,7 @@ pub enum Error {
NotARecord(ast::Value, Backtrace), NotARecord(ast::Value, Backtrace),
NotAReference(ast::Expr, ast::Value, Backtrace), NotAReference(ast::Expr, ast::Value, Backtrace),
NotABoolean(ast::Value, Backtrace), NotABoolean(ast::Value, Backtrace),
NotAnInt(ast::Value, Backtrace),
OpError(ast::Value, ast::Op, ast::Value, Backtrace), OpError(ast::Value, ast::Op, ast::Value, Backtrace),
MigrationError(ast::Value, String, Backtrace), MigrationError(ast::Value, String, Backtrace),
ArgumentsMismatch(Backtrace), ArgumentsMismatch(Backtrace),
@ -39,6 +40,7 @@ impl PartialEq for Error {
a1 == a2 && b1 == b2 a1 == a2 && b1 == b2
} }
(Error::NotABoolean(a1, _), Error::NotABoolean(a2, _)) => a1 == a2, (Error::NotABoolean(a1, _), Error::NotABoolean(a2, _)) => a1 == a2,
(Error::NotAnInt(a1, _), Error::NotAnInt(a2, _)) => a1 == a2,
(Error::MigrationError(a1, b1, _), Error::MigrationError(a2, b2, _)) => { (Error::MigrationError(a1, b1, _), Error::MigrationError(a2, b2, _)) => {
a1 == a2 && b1 == 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}" "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::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::ArgumentsMismatch(a) => write!(f, "Arguments mismatch\n{a}"),
Error::OpError(a, b, c, d) => write!(f, "Op Error {a:?} {b:?} {c:?}\n{d}"), Error::OpError(a, b, c, d) => write!(f, "Op Error {a:?} {b:?} {c:?}\n{d}"),
Error::MigrationError(a, b, c) => { Error::MigrationError(a, b, c) => {

View file

@ -76,9 +76,9 @@ let counter = fn(a,b) {
loop { loop {
if (a + count) >= b { if (a + count) >= b {
break break
}; }
count = count + 1 count = count + 1
}; }
count count
} }
@ -90,6 +90,54 @@ let main = fn() {
insta::assert_debug_snapshot!(result); 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] #[test]
fn direction() { fn direction() {
let program = " let program = "

View file

@ -0,0 +1,11 @@
---
source: src/lib.rs
expression: result
---
Ok(
Value(
Int(
45,
),
),
)

View file

@ -0,0 +1,25 @@
---
source: src/lib.rs
expression: result
---
Ok(
Vector(
[
Value(
Int(
2,
),
),
Value(
Int(
3,
),
),
Value(
Int(
4,
),
),
],
),
)