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}