use crate::eval::evaluator::eval;
use crate::value::Value;
use hamelin_lib::tree::ast::identifier::SimpleIdentifier;
use hamelin_lib::tree::builder::{
array, field, index, int, string, struct_literal, ExpressionBuilder,
};
use hamelin_lib::tree::options::ExpressionTypeCheckOptions;
use hamelin_lib::type_check_expression;
use ordermap::OrderMap;
use std::sync::Arc;
use super::test_helpers::test_context;
#[test]
fn test_eval_complex_nested_access() {
let ctx = test_context();
let expr = index(
field(
struct_literal().field(
"items",
array()
.element(
struct_literal()
.field("id", int(1))
.field("value", string("first")),
)
.element(
struct_literal()
.field("id", int(2))
.field("value", string("second")),
)
.element(
struct_literal()
.field("id", int(3))
.field("value", string("third")),
),
),
"items",
),
int(1),
);
let result = ctx.eval_expr(&expr);
let mut expected_fields = OrderMap::new();
expected_fields.insert("id".parse::<SimpleIdentifier>().unwrap(), Value::Int(2));
expected_fields.insert(
"value".parse::<SimpleIdentifier>().unwrap(),
Value::String("second".to_string()),
);
assert_eq!(result, Value::Struct(expected_fields));
let expr = field(
index(
field(
struct_literal().field(
"items",
array()
.element(
struct_literal()
.field("id", int(1))
.field("value", string("first")),
)
.element(
struct_literal()
.field("id", int(2))
.field("value", string("second")),
)
.element(
struct_literal()
.field("id", int(3))
.field("value", string("third")),
),
),
"items",
),
int(2), ),
"value",
);
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::String("third".to_string()));
}
#[test]
fn test_eval_array_of_arrays_access() {
let ctx = test_context();
let expr = index(
index(
array()
.element(array().element(int(1)).element(int(2)))
.element(array().element(int(3)).element(int(4)))
.element(array().element(int(5)).element(int(6))),
int(1), ),
int(0), );
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(3));
}
#[test]
fn test_eval_struct_containing_nested_arrays() {
let ctx = test_context();
let expr = index(
index(
field(
struct_literal().field(
"matrix",
array()
.element(array().element(int(1)).element(int(2)).element(int(3)))
.element(array().element(int(4)).element(int(5)).element(int(6)))
.element(array().element(int(7)).element(int(8)).element(int(9))),
),
"matrix",
),
int(2), ),
int(1), );
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(8));
}
#[test]
fn test_eval_array_of_structs_with_arrays() {
let ctx = test_context();
let expr = index(
field(
index(
array()
.element(
struct_literal()
.field("name", string("group1"))
.field("values", array().element(int(10)).element(int(20))),
)
.element(
struct_literal()
.field("name", string("group2"))
.field("values", array().element(int(30)).element(int(40))),
),
int(1), ),
"values", ),
int(0), );
let result = ctx.eval_expr(&expr);
assert_eq!(result, Value::Int(30));
}
#[test]
fn test_eval_deeply_nested_struct_access() {
let ctx = test_context();
let expr = field(
field(
field(
field(
struct_literal().field(
"level1",
struct_literal().field(
"level2",
struct_literal().field(
"level3",
struct_literal()
.field("level4", struct_literal().field("value", int(42))),
),
),
),
"level1",
),
"level2",
),
"level3",
),
"level4",
);
let result = ctx.eval_expr(&field(expr, "value"));
assert_eq!(result, Value::Int(42));
}
#[test]
fn test_eval_mixed_access_patterns() {
use hamelin_lib::tree::builder::boolean;
let ctx = test_context();
let expr = field(
index(
field(
struct_literal().field(
"data",
array()
.element(
struct_literal()
.field("active", boolean(false))
.field("info", struct_literal().field("code", int(100))),
)
.element(
struct_literal()
.field("active", boolean(true))
.field("info", struct_literal().field("code", int(200))),
),
),
"data",
),
int(1), ),
"info",
);
let result = ctx.eval_expr(&field(expr, "code"));
assert_eq!(result, Value::Int(200));
}
#[test]
fn test_eval_chained_field_access_with_variables() {
use hamelin_lib::tree::builder::field_ref;
use hamelin_lib::types::{struct_type::Struct, Type, BOOLEAN, STRING};
use super::test_helpers::TestContext;
let mut settings_fields = OrderMap::new();
settings_fields.insert(
"debug".parse::<SimpleIdentifier>().unwrap(),
Value::Boolean(true),
);
let mut config_fields = OrderMap::new();
config_fields.insert(
"settings".parse::<SimpleIdentifier>().unwrap(),
Value::Struct(settings_fields),
);
let settings_struct = Struct::default().with_str("debug", BOOLEAN);
let config_struct = Struct::default().with_str("settings", Type::Struct(settings_struct));
let mut ctx = TestContext::default();
ctx.set(
"config",
Value::Struct(config_fields),
Type::Struct(config_struct),
);
ctx.set("name", Value::String("test_config".to_string()), STRING);
let expr = type_check_expression(
field(field(field_ref("config"), "settings"), "debug").build(),
ExpressionTypeCheckOptions::builder()
.bindings(Arc::new(ctx.translation_env.clone()))
.build(),
)
.output;
let result = eval(&expr, &ctx.env).unwrap();
assert_eq!(result, Value::Boolean(true));
}
#[test]
fn test_eval_array_slice_simulation() {
let ctx = test_context();
let base_array = || {
array()
.element(int(10))
.element(int(20))
.element(int(30))
.element(int(40))
.element(int(50))
};
let elem1 = ctx.eval_expr(&index(base_array(), int(1)));
let elem2 = ctx.eval_expr(&index(base_array(), int(2)));
let elem3 = ctx.eval_expr(&index(base_array(), int(3)));
assert_eq!(elem1, Value::Int(20));
assert_eq!(elem2, Value::Int(30));
assert_eq!(elem3, Value::Int(40));
let expected_values = vec![Value::Int(20), Value::Int(30), Value::Int(40)];
let actual_values = vec![elem1, elem2, elem3];
assert_eq!(actual_values, expected_values);
}
#[test]
fn test_eval_complex_navigation_with_error_handling() {
let ctx = test_context();
let valid_expr = field(
index(
field(
struct_literal().field(
"users",
array().element(struct_literal().field("id", int(1))),
),
"users",
),
int(0),
),
"id",
);
let result = ctx.eval_expr(&valid_expr);
assert_eq!(result, Value::Int(1));
let invalid_expr = field(
index(
field(
struct_literal().field(
"users",
array().element(struct_literal().field("id", int(1))),
),
"users",
),
int(10), ),
"id",
);
let result = ctx.try_eval_expr(&invalid_expr);
assert!(result.is_err());
}