Add preliminary support for deeper get/set
This commit is contained in:
parent
72c23ad7ca
commit
924ce2eddc
128
src/engine.rs
128
src/engine.rs
@ -16,8 +16,9 @@ pub enum EvalAltResult {
|
|||||||
ErrorFunctionArgMismatch,
|
ErrorFunctionArgMismatch,
|
||||||
ErrorFunctionCallNotSupported,
|
ErrorFunctionCallNotSupported,
|
||||||
ErrorIfGuardMismatch,
|
ErrorIfGuardMismatch,
|
||||||
ErrorVariableNotFound,
|
ErrorVariableNotFound(String),
|
||||||
ErrorFunctionArityNotSupported,
|
ErrorFunctionArityNotSupported,
|
||||||
|
ErrorAssignmentToUnknownLHS,
|
||||||
InternalErrorMalformedDotExpression,
|
InternalErrorMalformedDotExpression,
|
||||||
LoopBreak,
|
LoopBreak,
|
||||||
Return(Box<Any>)
|
Return(Box<Any>)
|
||||||
@ -30,8 +31,9 @@ impl Error for EvalAltResult {
|
|||||||
EvalAltResult::ErrorFunctionArgMismatch => "Function argument types do not match",
|
EvalAltResult::ErrorFunctionArgMismatch => "Function argument types do not match",
|
||||||
EvalAltResult::ErrorFunctionCallNotSupported => "Function call with > 2 argument not supported",
|
EvalAltResult::ErrorFunctionCallNotSupported => "Function call with > 2 argument not supported",
|
||||||
EvalAltResult::ErrorIfGuardMismatch => "If guards expect boolean expression",
|
EvalAltResult::ErrorIfGuardMismatch => "If guards expect boolean expression",
|
||||||
EvalAltResult::ErrorVariableNotFound => "Variable not found",
|
EvalAltResult::ErrorVariableNotFound(ref s) => {println!("Var {} not found", s); "Variable not found"},
|
||||||
EvalAltResult::ErrorFunctionArityNotSupported => "Functions of more than 3 parameters are not yet supported",
|
EvalAltResult::ErrorFunctionArityNotSupported => "Functions of more than 3 parameters are not yet supported",
|
||||||
|
EvalAltResult::ErrorAssignmentToUnknownLHS => "Assignment to an unsupported left-hand side",
|
||||||
EvalAltResult::InternalErrorMalformedDotExpression => "[Internal error] Unexpected expression in dot expression",
|
EvalAltResult::InternalErrorMalformedDotExpression => "[Internal error] Unexpected expression in dot expression",
|
||||||
EvalAltResult::LoopBreak => "Loop broken before completion (not an error)",
|
EvalAltResult::LoopBreak => "Loop broken before completion (not an error)",
|
||||||
EvalAltResult::Return(_) => "Function returned value (not an error)"
|
EvalAltResult::Return(_) => "Function returned value (not an error)"
|
||||||
@ -372,6 +374,20 @@ 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::Dot(ref inner_lhs, ref inner_rhs) => {
|
||||||
|
match **inner_lhs {
|
||||||
|
Expr::Identifier(ref id) => {
|
||||||
|
let get_fn_name = "get$".to_string() + id;
|
||||||
|
let result = self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(mut v) => return self.get_dot_val_helper(scope, &mut v, inner_rhs),
|
||||||
|
e => return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,13 +399,15 @@ impl Engine {
|
|||||||
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
||||||
if *id == *name {
|
if *id == *name {
|
||||||
if let Ok(clone) = self.call_fn("clone", Some(val), None, None, None, None, None) {
|
let result = self.call_fn("clone", Some(val), None, None, None, None, None);
|
||||||
|
|
||||||
|
if let Ok(clone) = result {
|
||||||
target = Some(clone);
|
target = Some(clone);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println!("Error when cloning");
|
println!("Error when cloning");
|
||||||
return Err(EvalAltResult::ErrorVariableNotFound);
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,7 +425,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!("Error finding target: {}", id);
|
println!("Error finding target: {}", id);
|
||||||
return Err(EvalAltResult::ErrorVariableNotFound);
|
return Err(EvalAltResult::ErrorVariableNotFound(id.clone()));
|
||||||
}
|
}
|
||||||
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
}
|
}
|
||||||
@ -422,9 +440,38 @@ impl Engine {
|
|||||||
|
|
||||||
self.call_fn(&set_fn_name, Some(this_ptr), Some(&mut source_val), None, None, None, None)
|
self.call_fn(&set_fn_name, Some(this_ptr), Some(&mut source_val), None, None, None, None)
|
||||||
}
|
}
|
||||||
|
Expr::Dot(ref inner_lhs, ref inner_rhs) => {
|
||||||
|
match **inner_lhs {
|
||||||
|
Expr::Identifier(ref id) => {
|
||||||
|
println!("Setting into Dot");
|
||||||
|
|
||||||
|
let get_fn_name = "get$".to_string() + id;
|
||||||
|
let result = self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(mut v) => {
|
||||||
|
match self.set_dot_val_helper(&mut v, inner_rhs, source_val) {
|
||||||
|
Ok(_) => {
|
||||||
|
let set_fn_name = "set$".to_string() + id;
|
||||||
|
|
||||||
|
self.call_fn(&set_fn_name, Some(this_ptr), Some(&mut v), None, None, None, None)
|
||||||
|
}
|
||||||
|
e => e
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e => e
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Setting into unknown AST node");
|
||||||
|
Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_dot_val(&self, scope: &mut Scope, dot_lhs: &Expr, dot_rhs: &Expr, source_val: Box<Any>) -> Result<Box<Any>, EvalAltResult> {
|
fn set_dot_val(&self, scope: &mut Scope, dot_lhs: &Expr, dot_rhs: &Expr, source_val: Box<Any>) -> Result<Box<Any>, EvalAltResult> {
|
||||||
match *dot_lhs {
|
match *dot_lhs {
|
||||||
@ -438,7 +485,7 @@ impl Engine {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Err(EvalAltResult::ErrorVariableNotFound);
|
return Err(EvalAltResult::ErrorVariableNotFound(id.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,7 +502,7 @@ impl Engine {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(EvalAltResult::ErrorVariableNotFound);
|
return Err(EvalAltResult::ErrorAssignmentToUnknownLHS);
|
||||||
}
|
}
|
||||||
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
}
|
}
|
||||||
@ -471,7 +518,7 @@ impl Engine {
|
|||||||
return self.call_fn("clone", Some(val), None, None, None, None, None);
|
return self.call_fn("clone", Some(val), None, None, None, None, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
Err(EvalAltResult::ErrorVariableNotFound(id.clone()))
|
||||||
}
|
}
|
||||||
Expr::Assignment(ref id, ref rhs) => {
|
Expr::Assignment(ref id, ref rhs) => {
|
||||||
match **id {
|
match **id {
|
||||||
@ -485,14 +532,14 @@ impl Engine {
|
|||||||
return Ok(Box::new(()));
|
return Ok(Box::new(()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
Err(EvalAltResult::ErrorVariableNotFound(n.clone()))
|
||||||
}
|
}
|
||||||
Expr::Dot(ref dot_lhs, ref dot_rhs) => {
|
Expr::Dot(ref dot_lhs, ref dot_rhs) => {
|
||||||
let rhs_val = try!(self.eval_expr(scope, rhs));
|
let rhs_val = try!(self.eval_expr(scope, rhs));
|
||||||
|
|
||||||
self.set_dot_val(scope, dot_lhs, dot_rhs, rhs_val)
|
self.set_dot_val(scope, dot_lhs, dot_rhs, rhs_val)
|
||||||
}
|
}
|
||||||
_ => Err(EvalAltResult::ErrorVariableNotFound)
|
_ => Err(EvalAltResult::ErrorAssignmentToUnknownLHS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Dot(ref lhs, ref rhs) => {
|
Expr::Dot(ref lhs, ref rhs) => {
|
||||||
@ -965,6 +1012,67 @@ fn test_get_set() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_big_get_set() {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TestChild {
|
||||||
|
x: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestChild {
|
||||||
|
fn get_x(&mut self) -> i32 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_x(&mut self, new_x: i32) {
|
||||||
|
self.x = new_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> TestChild {
|
||||||
|
TestChild { x: 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TestParent {
|
||||||
|
child: TestChild
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestParent {
|
||||||
|
fn get_child(&mut self) -> TestChild {
|
||||||
|
self.child.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_child(&mut self, new_child: TestChild) {
|
||||||
|
self.child = new_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> TestParent {
|
||||||
|
TestParent { child: TestChild::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
engine.register_type::<TestChild>();
|
||||||
|
engine.register_type::<TestParent>();
|
||||||
|
|
||||||
|
&(TestChild::get_x as fn(&mut TestChild)->i32).register(&mut engine, "get$x");
|
||||||
|
&(TestChild::set_x as fn(&mut TestChild, i32)->()).register(&mut engine, "set$x");
|
||||||
|
|
||||||
|
&(TestParent::get_child as fn(&mut TestParent)->TestChild).register(&mut engine, "get$child");
|
||||||
|
&(TestParent::set_child as fn(&mut TestParent, TestChild)->()).register(&mut engine, "set$child");
|
||||||
|
&(TestParent::new as fn()->TestParent).register(&mut engine, "new_tp");
|
||||||
|
|
||||||
|
if let Ok(result) = engine.eval("var a = new_tp(); a.child.x = 500; a.child.x".to_string()).unwrap().downcast::<i32>() {
|
||||||
|
assert_eq!(*result, 500);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_internal_fn() {
|
fn test_internal_fn() {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user