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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Defines value expression representation used in Ledger format.
//! Note this is purely lexicographical and not always valid expression.

use super::pretty_decimal::PrettyDecimal;
use crate::datamodel;

use core::fmt;

/// Amount with presentation information.
/// Similar to `datamodel::Amount` with extra formatting information.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Amount {
    pub value: PrettyDecimal,
    pub commodity: String,
}

impl From<datamodel::Amount> for Amount {
    fn from(value: datamodel::Amount) -> Self {
        Self {
            value: PrettyDecimal::unformatted(value.value),
            commodity: value.commodity,
        }
    }
}

/// Defines value expression.
/// Value expression is a valid expression when used in amount.
/// It can be either amount literal or expression wrapped in `()`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ValueExpr {
    Paren(Expr),
    Amount(Amount),
}

impl From<Amount> for ValueExpr {
    fn from(v: Amount) -> Self {
        ValueExpr::Amount(v)
    }
}

impl From<datamodel::Amount> for ValueExpr {
    fn from(value: datamodel::Amount) -> Self {
        ValueExpr::Amount(value.into())
    }
}

/// Generic expression.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Expr {
    Unary(UnaryOpExpr),
    Binary(BinaryOpExpr),
    Value(Box<ValueExpr>),
}

/// Represents unary operator.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum UnaryOp {
    /// `-x`
    Negate,
}

impl fmt::Display for UnaryOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let op = match self {
            UnaryOp::Negate => "-",
        };
        write!(f, "{}", op)
    }
}

/// Unary operator expression.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct UnaryOpExpr {
    pub op: UnaryOp,
    pub expr: Box<Expr>,
}

/// Binary operator.
#[derive(Debug, PartialEq, Eq, Clone, Copy, strum::EnumIter)]
pub enum BinaryOp {
    /// `+`
    Add,
    /// `-`
    Sub,
    /// `*`
    Mul,
    /// `/`
    Div,
}

impl fmt::Display for BinaryOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let op = match self {
            BinaryOp::Add => "+",
            BinaryOp::Sub => "-",
            BinaryOp::Mul => "*",
            BinaryOp::Div => "/",
        };
        write!(f, "{}", op)
    }
}

/// Represents binary operator expression.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct BinaryOpExpr {
    pub op: BinaryOp,
    pub lhs: Box<Expr>,
    pub rhs: Box<Expr>,
}