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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::{
    ir::{
        function::IsIRStatement,
        quantity::{self, Quantity},
        RegisterName,
    },
    utility::{data_type, data_type::Type},
};
use nom::{
    bytes::complete::tag,
    character::{complete::space1, streaming::space0},
    combinator::map,
    sequence::tuple,
    IResult,
};
use serde::{Deserialize, Serialize};
use std::fmt;
/// [`Store`] instruction.
#[derive(Debug, Eq, PartialEq, Clone, Hash, Serialize, Deserialize)]
pub struct Store {
    /// Type of the value to store.
    pub data_type: Type,
    /// Value to store.
    pub source: Quantity,
    /// Where to store the value.
    pub target: Quantity,
}

impl IsIRStatement for Store {
    fn on_register_change(&mut self, from: &RegisterName, to: Quantity) {
        if let Quantity::RegisterName(local) = &mut self.source {
            if local == from {
                *local = to.clone().unwrap_local();
            }
        }
        if let Quantity::RegisterName(local) = &mut self.target {
            if local == from {
                *local = to.unwrap_local();
            }
        }
    }
    fn generate_register(&self) -> Option<(RegisterName, Type)> {
        None
    }
    fn use_register(&self) -> Vec<RegisterName> {
        let mut result = Vec::new();
        if let Quantity::RegisterName(register) = &self.source {
            result.push(register.clone());
        }
        if let Quantity::RegisterName(register) = &self.target {
            result.push(register.clone());
        }
        result
    }
}

impl fmt::Display for Store {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "store {} {}, address {}",
            self.data_type, self.source, self.target
        )
    }
}

/// Parse ir code to get a [`Store`] instruction.
pub fn parse(code: &str) -> IResult<&str, Store> {
    map(
        tuple((
            tag("store"),
            space1,
            data_type::parse,
            space1,
            quantity::parse,
            space0,
            tag(","),
            space0,
            tag("address"),
            space1,
            quantity::parse,
        )),
        |(_, _, data_type, _, source, _, _, _, _, _, target)| Store {
            data_type,
            source,
            target,
        },
    )(code)
}

#[cfg(test)]
pub mod test_util {
    #![allow(clippy::borrow_interior_mutable_const)]
    use super::*;

    pub fn new(variable_name: &str) -> Store {
        Store {
            data_type: data_type::I32.clone(),
            source: 1.into(),
            target: RegisterName(format!("{variable_name}_addr")).into(),
        }
    }

    pub fn with_reg_value(variable_name: &str, reg: &str) -> Store {
        Store {
            data_type: data_type::I32.clone(),
            source: RegisterName(reg.to_string()).into(),
            target: RegisterName(format!("{variable_name}_addr")).into(),
        }
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::borrow_interior_mutable_const)]

    use super::*;

    #[test]
    fn test_parse() {
        let code = "store i32 %0, address %1";
        let (_, store) = parse(code).unwrap();
        assert_eq!(
            store,
            Store {
                data_type: data_type::I32.clone(),
                source: RegisterName("0".to_string()).into(),
                target: RegisterName("1".to_string()).into(),
            }
        );
    }
}