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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use super::{
    binary_operator::{self, BinaryOperatorResult},
    field_access::FieldAccess,
    function_call::FunctionCall,
    in_brackets::{self, InBrackets},
    integer_literal::IntegerLiteral,
    lvalue::LValue,
    unary_operator::{self, UnaryOperatorResult},
    variable_ref::VariableRef,
};
use enum_dispatch::enum_dispatch;
use nom::{branch::alt, combinator::map, IResult};

/// Tag trait for [`RValue`].
#[enum_dispatch]
trait IsRValue {}

/// [`RValue`] represents an expression that has a value.
#[enum_dispatch(IsRValue)]
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum RValue {
    IntegerLiteral,
    VariableRef,
    InBrackets,
    FieldAccess,
    FunctionCall,
    UnaryOperatorResult,
    BinaryOperatorResult,
}

/// Parse source code to get a [`RValue`].
pub fn parse(code: &str) -> IResult<&str, RValue> {
    alt((
        map(in_brackets::parse, RValue::InBrackets),
        map(binary_operator::parse, RValue::BinaryOperatorResult),
        map(unary_operator::parse, RValue::UnaryOperatorResult),
        unary_operator::higher_than_unary_operator_result,
    ))(code)
}

impl From<LValue> for RValue {
    fn from(lvalue: LValue) -> Self {
        match lvalue {
            LValue::VariableRef(variable_ref) => RValue::VariableRef(variable_ref),
            LValue::FieldAccess(field_access) => RValue::FieldAccess(field_access),
        }
    }
}

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

    #[test]
    fn can_parse() {
        let rvale = super::parse("42").unwrap().1;
        assert!(matches!(rvale, RValue::IntegerLiteral(_)));

        let rvale = super::parse("a").unwrap().1;
        assert!(matches!(rvale, RValue::VariableRef(_)));

        let rvalue = super::parse("(a+b)").unwrap().1;
        assert!(matches!(rvalue, RValue::InBrackets(_)));

        let rvalue = super::parse("a.b").unwrap().1;
        assert!(matches!(rvalue, RValue::FieldAccess(_)));

        let rvalue = super::parse("f(a, b, c)").unwrap().1;
        assert!(matches!(rvalue, RValue::FunctionCall(_)));

        let rvalue = super::parse("-a").unwrap().1;
        assert!(matches!(rvalue, RValue::UnaryOperatorResult(_)));

        let rvalue = super::parse("a + b").unwrap().1;
        assert!(matches!(rvalue, RValue::BinaryOperatorResult(_)));
    }
}