cil/text/
opcode.rs

1use std::io::Write;
2use crate::opcode::{Label, OpCode, OpCodeVisitor, OpVisitor};
3
4pub struct OpCodeWriter<'a, W: Write> {
5    out: &'a mut W,
6}
7
8impl<'a, W: Write> OpCodeWriter<'a, W> {
9    pub fn new(out: &'a mut W) -> Self {
10        Self { out }
11    }
12}
13
14impl<'a, W: Write> OpCodeVisitor for OpCodeWriter<'a, W> {
15    type Error = std::io::Error;
16
17    fn visit_nop(&mut self) -> Result<(), Self::Error> {
18        self.out.write_all(b"nop")
19    }
20
21    fn visit_break(&mut self) -> Result<(), Self::Error> {
22        self.out.write_all(b"break")
23    }
24
25    fn visit_ldarg0(&mut self) -> Result<(), Self::Error> {
26        self.out.write_all(b"ldarg.0")
27    }
28
29    fn visit_ldarg1(&mut self) -> Result<(), Self::Error> {
30        self.out.write_all(b"ldarg.1")
31    }
32
33    fn visit_ldarg2(&mut self) -> Result<(), Self::Error> {
34        self.out.write_all(b"ldarg.2")
35    }
36
37    fn visit_ldarg3(&mut self) -> Result<(), Self::Error> {
38        self.out.write_all(b"ldarg.3")
39    }
40
41    fn visit_ldloc0(&mut self) -> Result<(), Self::Error> {
42        self.out.write_all(b"ldloc.0")
43    }
44
45    fn visit_ldloc1(&mut self) -> Result<(), Self::Error> {
46        self.out.write_all(b"ldloc.1")
47    }
48
49    fn visit_ldloc2(&mut self) -> Result<(), Self::Error> {
50        self.out.write_all(b"ldloc.2")
51    }
52
53    fn visit_ldloc3(&mut self) -> Result<(), Self::Error> {
54        self.out.write_all(b"ldloc.3")
55    }
56
57    fn visit_stloc0(&mut self) -> Result<(), Self::Error> {
58        self.out.write_all(b"stloc.0")
59    }
60
61    fn visit_stloc1(&mut self) -> Result<(), Self::Error> {
62        self.out.write_all(b"stloc.1")
63    }
64
65    fn visit_stloc2(&mut self) -> Result<(), Self::Error> {
66        self.out.write_all(b"stloc.2")
67    }
68
69    fn visit_stloc3(&mut self) -> Result<(), Self::Error> {
70        self.out.write_all(b"stloc.3")
71    }
72
73    fn visit_ldnull(&mut self) -> Result<(), Self::Error> {
74        self.out.write_all(b"ldnull")
75    }
76
77    fn visit_ldci4(&mut self, v: i32) -> Result<(), Self::Error> {
78        self.out.write_all(b"ldc.i4 ")?;
79        self.out.write_all(v.to_string().as_bytes())
80    }
81
82    fn visit_ldci8(&mut self, v: i64) -> Result<(), Self::Error> {
83        self.out.write_all(b"ldc.i8 ")?;
84        self.out.write_all(v.to_string().as_bytes())
85    }
86
87    fn visit_ldcr4(&mut self, v: f32) -> Result<(), Self::Error> {
88        let bytes = v.to_le_bytes();
89        self.out.write_all(
90            format!("ldc.r4 ({:02X} {:02X} {:02X} {:02X})",
91            bytes[0],
92            bytes[1],
93            bytes[2],
94            bytes[3]).as_bytes())
95    }
96
97    fn visit_ldcr8(&mut self, v: f64) -> Result<(), Self::Error> {
98        let bytes = v.to_le_bytes();
99        self.out.write_all(
100            format!("ldc.r8 ({:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X} {:02X})",
101            bytes[0],
102            bytes[1],
103            bytes[2],
104            bytes[3],
105            bytes[4],
106            bytes[5],
107            bytes[6],
108            bytes[7]).as_bytes())
109    }
110
111    fn visit_ret(&mut self) -> Result<(), Self::Error> {
112        self.out.write_all(b"ret")
113    }
114
115    fn visit_add(&mut self) -> Result<(), Self::Error> {
116        self.out.write_all(b"add")
117    }
118
119    fn visit_sub(&mut self) -> Result<(), Self::Error> {
120        self.out.write_all(b"sub")
121    }
122
123    fn visit_mul(&mut self) -> Result<(), Self::Error> {
124        self.out.write_all(b"mul")
125    }
126
127    fn visit_div(&mut self) -> Result<(), Self::Error> {
128        self.out.write_all(b"div")
129    }
130
131    fn visit_rem(&mut self) -> Result<(), Self::Error> {
132        self.out.write_all(b"rem")
133    }
134
135    fn visit_ldarg(&mut self, n: u16) -> Result<(), Self::Error> {
136        self.out.write_all(b"ldarg ")?;
137        self.out.write_all(n.to_string().as_bytes())
138    }
139
140    fn visit_ldargs(&mut self, n: u8) -> Result<(), Self::Error> {
141        self.out.write_all(b"ldarg.s ")?;
142        self.out.write_all(n.to_string().as_bytes())
143    }
144
145    fn visit_ldloc(&mut self, n: u16) -> Result<(), Self::Error> {
146        self.out.write_all(b"ldloc ")?;
147        self.out.write_all(n.to_string().as_bytes())
148    }
149
150    fn visit_ldlocs(&mut self, n: u8) -> Result<(), Self::Error> {
151        self.out.write_all(b"ldloc.s ")?;
152        self.out.write_all(n.to_string().as_bytes())
153    }
154
155    fn visit_stloc(&mut self, n: u16) -> Result<(), Self::Error> {
156        self.out.write_all(b"stloc ")?;
157        self.out.write_all(n.to_string().as_bytes())
158    }
159
160    fn visit_starg(&mut self, n: u16) -> Result<(), Self::Error> {
161        self.out.write_all(b"starg ")?;
162        self.out.write_all(n.to_string().as_bytes())
163    }
164
165    fn visit_stargs(&mut self, n: u8) -> Result<(), Self::Error> {
166        self.out.write_all(b"starg.s ")?;
167        self.out.write_all(n.to_string().as_bytes())
168    }
169}
170
171pub struct OpWriter<'a, W: Write> {
172    out: &'a mut W,
173}
174
175impl<'a, W: Write> OpWriter<'a, W> {
176    pub fn new(out: &'a mut W) -> Self {
177        Self { out }
178    }
179}
180
181impl<'a, W: Write> OpVisitor for OpWriter<'a, W> {
182    type Error = std::io::Error;
183
184    fn visit_label(&mut self, label: &Label) -> Result<(), Self::Error> {
185        self.out.write_all(label.name().as_bytes())?;
186        self.out.write_all(b": ")
187    }
188
189    fn visit_code(&mut self, code: &OpCode) -> Result<(), Self::Error> {
190        let mut writer = OpCodeWriter::new(&mut self.out);
191        code.visit(&mut writer)
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use crate::opcode::{Op, nop, ldci4, ldci8, ldcr4, ldcr8};
198    use crate::op;
199    use super::*;
200
201    #[test]
202    fn writer_writes_opcode() {
203        let mut buf = vec![];
204        let mut writer = OpCodeWriter::new(&mut buf);
205        nop.visit(&mut writer).unwrap();
206        assert_eq!(&buf, b"nop");
207    }
208
209    #[test]
210    fn writer_writes_unlabeled_op() {
211        let mut buf = vec![];
212        let mut writer = OpWriter::new(&mut buf);
213        op!(nop).visit(&mut writer).unwrap();
214        assert_eq!(&buf, b"nop");
215    }
216
217    #[test]
218    fn writer_writes_labeled_op() {
219        let mut buf = vec![];
220        let mut writer = OpWriter::new(&mut buf);
221        op!("label", nop).visit(&mut writer).unwrap();
222        assert_eq!(&buf, b"label: nop");
223    }
224
225    #[test]
226    fn writer_writes_ldci4_op() {
227        let mut buf = vec![];
228        let mut writer = OpWriter::new(&mut buf);
229        op!(ldci4(123)).visit(&mut writer).unwrap();
230        assert_eq!(&buf, b"ldc.i4 123");
231    }
232
233    #[test]
234    fn writer_writes_ldci8_op() {
235        let mut buf = vec![];
236        let mut writer = OpWriter::new(&mut buf);
237        op!(ldci8(123)).visit(&mut writer).unwrap();
238        assert_eq!(&buf, b"ldc.i8 123");
239    }
240
241    #[test]
242    fn writer_writes_ldcr4_op() {
243        let mut buf = vec![];
244        let mut writer = OpWriter::new(&mut buf);
245        op!(ldcr4(123.45)).visit(&mut writer).unwrap();
246        assert_eq!(&buf, b"ldc.r4 (66 E6 F6 42)");
247    }
248
249    #[test]
250    fn writer_writes_ldcr8_op() {
251        let mut buf = vec![];
252        let mut writer = OpWriter::new(&mut buf);
253        op!(ldcr8(123.45)).visit(&mut writer).unwrap();
254        assert_eq!(&buf, b"ldc.r8 (CD CC CC CC CC DC 5E 40)");
255    }
256}