}
fn evaluate(&self, expr: &Expression) -> Result<LocationContainer<Literal>, EvaluationError> {
match expr {
Expression::Binary {
left,
operator,
right,
} => {
let left_loc = self.evaluate(left.borrow())?;
let right_loc = self.evaluate(right.borrow())?;
let operator_tok = operator;
match (
left_loc.inner,
operator_tok.get_token_type(),
right_loc.inner,
) {
(Literal::Number(left), TokenType::Plus, Literal::Number(right)) => {
Ok(LocationContainer {
inner: Literal::Number(left + right),
location: left_loc.location.clone(),
})
}
(Literal::Number(left), TokenType::Minus, Literal::Number(right)) => {
Ok(LocationContainer {
inner: Literal::Number(left - right),
location: left_loc.location.clone(),
})
}
(Literal::Number(left), TokenType::Star, Literal::Number(right)) => {
Ok(LocationContainer {
inner: Literal::Number(left * right),
location: left_loc.location.clone(),
})
}
(Literal::Number(left), TokenType::Slash, Literal::Number(right)) => {
Ok(LocationContainer {
inner: Literal::Number(left / right),
location: left_loc.location.clone(),
})
}
(left, TokenType::Greater, right) => Ok(LocationContainer {
inner: Literal::Boolean(left > right),
location: left_loc.location.clone(),
}),
(left, TokenType::GreaterEqual, right) => Ok(LocationContainer {
inner: Literal::Boolean(left >= right),
location: left_loc.location.clone(),
}),
(left, TokenType::Less, right) => Ok(LocationContainer {
inner: Literal::Boolean(left < right),
location: left_loc.location.clone(),
}),
(left, TokenType::LessEqual, right) => Ok(LocationContainer {
inner: Literal::Boolean(left <= right),
location: left_loc.location.clone(),
}),
(left, TokenType::EqualEqual, right) => Ok(LocationContainer {
inner: Literal::Boolean(left == right),
location: left_loc.location.clone(),
}),
(left, TokenType::BangEqual, right) => Ok(LocationContainer {
inner: Literal::Boolean(left != right),
location: left_loc.location.clone(),
}),
(Literal::String(left), TokenType::Tilde, Literal::String(right)) => {
Ok(LocationContainer {
inner: Literal::String(format!("{}{}", left, right)),
location: left_loc.location.clone(),
})
}
(left, operator, right) if BINARY_OPERATORS.contains(&operator) => {
Err(EvaluationError::InvalidBinaryOperatorType {
location: right_loc.location.clone(),
left,
operator,
right,
})
}
(_, operator, _) => Err(EvaluationError::InvalidBinaryOperator {
location: operator_tok.location.clone(),
operator,
}),
}
}
Expression::Grouping { expression } => self.evaluate(expression),
Expression::Literal { value } => Ok(value.clone()),
Expression::Unary { operator, right } => {
let right_loc = self.evaluate(right.borrow())?;
let operator_tok = operator;
match (operator_tok.get_token_type(), right_loc.inner) {
(lexer::TokenType::Minus, Literal::Number(n)) => Ok(LocationContainer {
inner: Literal::Number(-n),
location: right_loc.location.clone(),
}),
(lexer::TokenType::Bang, Literal::Boolean(b)) => Ok(LocationContainer {
inner: Literal::Boolean(!b),
location: right_loc.location.clone(),
}),
(operator, right) if UNARY_OPERATORS.contains(&operator) => {
Err(EvaluationError::InvalidUnaryOperatorType {
location: right_loc.location.clone(),
operator,
right,
})
}
(operator, _) => Err(EvaluationError::InvalidUnaryOperator {
location: operator_tok.location.clone(),
operator,
}),
}
}
}