1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use super::{field_access, function_call, integer_literal, rvalue::RValue, variable_ref};
use nom::{branch::alt, bytes::complete::tag, combinator::map, sequence::tuple, IResult};

/// [`UnaryOperatorResult`] represents result of a unary operator.
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct UnaryOperatorResult {
    /// The operator.
    pub operator: String,
    /// The operand.
    pub operand: Box<RValue>,
}

pub fn higher_than_unary_operator_result(code: &str) -> IResult<&str, RValue> {
    alt((
        map(function_call::parse, RValue::FunctionCall),
        map(field_access::parse, RValue::FieldAccess),
        map(variable_ref::parse, RValue::VariableRef),
        map(integer_literal::parse, RValue::IntegerLiteral),
    ))(code)
}

/// Parse source code to get a [`UnaryOperatorResult`].
pub fn parse(code: &str) -> IResult<&str, UnaryOperatorResult> {
    map(
        tuple((
            alt((tag("+"), tag("-"), tag("!"), tag("~"))),
            higher_than_unary_operator_result,
        )),
        |(op, operand)| UnaryOperatorResult {
            operator: op.to_string(),
            operand: Box::new(operand),
        },
    )(code)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn can_parse() {
        let result = parse("-a").unwrap().1;
        assert_eq!(result.operator, "-");
    }
}