use crate::eval::environment::Environment;
use crate::eval::evaluator::eval;
use crate::value::Value;
use hamelin_lib::tree::ast::identifier::SimpleIdentifier;
use hamelin_lib::tree::typed_ast::environment::TypeEnvironment;
use hamelin_lib::tree::builder::{array, field_ref, index, ExpressionBuilder};
use hamelin_lib::tree::options::ExpressionTypeCheckOptions;
use hamelin_lib::tree::typed_ast::expression::TypedExpressionKind;
use hamelin_lib::type_check_expression;
use hamelin_lib::types::INT;
use std::sync::Arc;
use super::test_helpers::{setup_environment, TestContext};
#[test]
fn test_eval_array_literal() {
let env = setup_environment();
let expr = type_check_expression(
array().element(1).element(2).element(3).build(),
ExpressionTypeCheckOptions::default(),
)
.output;
let result = eval(&expr, &env).unwrap();
match result {
Value::Array(arr) => {
assert_eq!(arr.len(), 3);
assert_eq!(arr[0], Value::Int(1));
assert_eq!(arr[1], Value::Int(2));
assert_eq!(arr[2], Value::Int(3));
}
_ => panic!("Expected Array value"),
}
}
#[test]
fn test_eval_empty_array_literal() {
let env = setup_environment();
let expr = type_check_expression(array().build(), ExpressionTypeCheckOptions::default()).output;
let result = eval(&expr, &env).unwrap();
match result {
Value::Array(arr) => {
assert_eq!(arr.len(), 0);
}
_ => panic!("Expected Array value"),
}
}
#[test]
fn test_eval_mixed_array_types() {
let expr = type_check_expression(
array().element(42).element("mixed").element(true).build(),
ExpressionTypeCheckOptions::default(),
)
.output;
assert!(matches!(expr.kind, TypedExpressionKind::Error(_)));
}
#[test]
fn test_eval_nested_array() {
let env = setup_environment();
let inner_array = array().element(1).element(2);
let outer_array = array().element(inner_array);
let expr =
type_check_expression(outer_array.build(), ExpressionTypeCheckOptions::default()).output;
let result = eval(&expr, &env).unwrap();
match result {
Value::Array(arr) => {
assert_eq!(arr.len(), 1);
match &arr[0] {
Value::Array(inner) => {
assert_eq!(inner.len(), 2);
assert_eq!(inner[0], Value::Int(1));
assert_eq!(inner[1], Value::Int(2));
}
_ => panic!("Expected nested Array value"),
}
}
_ => panic!("Expected Array value"),
}
}
#[test]
fn test_eval_array_with_variables() {
let mut env = Environment::new();
env.bind(SimpleIdentifier::new("x"), Value::Int(10));
env.bind(SimpleIdentifier::new("y"), Value::Int(20));
let mut trans_env = TypeEnvironment::default();
trans_env.bind_str("x", INT);
trans_env.bind_str("y", INT);
let expr = array()
.element(field_ref("x"))
.element(5)
.element(field_ref("y"))
.element(42)
.build();
let expr = type_check_expression(
expr,
ExpressionTypeCheckOptions::builder()
.bindings(Arc::new(trans_env))
.build(),
)
.output;
let result = eval(&expr, &env).unwrap();
assert_eq!(
result,
Value::Array(vec![
Value::Int(10),
Value::Int(5),
Value::Int(20),
Value::Int(42)
])
);
}
#[test]
fn test_eval_array_index_access() {
let ctx = TestContext::default();
let make_arr = || array().element(10).element(20).element(30).element(40);
let expr = index(make_arr(), 0);
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(10));
let expr = index(make_arr(), 2);
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(30));
let expr = index(make_arr(), 3);
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(40));
}
#[test]
fn test_eval_index_access_errors() {
let ctx = TestContext::default();
let make_arr = || array().element(1).element(2);
let expr = index(make_arr(), 5);
let result = ctx.try_eval_expr(&expr);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.contains("out of bounds"));
let expr = index(make_arr(), -1);
let result = ctx.try_eval_expr(&expr);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.contains("out of bounds"));
}
#[test]
fn test_eval_single_element_array() {
let ctx = TestContext::new();
let expr = array().element(42);
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Array(vec![Value::Int(42)]));
}
#[test]
fn test_eval_array_of_strings() {
let ctx = TestContext::new();
let expr = array().element("first").element("second").element("third");
let result = ctx.eval_expr(&expr);
assert_eq!(
result,
Value::Array(vec![
Value::String("first".to_string()),
Value::String("second".to_string()),
Value::String("third".to_string())
])
);
}
#[test]
fn test_eval_array_of_booleans() {
let ctx = TestContext::new();
let expr = array().element(true).element(false).element(true);
let result = ctx.eval_expr(&expr);
assert_eq!(
result,
Value::Array(vec![
Value::Boolean(true),
Value::Boolean(false),
Value::Boolean(true)
])
);
}
#[test]
fn test_eval_array_index_first_element() {
let ctx = TestContext::new();
let arr = array().element("zero").element("one").element("two");
let expr = index(arr, 0);
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::String("zero".to_string()));
}
#[test]
fn test_eval_array_index_last_element() {
let ctx = TestContext::new();
let arr = array().element(100).element(200).element(300);
let expr = index(arr, 2); let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(300));
}