Fill out array support with get/set for indexes in more complex expressions

This commit is contained in:
jonathandturner 2016-03-26 13:32:20 -07:00
parent b1ccaf4516
commit 5ccfab87ce

View File

@ -402,6 +402,28 @@ impl Engine {
let get_fn_name = "get$".to_string() + id; let get_fn_name = "get$".to_string() + id;
return self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None); return self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None);
} }
Expr::Index(ref id, ref idx_raw) => {
let idx = try!(self.eval_expr(scope, idx_raw));
let get_fn_name = "get$".to_string() + id;
if let Ok(mut val) = self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None) {
if let Ok(i) = idx.downcast::<i32>() {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
return self.call_fn("clone", Some(&mut arr_typed[*i as usize]), None, None, None, None, None);
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
Expr::Dot(ref inner_lhs, ref inner_rhs) => { Expr::Dot(ref inner_lhs, ref inner_rhs) => {
match **inner_lhs { match **inner_lhs {
Expr::Identifier(ref id) => { Expr::Identifier(ref id) => {
@ -453,6 +475,47 @@ impl Engine {
return Err(EvalAltResult::ErrorVariableNotFound(id.clone())); return Err(EvalAltResult::ErrorVariableNotFound(id.clone()));
} }
Expr::Index(ref id, ref idx_raw) => {
let idx_boxed = try!(self.eval_expr(scope, idx_raw));
let idx = if let Ok(i) = idx_boxed.downcast::<i32>() { i } else { return Err(EvalAltResult::ErrorIndexMismatch); };
let mut target : Option<Box<Any>> = None;
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *id == *name {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
let result = self.call_fn("clone", Some(&mut arr_typed[*idx as usize]),
None, None, None, None, None);
if let Ok(clone) = result {
target = Some(clone);
break;
}
else {
return result;
}
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
}
if let Some(mut t) = target {
let result = self.get_dot_val_helper(scope, &mut t, dot_rhs);
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *id == *name {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
arr_typed[*idx as usize] = t;
break;
}
}
}
return result;
}
Err(EvalAltResult::ErrorVariableNotFound(id.clone()))
}
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression) _ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
} }
} }
@ -524,6 +587,47 @@ impl Engine {
return Err(EvalAltResult::ErrorAssignmentToUnknownLHS); return Err(EvalAltResult::ErrorAssignmentToUnknownLHS);
} }
Expr::Index(ref id, ref idx_raw) => {
let idx_boxed = try!(self.eval_expr(scope, idx_raw));
let idx = if let Ok(i) = idx_boxed.downcast::<i32>() { i } else { return Err(EvalAltResult::ErrorIndexMismatch); };
let mut target : Option<Box<Any>> = None;
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *id == *name {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
let result = self.call_fn("clone", Some(&mut arr_typed[*idx as usize]),
None, None, None, None, None);
if let Ok(clone) = result {
target = Some(clone);
break;
}
else {
return result;
}
}
else {
return Err(EvalAltResult::ErrorIndexMismatch);
}
}
}
if let Some(mut t) = target {
let result = self.set_dot_val_helper(&mut t, dot_rhs, source_val);
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
if *id == *name {
if let Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec<Box<Any>>> {
arr_typed[*idx as usize] = t;
break;
}
}
}
return result;
}
Err(EvalAltResult::ErrorVariableNotFound(id.clone()))
}
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression) _ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
} }
} }
@ -1189,6 +1293,54 @@ fn test_big_get_set() {
} }
} }
#[test]
fn test_array_with_structs() {
#[derive(Clone)]
struct TestStruct {
x: i32
}
impl TestStruct {
fn update(&mut self) {
self.x += 1000;
}
fn get_x(&mut self) -> i32 {
self.x
}
fn set_x(&mut self, new_x: i32) {
self.x = new_x;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
}
}
let mut engine = Engine::new();
engine.register_type::<TestStruct>();
engine.register_get_set("x", TestStruct::get_x, TestStruct::set_x);
engine.register_fn("update", TestStruct::update);
engine.register_fn("new_ts", TestStruct::new);
if let Ok(result) = engine.eval::<i32>("var a = [new_ts()]; a[0].x") {
assert_eq!(result, 1);
}
else {
assert!(false);
}
if let Ok(result) = engine.eval::<i32>("var a = [new_ts()]; a[0].x = 100; a[0].update(); a[0].x") {
assert_eq!(result, 1100);
}
else {
assert!(false);
}
}
#[test] #[test]
fn test_internal_fn() { fn test_internal_fn() {
let mut engine = Engine::new(); let mut engine = Engine::new();