Start adding support for dotted expressions
This commit is contained in:
parent
fbf81ff651
commit
72c23ad7ca
262
src/engine.rs
262
src/engine.rs
@ -18,6 +18,7 @@ pub enum EvalAltResult {
|
|||||||
ErrorIfGuardMismatch,
|
ErrorIfGuardMismatch,
|
||||||
ErrorVariableNotFound,
|
ErrorVariableNotFound,
|
||||||
ErrorFunctionArityNotSupported,
|
ErrorFunctionArityNotSupported,
|
||||||
|
InternalErrorMalformedDotExpression,
|
||||||
LoopBreak,
|
LoopBreak,
|
||||||
Return(Box<Any>)
|
Return(Box<Any>)
|
||||||
}
|
}
|
||||||
@ -31,6 +32,7 @@ impl Error for EvalAltResult {
|
|||||||
EvalAltResult::ErrorIfGuardMismatch => "If guards expect boolean expression",
|
EvalAltResult::ErrorIfGuardMismatch => "If guards expect boolean expression",
|
||||||
EvalAltResult::ErrorVariableNotFound => "Variable not found",
|
EvalAltResult::ErrorVariableNotFound => "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::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)"
|
||||||
}
|
}
|
||||||
@ -319,6 +321,146 @@ impl Engine {
|
|||||||
&(clone_helper as fn(T)->T).register(self, "clone");
|
&(clone_helper as fn(T)->T).register(self, "clone");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_dot_val_helper(&self, scope: &mut Scope, this_ptr: &mut Box<Any>, dot_rhs: &Expr) -> Result<Box<Any>, EvalAltResult> {
|
||||||
|
match *dot_rhs {
|
||||||
|
Expr::FnCall(ref fn_name, ref args) => {
|
||||||
|
if args.len() == 0 {
|
||||||
|
return self.call_fn(&fn_name, Some(this_ptr), None, None, None, None, None);
|
||||||
|
}
|
||||||
|
else if args.len() == 1 {
|
||||||
|
let mut arg = try!(self.eval_expr(scope, &args[0]));
|
||||||
|
|
||||||
|
return self.call_fn(&fn_name, Some(this_ptr), Some(&mut arg), None, None, None, None);
|
||||||
|
}
|
||||||
|
else if args.len() == 2 {
|
||||||
|
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
||||||
|
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
||||||
|
|
||||||
|
return self.call_fn(&fn_name, Some(this_ptr), Some(&mut arg1), Some(&mut arg2), None, None, None);
|
||||||
|
}
|
||||||
|
else if args.len() == 3 {
|
||||||
|
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
||||||
|
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
||||||
|
let mut arg3 = try!(self.eval_expr(scope, &args[2]));
|
||||||
|
|
||||||
|
return self.call_fn(&fn_name, Some(this_ptr), Some(&mut arg1), Some(&mut arg2), Some(&mut arg3), None, None);
|
||||||
|
}
|
||||||
|
else if args.len() == 4 {
|
||||||
|
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
||||||
|
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
||||||
|
let mut arg3 = try!(self.eval_expr(scope, &args[2]));
|
||||||
|
let mut arg4 = try!(self.eval_expr(scope, &args[3]));
|
||||||
|
|
||||||
|
return self.call_fn(&fn_name, Some(this_ptr), Some(&mut arg1), Some(&mut arg2), Some(&mut arg3),
|
||||||
|
Some(&mut arg4), None);
|
||||||
|
}
|
||||||
|
else if args.len() == 5 {
|
||||||
|
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
||||||
|
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
||||||
|
let mut arg3 = try!(self.eval_expr(scope, &args[2]));
|
||||||
|
let mut arg4 = try!(self.eval_expr(scope, &args[3]));
|
||||||
|
let mut arg5 = try!(self.eval_expr(scope, &args[4]));
|
||||||
|
|
||||||
|
return self.call_fn(&fn_name, Some(this_ptr), Some(&mut arg1), Some(&mut arg2), Some(&mut arg3),
|
||||||
|
Some(&mut arg4), Some(&mut arg5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(EvalAltResult::ErrorFunctionCallNotSupported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Identifier(ref id) => {
|
||||||
|
let get_fn_name = "get$".to_string() + id;
|
||||||
|
return self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None);
|
||||||
|
}
|
||||||
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_dot_val(&self, scope: &mut Scope, dot_lhs: &Expr, dot_rhs: &Expr) -> Result<Box<Any>, EvalAltResult> {
|
||||||
|
match *dot_lhs {
|
||||||
|
Expr::Identifier(ref id) => {
|
||||||
|
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 Ok(clone) = self.call_fn("clone", Some(val), None, None, None, None, None) {
|
||||||
|
target = Some(clone);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("Error when cloning");
|
||||||
|
return Err(EvalAltResult::ErrorVariableNotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
*val = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Error finding target: {}", id);
|
||||||
|
return Err(EvalAltResult::ErrorVariableNotFound);
|
||||||
|
}
|
||||||
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dot_val_helper(&self, this_ptr: &mut Box<Any>, dot_rhs: &Expr, mut source_val: Box<Any>) -> Result<Box<Any>, EvalAltResult> {
|
||||||
|
match *dot_rhs {
|
||||||
|
Expr::Identifier(ref id) => {
|
||||||
|
let set_fn_name = "set$".to_string() + id;
|
||||||
|
|
||||||
|
println!("calling: {}", set_fn_name);
|
||||||
|
|
||||||
|
self.call_fn(&set_fn_name, Some(this_ptr), Some(&mut source_val), None, None, None, None)
|
||||||
|
}
|
||||||
|
_ => 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> {
|
||||||
|
match *dot_lhs {
|
||||||
|
Expr::Identifier(ref id) => {
|
||||||
|
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 Ok(clone) = self.call_fn("clone", Some(val), None, None, None, None, None) {
|
||||||
|
target = Some(clone);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Err(EvalAltResult::ErrorVariableNotFound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
*val = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(EvalAltResult::ErrorVariableNotFound);
|
||||||
|
}
|
||||||
|
_ => Err(EvalAltResult::InternalErrorMalformedDotExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result<Box<Any>, EvalAltResult> {
|
fn eval_expr(&self, scope: &mut Scope, expr: &Expr) -> Result<Box<Any>, EvalAltResult> {
|
||||||
match *expr {
|
match *expr {
|
||||||
Expr::IntConst(i) => Ok(Box::new(i)),
|
Expr::IntConst(i) => Ok(Box::new(i)),
|
||||||
@ -345,9 +487,17 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
Err(EvalAltResult::ErrorVariableNotFound)
|
||||||
}
|
}
|
||||||
|
Expr::Dot(ref dot_lhs, ref dot_rhs) => {
|
||||||
|
let rhs_val = try!(self.eval_expr(scope, rhs));
|
||||||
|
|
||||||
|
self.set_dot_val(scope, dot_lhs, dot_rhs, rhs_val)
|
||||||
|
}
|
||||||
_ => Err(EvalAltResult::ErrorVariableNotFound)
|
_ => Err(EvalAltResult::ErrorVariableNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::Dot(ref lhs, ref rhs) => {
|
||||||
|
self.get_dot_val(scope, lhs, rhs)
|
||||||
|
}
|
||||||
Expr::FnCall(ref fn_name, ref args) => {
|
Expr::FnCall(ref fn_name, ref args) => {
|
||||||
if args.len() == 0 {
|
if args.len() == 0 {
|
||||||
self.call_fn(&fn_name, None, None, None, None, None, None)
|
self.call_fn(&fn_name, None, None, None, None, None, None)
|
||||||
@ -403,81 +553,6 @@ impl Engine {
|
|||||||
Err(EvalAltResult::ErrorFunctionCallNotSupported)
|
Err(EvalAltResult::ErrorFunctionCallNotSupported)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::MethodCall(ref target, ref fn_name, ref args) => {
|
|
||||||
if args.len() == 0 {
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
|
||||||
if *target == *name {
|
|
||||||
return self.call_fn(&fn_name, Some(val), None, None, None, None, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
|
||||||
}
|
|
||||||
else if args.len() == 1 {
|
|
||||||
let mut arg = try!(self.eval_expr(scope, &args[0]));
|
|
||||||
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
|
||||||
if *target == *name {
|
|
||||||
return self.call_fn(&fn_name, Some(val), Some(&mut arg), None, None, None, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
|
||||||
}
|
|
||||||
else if args.len() == 2 {
|
|
||||||
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
|
||||||
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
|
||||||
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
|
||||||
if *target == *name {
|
|
||||||
return self.call_fn(&fn_name, Some(val), Some(&mut arg1), Some(&mut arg2), None, None, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
|
||||||
}
|
|
||||||
else if args.len() == 3 {
|
|
||||||
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
|
||||||
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
|
||||||
let mut arg3 = try!(self.eval_expr(scope, &args[2]));
|
|
||||||
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
|
||||||
if *target == *name {
|
|
||||||
return self.call_fn(&fn_name, Some(val), Some(&mut arg1), Some(&mut arg2), Some(&mut arg3), None, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
|
||||||
}
|
|
||||||
else if args.len() == 4 {
|
|
||||||
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
|
||||||
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
|
||||||
let mut arg3 = try!(self.eval_expr(scope, &args[2]));
|
|
||||||
let mut arg4 = try!(self.eval_expr(scope, &args[3]));
|
|
||||||
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
|
||||||
if *target == *name {
|
|
||||||
return self.call_fn(&fn_name, Some(val), Some(&mut arg1), Some(&mut arg2), Some(&mut arg3),
|
|
||||||
Some(&mut arg4), None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
|
||||||
}
|
|
||||||
else if args.len() == 5 {
|
|
||||||
let mut arg1 = try!(self.eval_expr(scope, &args[0]));
|
|
||||||
let mut arg2 = try!(self.eval_expr(scope, &args[1]));
|
|
||||||
let mut arg3 = try!(self.eval_expr(scope, &args[2]));
|
|
||||||
let mut arg4 = try!(self.eval_expr(scope, &args[3]));
|
|
||||||
let mut arg5 = try!(self.eval_expr(scope, &args[4]));
|
|
||||||
|
|
||||||
for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() {
|
|
||||||
if *target == *name {
|
|
||||||
return self.call_fn(&fn_name, Some(val), Some(&mut arg1), Some(&mut arg2), Some(&mut arg3),
|
|
||||||
Some(&mut arg4), Some(&mut arg5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(EvalAltResult::ErrorVariableNotFound)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Err(EvalAltResult::ErrorFunctionCallNotSupported)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::True => {
|
Expr::True => {
|
||||||
Ok(Box::new(true))
|
Ok(Box::new(true))
|
||||||
}
|
}
|
||||||
@ -853,6 +928,43 @@ fn test_method_call() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_set() {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TestStruct {
|
||||||
|
x: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestStruct {
|
||||||
|
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>();
|
||||||
|
|
||||||
|
&(TestStruct::get_x as fn(&mut TestStruct)->i32).register(&mut engine, "get$x");
|
||||||
|
&(TestStruct::set_x as fn(&mut TestStruct, i32)->()).register(&mut engine, "set$x");
|
||||||
|
&(TestStruct::new as fn()->TestStruct).register(&mut engine, "new_ts");
|
||||||
|
|
||||||
|
if let Ok(result) = engine.eval("var a = new_ts(); a.x = 500; a.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();
|
||||||
|
@ -43,7 +43,6 @@ pub enum ParseError {
|
|||||||
MissingRCurly,
|
MissingRCurly,
|
||||||
MalformedCallExpr,
|
MalformedCallExpr,
|
||||||
VarExpectsIdentifier,
|
VarExpectsIdentifier,
|
||||||
ExpectedMethodInvocation,
|
|
||||||
FnMissingName,
|
FnMissingName,
|
||||||
FnMissingParams
|
FnMissingParams
|
||||||
}
|
}
|
||||||
@ -59,7 +58,6 @@ impl Error for ParseError {
|
|||||||
ParseError::MissingRCurly => "Expected '}'",
|
ParseError::MissingRCurly => "Expected '}'",
|
||||||
ParseError::MalformedCallExpr => "Call contains bad expression",
|
ParseError::MalformedCallExpr => "Call contains bad expression",
|
||||||
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable",
|
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable",
|
||||||
ParseError::ExpectedMethodInvocation => "Expected method call after '.'",
|
|
||||||
ParseError::FnMissingName => "Function declaration is missing name",
|
ParseError::FnMissingName => "Function declaration is missing name",
|
||||||
ParseError::FnMissingParams => "Function declaration is missing parameters"
|
ParseError::FnMissingParams => "Function declaration is missing parameters"
|
||||||
}
|
}
|
||||||
@ -89,7 +87,7 @@ pub enum Stmt { If(Box<Expr>, Box<Stmt>), IfElse(Box<Expr>, Box<Stmt>, Box<Stmt>
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr { IntConst(i32), Identifier(String), StringConst(String), FnCall(String, Box<Vec<Expr>>),
|
pub enum Expr { IntConst(i32), Identifier(String), StringConst(String), FnCall(String, Box<Vec<Expr>>),
|
||||||
MethodCall(String, String, Box<Vec<Expr>>), Assignment(Box<Expr>, Box<Expr>), True, False }
|
Assignment(Box<Expr>, Box<Expr>), Dot(Box<Expr>, Box<Expr>), True, False }
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Token { IntConst(i32), Identifier(String), StringConst(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
|
pub enum Token { IntConst(i32), Identifier(String), StringConst(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
|
||||||
@ -343,6 +341,7 @@ fn get_precedence(token: &Token) -> i32 {
|
|||||||
Token::Minus => 20,
|
Token::Minus => 20,
|
||||||
Token::Divide => 40,
|
Token::Divide => 40,
|
||||||
Token::Multiply => 40,
|
Token::Multiply => 40,
|
||||||
|
Token::Period => 100,
|
||||||
_ => -1
|
_ => -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,18 +356,6 @@ fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
||||||
let id2 = match input.peek() {
|
|
||||||
Some(&Token::Period) => {
|
|
||||||
input.next();
|
|
||||||
match input.next() {
|
|
||||||
Some(Token::Identifier(ref s)) => {
|
|
||||||
s.clone()
|
|
||||||
}
|
|
||||||
_ => return Err(ParseError::ExpectedMethodInvocation)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => String::new()
|
|
||||||
};
|
|
||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::LParen) => {input.next();},
|
Some(&Token::LParen) => {input.next();},
|
||||||
_ => return Ok(Expr::Identifier(id))
|
_ => return Ok(Expr::Identifier(id))
|
||||||
@ -379,12 +366,7 @@ fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) ->
|
|||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::RParen) => {
|
Some(&Token::RParen) => {
|
||||||
input.next();
|
input.next();
|
||||||
if id2 == "" {
|
|
||||||
return Ok(Expr::FnCall(id, Box::new(args)))
|
return Ok(Expr::FnCall(id, Box::new(args)))
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Ok(Expr::MethodCall(id, id2, Box::new(args)))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
@ -400,12 +382,7 @@ fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) ->
|
|||||||
match input.peek() {
|
match input.peek() {
|
||||||
Some(&Token::RParen) => {
|
Some(&Token::RParen) => {
|
||||||
input.next();
|
input.next();
|
||||||
if id2 == "" {
|
|
||||||
return Ok(Expr::FnCall(id, Box::new(args)))
|
return Ok(Expr::FnCall(id, Box::new(args)))
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Ok(Expr::MethodCall(id, id2, Box::new(args)))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Some(&Token::Comma) => (),
|
Some(&Token::Comma) => (),
|
||||||
_ => return Err(ParseError::MalformedCallExpr)
|
_ => return Err(ParseError::MalformedCallExpr)
|
||||||
@ -459,6 +436,10 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>, prec: i32, lhs: Expr
|
|||||||
if curr_prec < next_prec {
|
if curr_prec < next_prec {
|
||||||
rhs = try!(parse_binop(input, curr_prec+1, rhs));
|
rhs = try!(parse_binop(input, curr_prec+1, rhs));
|
||||||
}
|
}
|
||||||
|
else if curr_prec >= 100 {
|
||||||
|
//Always bind right to left for precedence over 100
|
||||||
|
rhs = try!(parse_binop(input, curr_prec, rhs));
|
||||||
|
}
|
||||||
|
|
||||||
lhs_curr = match op_token {
|
lhs_curr = match op_token {
|
||||||
Token::Plus => Expr::FnCall("+".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Plus => Expr::FnCall("+".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
@ -466,6 +447,7 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>, prec: i32, lhs: Expr
|
|||||||
Token::Multiply => Expr::FnCall("*".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Multiply => Expr::FnCall("*".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Divide => Expr::FnCall("/".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::Divide => Expr::FnCall("/".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
|
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
|
||||||
|
Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)),
|
||||||
Token::EqualTo => Expr::FnCall("==".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::EqualTo => Expr::FnCall("==".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::NotEqualTo => Expr::FnCall("!=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::NotEqualTo => Expr::FnCall("!=".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
Token::LessThan => Expr::FnCall("<".to_string(), Box::new(vec![lhs_curr, rhs])),
|
Token::LessThan => Expr::FnCall("<".to_string(), Box::new(vec![lhs_curr, rhs])),
|
||||||
|
Loading…
Reference in New Issue
Block a user