Skip to main content

expr/ast/
unary_operator.rs

1use crate::ast::node::Node;
2use crate::Rule;
3use crate::Value::Bool;
4use crate::{bail, Result};
5use crate::{ContextProvider, Environment, Value};
6use log::trace;
7use pest::iterators::Pair;
8
9#[derive(Debug, Clone)]
10pub enum UnaryOperator {
11    Not,
12    Positive,
13    Negative,
14}
15
16impl From<Pair<'_, Rule>> for UnaryOperator {
17    fn from(pair: Pair<Rule>) -> Self {
18        trace!("[unary_operator] {pair:?}");
19        match pair.as_str() {
20            "not" | "!" => UnaryOperator::Not,
21            "+" => UnaryOperator::Positive,
22            "-" => UnaryOperator::Negative,
23            op => unreachable!("Invalid operator {op}"),
24        }
25    }
26}
27
28impl Environment<'_> {
29    pub fn eval_unary_operator(
30        &self,
31        ctx: &dyn ContextProvider,
32        operator: &UnaryOperator,
33        node: &Node,
34    ) -> Result<Value> {
35        let node = self.eval_expr(ctx, node)?;
36        let result = match operator {
37            UnaryOperator::Not => match node {
38                Bool(b) => Bool(!b),
39                _ => bail!("Invalid operand for operator !"),
40            },
41            UnaryOperator::Positive => match node {
42                Value::Integer(n) => Value::Integer(n),
43                Value::Float(f) => Value::Float(f),
44                _ => bail!("Invalid operand for operator +"),
45            },
46            UnaryOperator::Negative => match node {
47                Value::Integer(n) => Value::Integer(n.wrapping_neg()),
48                Value::Float(f) => Value::Float(-f),
49                _ => bail!("Invalid operand for operator -"),
50            },
51        };
52
53        Ok(result)
54    }
55}