Implement and test chain operator

Relates to #26
This commit is contained in:
Sebastian Schmidt 2019-03-28 11:34:54 +01:00
parent 4838a21a57
commit 9d27969eac
6 changed files with 50 additions and 10 deletions

View File

@ -111,6 +111,12 @@ impl Display for Tuple {
} }
impl Display for Assign { impl Display for Assign {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "; ")
}
}
impl Display for Chain {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, " = ") write!(f, " = ")
} }

View File

@ -78,10 +78,12 @@ pub struct Not;
#[derive(Debug)] #[derive(Debug)]
pub struct Tuple; pub struct Tuple;
#[derive(Debug)] #[derive(Debug)]
pub struct Assign; pub struct Assign;
#[derive(Debug)]
pub struct Chain;
#[derive(Debug)] #[derive(Debug)]
pub struct Const { pub struct Const {
value: Value, value: Value,
@ -627,6 +629,24 @@ impl Operator for Assign {
} }
} }
impl Operator for Chain {
fn precedence(&self) -> i32 {
0
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> Result<Value, EvalexprError> {
if arguments.is_empty() {
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
}
Ok(arguments.get(1).cloned().unwrap_or(Value::Empty))
}
}
impl Operator for Const { impl Operator for Const {
fn precedence(&self) -> i32 { fn precedence(&self) -> i32 {
200 200

View File

@ -28,11 +28,10 @@ impl fmt::Display for Token {
LBrace => write!(f, "("), LBrace => write!(f, "("),
RBrace => write!(f, ")"), RBrace => write!(f, ")"),
// Aggregation // Special
Comma => write!(f, ","), Comma => write!(f, ","),
// Assignment
Assign => write!(f, "="), Assign => write!(f, "="),
Semicolon => write!(f, ";"),
// Values => write!(f, ""), Variables and Functions // Values => write!(f, ""), Variables and Functions
Identifier(identifier) => identifier.fmt(f), Identifier(identifier) => identifier.fmt(f),

View File

@ -28,11 +28,10 @@ pub enum Token {
LBrace, LBrace,
RBrace, RBrace,
// Aggregation // Special
Comma, Comma,
// Assignment
Assign, Assign,
Semicolon,
// Values, Variables and Functions // Values, Variables and Functions
Identifier(String), Identifier(String),
@ -75,6 +74,7 @@ fn char_to_partial_token(c: char) -> PartialToken {
')' => PartialToken::Token(Token::RBrace), ')' => PartialToken::Token(Token::RBrace),
',' => PartialToken::Token(Token::Comma), ',' => PartialToken::Token(Token::Comma),
';' => PartialToken::Token(Token::Semicolon),
c => { c => {
if c.is_whitespace() { if c.is_whitespace() {
@ -111,8 +111,8 @@ impl Token {
Token::RBrace => false, Token::RBrace => false,
Token::Comma => false, Token::Comma => false,
Token::Assign => false, Token::Assign => false,
Token::Semicolon => false,
Token::Identifier(_) => true, Token::Identifier(_) => true,
Token::Float(_) => true, Token::Float(_) => true,
@ -145,8 +145,8 @@ impl Token {
Token::RBrace => true, Token::RBrace => true,
Token::Comma => false, Token::Comma => false,
Token::Assign => false, Token::Assign => false,
Token::Semicolon => false,
Token::Identifier(_) => true, Token::Identifier(_) => true,
Token::Float(_) => true, Token::Float(_) => true,

View File

@ -383,8 +383,8 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
}, },
Token::Comma => Some(Node::new(Tuple)), Token::Comma => Some(Node::new(Tuple)),
Token::Assign => Some(Node::new(Assign)), Token::Assign => Some(Node::new(Assign)),
Token::Semicolon => Some(Node::new(Chain)),
Token::Identifier(identifier) => { Token::Identifier(identifier) => {
let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone()))); let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone())));

View File

@ -522,6 +522,21 @@ fn test_assignment() {
); );
assert_eq!(eval_empty_with_context("empty", &context), Ok(EMPTY_VALUE)); assert_eq!(eval_empty_with_context("empty", &context), Ok(EMPTY_VALUE));
assert_eq!(eval_boolean_with_context("boolean", &context), Ok(false)); assert_eq!(eval_boolean_with_context("boolean", &context), Ok(false));
assert_eq!(
eval_empty_with_context_mut("b = a = 5", &mut context),
Ok(EMPTY_VALUE)
);
assert_eq!(eval_empty_with_context("b", &context), Ok(EMPTY_VALUE));
}
#[test]
fn test_expression_chaining() {
let mut context = HashMapContext::new();
assert_eq!(
eval_int_with_context_mut("a = 5; a = a + 2; a", &mut context),
Ok(7)
);
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]