glulx_asm/
instr_impls.rs

1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-Exception
2// Copyright 2024 Daniel Fox Franke.
3
4//! Implementations for [`Instr`].
5
6use core::fmt::Display;
7
8use crate::error::AssemblerError;
9use crate::instr_def::Instr;
10use crate::operands::RawOperand;
11use crate::resolver::Resolver;
12use arrayvec::ArrayVec;
13use bytes::BufMut;
14
15/// The largest number of operands taken by any instruction.
16///
17/// `linearsearch` and `binarysearch` set the high-water mark.
18pub(crate) const MAX_OPERANDS: usize = 8;
19
20/// An encoded instruction ready to be serialized.
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22pub(crate) struct RawInstr {
23    /// The instruction's opcode.
24    pub opcode: u32,
25    /// List of operands to the instruction.
26    pub operands: ArrayVec<RawOperand, MAX_OPERANDS>,
27}
28
29/// Return the number of arguments the macro was called with.
30macro_rules! count {
31    ($(,)*) => (0u32);
32    ($current:expr $(,)*) => (1u32);
33    ( $current:expr, $($rest:expr),* $(,)*) => (const { 1 + count!($($rest),*) });
34}
35
36/// Call arg.resolve(position, resolver) for each argument after the
37/// third, correctly updating position for each call. Position at the start of
38/// the invocation should the end of the opcode.
39macro_rules! resolve {
40    ($position:expr, $resolver:expr, $($x:expr),* $(,)*) => {
41        {
42            #[allow(unused_mut)]
43            let mut v = ArrayVec::<RawOperand, MAX_OPERANDS>::new();
44            let n_args = count!($($x),*);
45
46            let mut _position = $position.checked_add(n_args.div_ceil(2))
47                .ok_or(AssemblerError::Overflow)?;
48
49            $(
50                let operand = $x.resolve(_position, $resolver)?;
51                _position = _position.checked_add(u32::try_from(operand.len())
52                    .or(Err(AssemblerError::Overflow))?)
53                    .ok_or(AssemblerError::Overflow)?;
54                v.push(operand);
55            )*
56
57            v
58        }
59    };
60}
61
62/// Call arg.worst_len() on each argument and return the sum of the results plus
63/// the space occupied by the addressing-mode nibbles.
64macro_rules! worst_len {
65    ($($x:expr),* $(,)*) => {
66        {
67            let oplens = [$($x.worst_len()),*];
68            let oplens_slice = oplens.as_slice();
69            let modelen  = oplens_slice.len().div_ceil(2);
70            let oplen_sum = oplens_slice.iter().copied().sum::<usize>();
71            modelen + oplen_sum
72        }
73    };
74}
75
76impl<L> Instr<L> {
77    /// Applies the given mapping function to all labels within the instruction.
78    pub fn map<F, M>(self, mut f: F) -> Instr<M>
79    where
80        F: FnMut(L) -> M,
81    {
82        match self {
83            Instr::Nop => Instr::Nop,
84            Instr::Add(l1, l2, s1) => Instr::Add(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
85            Instr::Sub(l1, l2, s1) => Instr::Sub(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
86            Instr::Mul(l1, l2, s1) => Instr::Mul(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
87            Instr::Div(l1, l2, s1) => Instr::Div(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
88            Instr::Mod(l1, l2, s1) => Instr::Mod(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
89            Instr::Neg(l1, s1) => Instr::Neg(l1.map(&mut f), s1.map(&mut f)),
90            Instr::Bitand(l1, l2, s1) => {
91                Instr::Bitand(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
92            }
93            Instr::Bitor(l1, l2, s1) => {
94                Instr::Bitor(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
95            }
96            Instr::Bitxor(l1, l2, s1) => {
97                Instr::Bitxor(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
98            }
99            Instr::Bitnot(l1, s1) => Instr::Bitnot(l1.map(&mut f), s1.map(&mut f)),
100            Instr::Shiftl(l1, l2, s1) => {
101                Instr::Shiftl(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
102            }
103            Instr::Ushiftr(l1, l2, s1) => {
104                Instr::Ushiftr(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
105            }
106            Instr::Sshiftr(l1, l2, s1) => {
107                Instr::Sshiftr(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
108            }
109            Instr::Jump(l1) => Instr::Jump(l1.map(&mut f)),
110            Instr::Jz(l1, l2) => Instr::Jz(l1.map(&mut f), l2.map(&mut f)),
111            Instr::Jnz(l1, l2) => Instr::Jnz(l1.map(&mut f), l2.map(&mut f)),
112            Instr::Jeq(l1, l2, l3) => Instr::Jeq(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
113            Instr::Jne(l1, l2, l3) => Instr::Jne(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
114            Instr::Jlt(l1, l2, l3) => Instr::Jlt(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
115            Instr::Jle(l1, l2, l3) => Instr::Jle(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
116            Instr::Jgt(l1, l2, l3) => Instr::Jgt(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
117            Instr::Jge(l1, l2, l3) => Instr::Jge(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
118            Instr::Jltu(l1, l2, l3) => Instr::Jltu(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
119            Instr::Jleu(l1, l2, l3) => Instr::Jleu(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
120            Instr::Jgtu(l1, l2, l3) => Instr::Jgtu(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
121            Instr::Jgeu(l1, l2, l3) => Instr::Jgeu(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
122            Instr::Jumpabs(l1) => Instr::Jumpabs(l1.map(&mut f)),
123            Instr::Copy(l1, s1) => Instr::Copy(l1.map(&mut f), s1.map(&mut f)),
124            Instr::Copys(l1, s1) => Instr::Copys(l1.map(&mut f), s1.map(&mut f)),
125            Instr::Copyb(l1, s1) => Instr::Copyb(l1.map(&mut f), s1.map(&mut f)),
126            Instr::Sexs(l1, s1) => Instr::Sexs(l1.map(&mut f), s1.map(&mut f)),
127            Instr::Sexb(l1, s1) => Instr::Sexb(l1.map(&mut f), s1.map(&mut f)),
128            Instr::Astore(l1, l2, l3) => {
129                Instr::Astore(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
130            }
131            Instr::Aload(l1, l2, s1) => {
132                Instr::Aload(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
133            }
134            Instr::Astores(l1, l2, l3) => {
135                Instr::Astores(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
136            }
137            Instr::Aloads(l1, l2, s1) => {
138                Instr::Aloads(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
139            }
140            Instr::Astoreb(l1, l2, l3) => {
141                Instr::Astoreb(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
142            }
143            Instr::Aloadb(l1, l2, s1) => {
144                Instr::Aloadb(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
145            }
146            Instr::Astorebit(l1, l2, l3) => {
147                Instr::Astorebit(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
148            }
149            Instr::Aloadbit(l1, l2, s1) => {
150                Instr::Aloadbit(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
151            }
152            Instr::Stkcount(s1) => Instr::Stkcount(s1.map(&mut f)),
153            Instr::Stkpeek(l1, s1) => Instr::Stkpeek(l1.map(&mut f), s1.map(&mut f)),
154            Instr::Stkswap => Instr::Stkswap,
155            Instr::Stkcopy(l1) => Instr::Stkcopy(l1.map(&mut f)),
156            Instr::Stkroll(l1, l2) => Instr::Stkroll(l1.map(&mut f), l2.map(&mut f)),
157            Instr::Call(l1, l2, s1) => Instr::Call(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
158            Instr::Callf(l1, s1) => Instr::Callf(l1.map(&mut f), s1.map(&mut f)),
159            Instr::Callfi(l1, l2, s1) => {
160                Instr::Callfi(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
161            }
162            Instr::Callfii(l1, l2, l3, s1) => Instr::Callfii(
163                l1.map(&mut f),
164                l2.map(&mut f),
165                l3.map(&mut f),
166                s1.map(&mut f),
167            ),
168            Instr::Callfiii(l1, l2, l3, l4, s1) => Instr::Callfiii(
169                l1.map(&mut f),
170                l2.map(&mut f),
171                l3.map(&mut f),
172                l4.map(&mut f),
173                s1.map(&mut f),
174            ),
175            Instr::Return(l1) => Instr::Return(l1.map(&mut f)),
176            Instr::Tailcall(l1, l2) => Instr::Tailcall(l1.map(&mut f), l2.map(&mut f)),
177            Instr::Catch(s1, l1) => Instr::Catch(s1.map(&mut f), l1.map(&mut f)),
178            Instr::Throw(l1, l2) => Instr::Throw(l1.map(&mut f), l2.map(&mut f)),
179            Instr::Getmemsize(s1) => Instr::Getmemsize(s1.map(&mut f)),
180            Instr::Setmemsize(l1, s1) => Instr::Setmemsize(l1.map(&mut f), s1.map(&mut f)),
181            Instr::Malloc(l1, s1) => Instr::Malloc(l1.map(&mut f), s1.map(&mut f)),
182            Instr::Mfree(l1) => Instr::Mfree(l1.map(&mut f)),
183            Instr::Quit => Instr::Quit,
184            Instr::Restart => Instr::Restart,
185            Instr::Save(l1, s1) => Instr::Save(l1.map(&mut f), s1.map(&mut f)),
186            Instr::Restore(l1, s1) => Instr::Restore(l1.map(&mut f), s1.map(&mut f)),
187            Instr::Saveundo(s1) => Instr::Saveundo(s1.map(&mut f)),
188            Instr::Restoreundo(s1) => Instr::Restoreundo(s1.map(&mut f)),
189            Instr::Hasundo(s1) => Instr::Hasundo(s1.map(&mut f)),
190            Instr::Discardundo => Instr::Discardundo,
191            Instr::Protect(l1, l2) => Instr::Protect(l1.map(&mut f), l2.map(&mut f)),
192            Instr::Verify(s1) => Instr::Verify(s1.map(&mut f)),
193            Instr::Getiosys(s1, s2) => Instr::Getiosys(s1.map(&mut f), s2.map(&mut f)),
194            Instr::Setiosys(l1, l2) => Instr::Setiosys(l1.map(&mut f), l2.map(&mut f)),
195            Instr::Streamchar(l1) => Instr::Streamchar(l1.map(&mut f)),
196            Instr::Streamunichar(l1) => Instr::Streamunichar(l1.map(&mut f)),
197            Instr::Streamnum(l1) => Instr::Streamnum(l1.map(&mut f)),
198            Instr::Streamstr(l1) => Instr::Streamstr(l1.map(&mut f)),
199            Instr::Getstringtbl(s1) => Instr::Getstringtbl(s1.map(&mut f)),
200            Instr::Setstringtbl(l1) => Instr::Setstringtbl(l1.map(&mut f)),
201            Instr::Numtof(l1, s1) => Instr::Numtof(l1.map(&mut f), s1.map(&mut f)),
202            Instr::Ftonumz(l1, s1) => Instr::Ftonumz(l1.map(&mut f), s1.map(&mut f)),
203            Instr::Ftonumn(l1, s1) => Instr::Ftonumn(l1.map(&mut f), s1.map(&mut f)),
204            Instr::Fadd(l1, l2, s1) => Instr::Fadd(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
205            Instr::Fsub(l1, l2, s1) => Instr::Fsub(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
206            Instr::Fmul(l1, l2, s1) => Instr::Fmul(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
207            Instr::Fdiv(l1, l2, s1) => Instr::Fdiv(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
208            Instr::Fmod(l1, l2, s1, s2) => Instr::Fmod(
209                l1.map(&mut f),
210                l2.map(&mut f),
211                s1.map(&mut f),
212                s2.map(&mut f),
213            ),
214            Instr::Ceil(l1, s1) => Instr::Ceil(l1.map(&mut f), s1.map(&mut f)),
215            Instr::Floor(l1, s1) => Instr::Floor(l1.map(&mut f), s1.map(&mut f)),
216            Instr::Sqrt(l1, s1) => Instr::Sqrt(l1.map(&mut f), s1.map(&mut f)),
217            Instr::Exp(l1, s1) => Instr::Exp(l1.map(&mut f), s1.map(&mut f)),
218            Instr::Log(l1, s1) => Instr::Log(l1.map(&mut f), s1.map(&mut f)),
219            Instr::Pow(l1, l2, s1) => Instr::Pow(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
220            Instr::Sin(l1, s1) => Instr::Sin(l1.map(&mut f), s1.map(&mut f)),
221            Instr::Cos(l1, s1) => Instr::Cos(l1.map(&mut f), s1.map(&mut f)),
222            Instr::Tan(l1, s1) => Instr::Tan(l1.map(&mut f), s1.map(&mut f)),
223            Instr::Asin(l1, s1) => Instr::Asin(l1.map(&mut f), s1.map(&mut f)),
224            Instr::Acos(l1, s1) => Instr::Acos(l1.map(&mut f), s1.map(&mut f)),
225            Instr::Atan(l1, s1) => Instr::Atan(l1.map(&mut f), s1.map(&mut f)),
226            Instr::Atan2(l1, s1) => Instr::Atan2(l1.map(&mut f), s1.map(&mut f)),
227            Instr::Numtod(l1, s1, s2) => {
228                Instr::Numtod(l1.map(&mut f), s1.map(&mut f), s2.map(&mut f))
229            }
230            Instr::Dtonumz(l1, l2, s1) => {
231                Instr::Dtonumz(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
232            }
233            Instr::Dtonumn(l1, l2, s1) => {
234                Instr::Dtonumn(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
235            }
236            Instr::Ftod(l1, s1, s2) => Instr::Ftod(l1.map(&mut f), s1.map(&mut f), s2.map(&mut f)),
237            Instr::Dtof(l1, l2, s1) => Instr::Dtof(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
238            Instr::Dadd(l1, l2, l3, l4, s1, s2) => Instr::Dadd(
239                l1.map(&mut f),
240                l2.map(&mut f),
241                l3.map(&mut f),
242                l4.map(&mut f),
243                s1.map(&mut f),
244                s2.map(&mut f),
245            ),
246            Instr::Dsub(l1, l2, l3, l4, s1, s2) => Instr::Dsub(
247                l1.map(&mut f),
248                l2.map(&mut f),
249                l3.map(&mut f),
250                l4.map(&mut f),
251                s1.map(&mut f),
252                s2.map(&mut f),
253            ),
254            Instr::Dmul(l1, l2, l3, l4, s1, s2) => Instr::Dmul(
255                l1.map(&mut f),
256                l2.map(&mut f),
257                l3.map(&mut f),
258                l4.map(&mut f),
259                s1.map(&mut f),
260                s2.map(&mut f),
261            ),
262            Instr::Ddiv(l1, l2, l3, l4, s1, s2) => Instr::Ddiv(
263                l1.map(&mut f),
264                l2.map(&mut f),
265                l3.map(&mut f),
266                l4.map(&mut f),
267                s1.map(&mut f),
268                s2.map(&mut f),
269            ),
270            Instr::Dmodr(l1, l2, l3, l4, s1, s2) => Instr::Dmodr(
271                l1.map(&mut f),
272                l2.map(&mut f),
273                l3.map(&mut f),
274                l4.map(&mut f),
275                s1.map(&mut f),
276                s2.map(&mut f),
277            ),
278            Instr::Dmodq(l1, l2, l3, l4, s1, s2) => Instr::Dmodq(
279                l1.map(&mut f),
280                l2.map(&mut f),
281                l3.map(&mut f),
282                l4.map(&mut f),
283                s1.map(&mut f),
284                s2.map(&mut f),
285            ),
286            Instr::Dceil(l1, l2, s1, s2) => Instr::Dceil(
287                l1.map(&mut f),
288                l2.map(&mut f),
289                s1.map(&mut f),
290                s2.map(&mut f),
291            ),
292            Instr::Dfloor(l1, l2, s1, s2) => Instr::Dfloor(
293                l1.map(&mut f),
294                l2.map(&mut f),
295                s1.map(&mut f),
296                s2.map(&mut f),
297            ),
298            Instr::Dsqrt(l1, l2, s1, s2) => Instr::Dsqrt(
299                l1.map(&mut f),
300                l2.map(&mut f),
301                s1.map(&mut f),
302                s2.map(&mut f),
303            ),
304            Instr::Dexp(l1, l2, s1, s2) => Instr::Dexp(
305                l1.map(&mut f),
306                l2.map(&mut f),
307                s1.map(&mut f),
308                s2.map(&mut f),
309            ),
310            Instr::Dlog(l1, l2, s1, s2) => Instr::Dlog(
311                l1.map(&mut f),
312                l2.map(&mut f),
313                s1.map(&mut f),
314                s2.map(&mut f),
315            ),
316            Instr::Dpow(l1, l2, l3, l4, s1, s2) => Instr::Dpow(
317                l1.map(&mut f),
318                l2.map(&mut f),
319                l3.map(&mut f),
320                l4.map(&mut f),
321                s1.map(&mut f),
322                s2.map(&mut f),
323            ),
324            Instr::Dsin(l1, l2, s1, s2) => Instr::Dsin(
325                l1.map(&mut f),
326                l2.map(&mut f),
327                s1.map(&mut f),
328                s2.map(&mut f),
329            ),
330            Instr::Dcos(l1, l2, s1, s2) => Instr::Dcos(
331                l1.map(&mut f),
332                l2.map(&mut f),
333                s1.map(&mut f),
334                s2.map(&mut f),
335            ),
336            Instr::Dtan(l1, l2, s1, s2) => Instr::Dtan(
337                l1.map(&mut f),
338                l2.map(&mut f),
339                s1.map(&mut f),
340                s2.map(&mut f),
341            ),
342            Instr::Dasin(l1, l2, s1, s2) => Instr::Dasin(
343                l1.map(&mut f),
344                l2.map(&mut f),
345                s1.map(&mut f),
346                s2.map(&mut f),
347            ),
348            Instr::Dacos(l1, l2, s1, s2) => Instr::Dacos(
349                l1.map(&mut f),
350                l2.map(&mut f),
351                s1.map(&mut f),
352                s2.map(&mut f),
353            ),
354            Instr::Datan(l1, l2, s1, s2) => Instr::Datan(
355                l1.map(&mut f),
356                l2.map(&mut f),
357                s1.map(&mut f),
358                s2.map(&mut f),
359            ),
360            Instr::Datan2(l1, l2, l3, l4, s1, s2) => Instr::Datan2(
361                l1.map(&mut f),
362                l2.map(&mut f),
363                l3.map(&mut f),
364                l4.map(&mut f),
365                s1.map(&mut f),
366                s2.map(&mut f),
367            ),
368            Instr::Jisnan(l1, l2) => Instr::Jisnan(l1.map(&mut f), l2.map(&mut f)),
369            Instr::Jisinf(l1, l2) => Instr::Jisinf(l1.map(&mut f), l2.map(&mut f)),
370            Instr::Jfeq(l1, l2, l3, l4) => Instr::Jfeq(
371                l1.map(&mut f),
372                l2.map(&mut f),
373                l3.map(&mut f),
374                l4.map(&mut f),
375            ),
376            Instr::Jfne(l1, l2, l3, l4) => Instr::Jfne(
377                l1.map(&mut f),
378                l2.map(&mut f),
379                l3.map(&mut f),
380                l4.map(&mut f),
381            ),
382            Instr::Jflt(l1, l2, l3) => Instr::Jflt(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
383            Instr::Jfle(l1, l2, l3) => Instr::Jfle(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
384            Instr::Jfgt(l1, l2, l3) => Instr::Jfgt(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
385            Instr::Jfge(l1, l2, l3) => Instr::Jfge(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f)),
386            Instr::Jdisnan(l1, l2, l3) => {
387                Instr::Jdisnan(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
388            }
389            Instr::Jdisinf(l1, l2, l3) => {
390                Instr::Jdisinf(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
391            }
392            Instr::Jdeq(l1, l2, l3, l4, l5, l6, l7) => Instr::Jdeq(
393                l1.map(&mut f),
394                l2.map(&mut f),
395                l3.map(&mut f),
396                l4.map(&mut f),
397                l5.map(&mut f),
398                l6.map(&mut f),
399                l7.map(&mut f),
400            ),
401            Instr::Jdne(l1, l2, l3, l4, l5, l6, l7) => Instr::Jdne(
402                l1.map(&mut f),
403                l2.map(&mut f),
404                l3.map(&mut f),
405                l4.map(&mut f),
406                l5.map(&mut f),
407                l6.map(&mut f),
408                l7.map(&mut f),
409            ),
410            Instr::Jdlt(l1, l2, l3, l4, l5) => Instr::Jdlt(
411                l1.map(&mut f),
412                l2.map(&mut f),
413                l3.map(&mut f),
414                l4.map(&mut f),
415                l5.map(&mut f),
416            ),
417            Instr::Jdle(l1, l2, l3, l4, l5) => Instr::Jdle(
418                l1.map(&mut f),
419                l2.map(&mut f),
420                l3.map(&mut f),
421                l4.map(&mut f),
422                l5.map(&mut f),
423            ),
424            Instr::Jdgt(l1, l2, l3, l4, l5) => Instr::Jdgt(
425                l1.map(&mut f),
426                l2.map(&mut f),
427                l3.map(&mut f),
428                l4.map(&mut f),
429                l5.map(&mut f),
430            ),
431            Instr::Jdge(l1, l2, l3, l4, l5) => Instr::Jdge(
432                l1.map(&mut f),
433                l2.map(&mut f),
434                l3.map(&mut f),
435                l4.map(&mut f),
436                l5.map(&mut f),
437            ),
438            Instr::Random(l1, s1) => Instr::Random(l1.map(&mut f), s1.map(&mut f)),
439            Instr::Setrandom(l1) => Instr::Setrandom(l1.map(&mut f)),
440            Instr::Mzero(l1, l2) => Instr::Mzero(l1.map(&mut f), l2.map(&mut f)),
441            Instr::Mcopy(l1, l2, l3) => {
442                Instr::Mcopy(l1.map(&mut f), l2.map(&mut f), l3.map(&mut f))
443            }
444            Instr::Linearsearch(l1, l2, l3, l4, l5, l6, l7, s1) => Instr::Linearsearch(
445                l1.map(&mut f),
446                l2.map(&mut f),
447                l3.map(&mut f),
448                l4.map(&mut f),
449                l5.map(&mut f),
450                l6.map(&mut f),
451                l7.map(&mut f),
452                s1.map(&mut f),
453            ),
454            Instr::Binarysearch(l1, l2, l3, l4, l5, l6, l7, s1) => Instr::Binarysearch(
455                l1.map(&mut f),
456                l2.map(&mut f),
457                l3.map(&mut f),
458                l4.map(&mut f),
459                l5.map(&mut f),
460                l6.map(&mut f),
461                l7.map(&mut f),
462                s1.map(&mut f),
463            ),
464            Instr::Linkedsearch(l1, l2, l3, l4, l5, l6, s1) => Instr::Linkedsearch(
465                l1.map(&mut f),
466                l2.map(&mut f),
467                l3.map(&mut f),
468                l4.map(&mut f),
469                l5.map(&mut f),
470                l6.map(&mut f),
471                s1.map(&mut f),
472            ),
473            Instr::Accelfunc(l1, l2) => Instr::Accelfunc(l1.map(&mut f), l2.map(&mut f)),
474            Instr::Accelparam(l1, l2) => Instr::Accelparam(l1.map(&mut f), l2.map(&mut f)),
475            Instr::Gestalt(l1, l2, s1) => {
476                Instr::Gestalt(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f))
477            }
478            Instr::Debugtrap(l1) => Instr::Debugtrap(l1.map(&mut f)),
479            Instr::Glk(l1, l2, s1) => Instr::Glk(l1.map(&mut f), l2.map(&mut f), s1.map(&mut f)),
480        }
481    }
482}
483
484impl<L> Instr<L>
485where
486    L: Clone,
487{
488    /// Returns an upper bound on how long the serialized instruction might be,
489    /// regardless of its position.
490    pub(crate) fn worst_len(&self) -> usize {
491        let opcode = self.opcode();
492        let opcode_length = opcode_len(opcode);
493
494        let operands_length: usize = match self {
495            Instr::Nop => 0,
496            Instr::Add(l1, l2, s1) => worst_len!(l1, l2, s1),
497            Instr::Sub(l1, l2, s1) => worst_len!(l1, l2, s1),
498            Instr::Mul(l1, l2, s1) => worst_len!(l1, l2, s1),
499            Instr::Div(l1, l2, s1) => worst_len!(l1, l2, s1),
500            Instr::Mod(l1, l2, s1) => worst_len!(l1, l2, s1),
501            Instr::Neg(l1, s1) => worst_len!(l1, s1),
502            Instr::Bitand(l1, l2, s1) => worst_len!(l1, l2, s1),
503            Instr::Bitor(l1, l2, s1) => worst_len!(l1, l2, s1),
504            Instr::Bitxor(l1, l2, s1) => worst_len!(l1, l2, s1),
505            Instr::Bitnot(l1, s1) => worst_len!(l1, s1),
506            Instr::Shiftl(l1, l2, s1) => worst_len!(l1, l2, s1),
507            Instr::Ushiftr(l1, l2, s1) => worst_len!(l1, l2, s1),
508            Instr::Sshiftr(l1, l2, s1) => worst_len!(l1, l2, s1),
509            Instr::Jump(l1) => worst_len!(l1),
510            Instr::Jz(l1, l2) => worst_len!(l1, l2),
511            Instr::Jnz(l1, l2) => worst_len!(l1, l2),
512            Instr::Jeq(l1, l2, l3) => worst_len!(l1, l2, l3),
513            Instr::Jne(l1, l2, l3) => worst_len!(l1, l2, l3),
514            Instr::Jlt(l1, l2, l3) => worst_len!(l1, l2, l3),
515            Instr::Jle(l1, l2, l3) => worst_len!(l1, l2, l3),
516            Instr::Jgt(l1, l2, l3) => worst_len!(l1, l2, l3),
517            Instr::Jge(l1, l2, l3) => worst_len!(l1, l2, l3),
518            Instr::Jltu(l1, l2, l3) => worst_len!(l1, l2, l3),
519            Instr::Jleu(l1, l2, l3) => worst_len!(l1, l2, l3),
520            Instr::Jgtu(l1, l2, l3) => worst_len!(l1, l2, l3),
521            Instr::Jgeu(l1, l2, l3) => worst_len!(l1, l2, l3),
522            Instr::Jumpabs(l1) => worst_len!(l1),
523            Instr::Copy(l1, s1) => worst_len!(l1, s1),
524            Instr::Copys(l1, s1) => worst_len!(l1, s1),
525            Instr::Copyb(l1, s1) => worst_len!(l1, s1),
526            Instr::Sexs(l1, s1) => worst_len!(l1, s1),
527            Instr::Sexb(l1, s1) => worst_len!(l1, s1),
528            Instr::Astore(l1, l2, l3) => worst_len!(l1, l2, l3),
529            Instr::Aload(l1, l2, s1) => worst_len!(l1, l2, s1),
530            Instr::Astores(l1, l2, l3) => worst_len!(l1, l2, l3),
531            Instr::Aloads(l1, l2, s1) => worst_len!(l1, l2, s1),
532            Instr::Astoreb(l1, l2, l3) => worst_len!(l1, l2, l3),
533            Instr::Aloadb(l1, l2, s1) => worst_len!(l1, l2, s1),
534            Instr::Astorebit(l1, l2, l3) => worst_len!(l1, l2, l3),
535            Instr::Aloadbit(l1, l2, s1) => worst_len!(l1, l2, s1),
536            Instr::Stkcount(s1) => worst_len!(s1),
537            Instr::Stkpeek(l1, s1) => worst_len!(l1, s1),
538            Instr::Stkswap => 0,
539            Instr::Stkcopy(l1) => worst_len!(l1),
540            Instr::Stkroll(l1, l2) => worst_len!(l1, l2),
541            Instr::Call(l1, l2, s1) => worst_len!(l1, l2, s1),
542            Instr::Callf(l1, s1) => worst_len!(l1, s1),
543            Instr::Callfi(l1, l2, s1) => worst_len!(l1, l2, s1),
544            Instr::Callfii(l1, l2, l3, s1) => worst_len!(l1, l2, l3, s1),
545            Instr::Callfiii(l1, l2, l3, l4, s1) => worst_len!(l1, l2, l3, l4, s1),
546            Instr::Return(l1) => worst_len!(l1),
547            Instr::Tailcall(l1, l2) => worst_len!(l1, l2),
548            Instr::Catch(s1, l1) => worst_len!(s1, l1),
549            Instr::Throw(l1, l2) => worst_len!(l1, l2),
550            Instr::Getmemsize(s1) => worst_len!(s1),
551            Instr::Setmemsize(l1, s1) => worst_len!(l1, s1),
552            Instr::Malloc(l1, s1) => worst_len!(l1, s1),
553            Instr::Mfree(l1) => worst_len!(l1),
554            Instr::Quit => 0,
555            Instr::Restart => 0,
556            Instr::Save(l1, s1) => worst_len!(l1, s1),
557            Instr::Restore(l1, s1) => worst_len!(l1, s1),
558            Instr::Saveundo(s1) => worst_len!(s1),
559            Instr::Restoreundo(s1) => worst_len!(s1),
560            Instr::Hasundo(s1) => worst_len!(s1),
561            Instr::Discardundo => 0,
562            Instr::Protect(l1, l2) => worst_len!(l1, l2),
563            Instr::Verify(s1) => worst_len!(s1),
564            Instr::Getiosys(s1, s2) => worst_len!(s1, s2),
565            Instr::Setiosys(l1, l2) => worst_len!(l1, l2),
566            Instr::Streamchar(l1) => worst_len!(l1),
567            Instr::Streamunichar(l1) => worst_len!(l1),
568            Instr::Streamnum(l1) => worst_len!(l1),
569            Instr::Streamstr(l1) => worst_len!(l1),
570            Instr::Getstringtbl(s1) => worst_len!(s1),
571            Instr::Setstringtbl(l1) => worst_len!(l1),
572            Instr::Numtof(l1, s1) => worst_len!(l1, s1),
573            Instr::Ftonumz(l1, s1) => worst_len!(l1, s1),
574            Instr::Ftonumn(l1, s1) => worst_len!(l1, s1),
575            Instr::Fadd(l1, l2, s1) => worst_len!(l1, l2, s1),
576            Instr::Fsub(l1, l2, s1) => worst_len!(l1, l2, s1),
577            Instr::Fmul(l1, l2, s1) => worst_len!(l1, l2, s1),
578            Instr::Fdiv(l1, l2, s1) => worst_len!(l1, l2, s1),
579            Instr::Fmod(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
580            Instr::Ceil(l1, s1) => worst_len!(l1, s1),
581            Instr::Floor(l1, s1) => worst_len!(l1, s1),
582            Instr::Sqrt(l1, s1) => worst_len!(l1, s1),
583            Instr::Exp(l1, s1) => worst_len!(l1, s1),
584            Instr::Log(l1, s1) => worst_len!(l1, s1),
585            Instr::Pow(l1, l2, s1) => worst_len!(l1, l2, s1),
586            Instr::Sin(l1, s1) => worst_len!(l1, s1),
587            Instr::Cos(l1, s1) => worst_len!(l1, s1),
588            Instr::Tan(l1, s1) => worst_len!(l1, s1),
589            Instr::Asin(l1, s1) => worst_len!(l1, s1),
590            Instr::Acos(l1, s1) => worst_len!(l1, s1),
591            Instr::Atan(l1, s1) => worst_len!(l1, s1),
592            Instr::Atan2(l1, s1) => worst_len!(l1, s1),
593            Instr::Numtod(l1, s1, s2) => worst_len!(l1, s1, s2),
594            Instr::Dtonumz(l1, l2, s1) => worst_len!(l1, l2, s1),
595            Instr::Dtonumn(l1, l2, s1) => worst_len!(l1, l2, s1),
596            Instr::Ftod(l1, s1, s2) => worst_len!(l1, s1, s2),
597            Instr::Dtof(l1, l2, s1) => worst_len!(l1, l2, s1),
598            Instr::Dadd(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
599            Instr::Dsub(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
600            Instr::Dmul(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
601            Instr::Ddiv(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
602            Instr::Dmodr(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
603            Instr::Dmodq(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
604            Instr::Dceil(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
605            Instr::Dfloor(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
606            Instr::Dsqrt(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
607            Instr::Dexp(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
608            Instr::Dlog(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
609            Instr::Dpow(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
610            Instr::Dsin(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
611            Instr::Dcos(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
612            Instr::Dtan(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
613            Instr::Dasin(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
614            Instr::Dacos(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
615            Instr::Datan(l1, l2, s1, s2) => worst_len!(l1, l2, s1, s2),
616            Instr::Datan2(l1, l2, l3, l4, s1, s2) => worst_len!(l1, l2, l3, l4, s1, s2),
617            Instr::Jisnan(l1, l2) => worst_len!(l1, l2),
618            Instr::Jisinf(l1, l2) => worst_len!(l1, l2),
619            Instr::Jfeq(l1, l2, l3, l4) => worst_len!(l1, l2, l3, l4),
620            Instr::Jfne(l1, l2, l3, l4) => worst_len!(l1, l2, l3, l4),
621            Instr::Jflt(l1, l2, l3) => worst_len!(l1, l2, l3),
622            Instr::Jfle(l1, l2, l3) => worst_len!(l1, l2, l3),
623            Instr::Jfgt(l1, l2, l3) => worst_len!(l1, l2, l3),
624            Instr::Jfge(l1, l2, l3) => worst_len!(l1, l2, l3),
625            Instr::Jdisnan(l1, l2, l3) => worst_len!(l1, l2, l3),
626            Instr::Jdisinf(l1, l2, l3) => worst_len!(l1, l2, l3),
627            Instr::Jdeq(l1, l2, l3, l4, l5, l6, l7) => worst_len!(l1, l2, l3, l4, l5, l6, l7),
628            Instr::Jdne(l1, l2, l3, l4, l5, l6, l7) => worst_len!(l1, l2, l3, l4, l5, l6, l7),
629            Instr::Jdlt(l1, l2, l3, l4, l5) => worst_len!(l1, l2, l3, l4, l5),
630            Instr::Jdle(l1, l2, l3, l4, l5) => worst_len!(l1, l2, l3, l4, l5),
631            Instr::Jdgt(l1, l2, l3, l4, l5) => worst_len!(l1, l2, l3, l4, l5),
632            Instr::Jdge(l1, l2, l3, l4, l5) => worst_len!(l1, l2, l3, l4, l5),
633            Instr::Random(l1, s1) => worst_len!(l1, s1),
634            Instr::Setrandom(l1) => worst_len!(l1),
635            Instr::Mzero(l1, l2) => worst_len!(l1, l2),
636            Instr::Mcopy(l1, l2, l3) => worst_len!(l1, l2, l3),
637            Instr::Linearsearch(l1, l2, l3, l4, l5, l6, l7, s1) => {
638                worst_len!(l1, l2, l3, l4, l5, l6, l7, s1)
639            }
640            Instr::Binarysearch(l1, l2, l3, l4, l5, l6, l7, s1) => {
641                worst_len!(l1, l2, l3, l4, l5, l6, l7, s1)
642            }
643            Instr::Linkedsearch(l1, l2, l3, l4, l5, l6, s1) => {
644                worst_len!(l1, l2, l3, l4, l5, l6, s1)
645            }
646            Instr::Accelfunc(l1, l2) => worst_len!(l1, l2),
647            Instr::Accelparam(l1, l2) => worst_len!(l1, l2),
648            Instr::Gestalt(l1, l2, s1) => worst_len!(l1, l2, s1),
649            Instr::Debugtrap(l1) => worst_len!(l1),
650            Instr::Glk(l1, l2, s1) => worst_len!(l1, l2, s1),
651        };
652
653        opcode_length + operands_length
654    }
655
656    /// Returrns the instruction's opcode.
657    pub fn opcode(&self) -> u32 {
658        match self {
659            Instr::Nop => 0x00,
660            Instr::Add(_, _, _) => 0x10,
661            Instr::Sub(_, _, _) => 0x11,
662            Instr::Mul(_, _, _) => 0x12,
663            Instr::Div(_, _, _) => 0x13,
664            Instr::Mod(_, _, _) => 0x14,
665            Instr::Neg(_, _) => 0x15,
666            Instr::Bitand(_, _, _) => 0x18,
667            Instr::Bitor(_, _, _) => 0x19,
668            Instr::Bitxor(_, _, _) => 0x1A,
669            Instr::Bitnot(_, _) => 0x1B,
670            Instr::Shiftl(_, _, _) => 0x1C,
671            Instr::Sshiftr(_, _, _) => 0x1D,
672            Instr::Ushiftr(_, _, _) => 0x1E,
673            Instr::Jump(_) => 0x20,
674            Instr::Jz(_, _) => 0x22,
675            Instr::Jnz(_, _) => 0x23,
676            Instr::Jeq(_, _, _) => 0x24,
677            Instr::Jne(_, _, _) => 0x25,
678            Instr::Jlt(_, _, _) => 0x26,
679            Instr::Jge(_, _, _) => 0x27,
680            Instr::Jgt(_, _, _) => 0x28,
681            Instr::Jle(_, _, _) => 0x29,
682            Instr::Jltu(_, _, _) => 0x2A,
683            Instr::Jgeu(_, _, _) => 0x2B,
684            Instr::Jgtu(_, _, _) => 0x2C,
685            Instr::Jleu(_, _, _) => 0x2D,
686            Instr::Call(_, _, _) => 0x30,
687            Instr::Return(_) => 0x31,
688            Instr::Catch(_, _) => 0x32,
689            Instr::Throw(_, _) => 0x33,
690            Instr::Tailcall(_, _) => 0x34,
691            Instr::Copy(_, _) => 0x40,
692            Instr::Copys(_, _) => 0x41,
693            Instr::Copyb(_, _) => 0x42,
694            Instr::Sexs(_, _) => 0x44,
695            Instr::Sexb(_, _) => 0x45,
696            Instr::Aload(_, _, _) => 0x48,
697            Instr::Aloads(_, _, _) => 0x49,
698            Instr::Aloadb(_, _, _) => 0x4A,
699            Instr::Aloadbit(_, _, _) => 0x4B,
700            Instr::Astore(_, _, _) => 0x4C,
701            Instr::Astores(_, _, _) => 0x4D,
702            Instr::Astoreb(_, _, _) => 0x4E,
703            Instr::Astorebit(_, _, _) => 0x4F,
704            Instr::Stkcount(_) => 0x50,
705            Instr::Stkpeek(_, _) => 0x51,
706            Instr::Stkswap => 0x52,
707            Instr::Stkroll(_, _) => 0x53,
708            Instr::Stkcopy(_) => 0x54,
709            Instr::Streamchar(_) => 0x70,
710            Instr::Streamnum(_) => 0x71,
711            Instr::Streamstr(_) => 0x72,
712            Instr::Streamunichar(_) => 0x73,
713            Instr::Gestalt(_, _, _) => 0x100,
714            Instr::Debugtrap(_) => 0x101,
715            Instr::Getmemsize(_) => 0x102,
716            Instr::Setmemsize(_, _) => 0x103,
717            Instr::Jumpabs(_) => 0x104,
718            Instr::Random(_, _) => 0x110,
719            Instr::Setrandom(_) => 0x111,
720            Instr::Quit => 0x120,
721            Instr::Verify(_) => 0x121,
722            Instr::Restart => 0x122,
723            Instr::Save(_, _) => 0x123,
724            Instr::Restore(_, _) => 0x124,
725            Instr::Saveundo(_) => 0x125,
726            Instr::Restoreundo(_) => 0x126,
727            Instr::Protect(_, _) => 0x127,
728            Instr::Hasundo(_) => 0x128,
729            Instr::Discardundo => 0x129,
730            Instr::Glk(_, _, _) => 0x130,
731            Instr::Getstringtbl(_) => 0x140,
732            Instr::Setstringtbl(_) => 0x141,
733            Instr::Getiosys(_, _) => 0x148,
734            Instr::Setiosys(_, _) => 0x149,
735            Instr::Linearsearch(_, _, _, _, _, _, _, _) => 0x150,
736            Instr::Binarysearch(_, _, _, _, _, _, _, _) => 0x151,
737            Instr::Linkedsearch(_, _, _, _, _, _, _) => 0x152,
738            Instr::Callf(_, _) => 0x160,
739            Instr::Callfi(_, _, _) => 0x161,
740            Instr::Callfii(_, _, _, _) => 0x162,
741            Instr::Callfiii(_, _, _, _, _) => 0x163,
742            Instr::Mzero(_, _) => 0x170,
743            Instr::Mcopy(_, _, _) => 0x171,
744            Instr::Malloc(_, _) => 0x178,
745            Instr::Mfree(_) => 0x179,
746            Instr::Accelfunc(_, _) => 0x180,
747            Instr::Accelparam(_, _) => 0x181,
748            Instr::Numtof(_, _) => 0x190,
749            Instr::Ftonumz(_, _) => 0x191,
750            Instr::Ftonumn(_, _) => 0x192,
751            Instr::Ceil(_, _) => 0x198,
752            Instr::Floor(_, _) => 0x199,
753            Instr::Fadd(_, _, _) => 0x1A0,
754            Instr::Fsub(_, _, _) => 0x1A1,
755            Instr::Fmul(_, _, _) => 0x1A2,
756            Instr::Fdiv(_, _, _) => 0x1A3,
757            Instr::Fmod(_, _, _, _) => 0x1A4,
758            Instr::Sqrt(_, _) => 0x1A8,
759            Instr::Exp(_, _) => 0x1A9,
760            Instr::Log(_, _) => 0x1AA,
761            Instr::Pow(_, _, _) => 0x1AB,
762            Instr::Sin(_, _) => 0x1B0,
763            Instr::Cos(_, _) => 0x1B1,
764            Instr::Tan(_, _) => 0x1B2,
765            Instr::Asin(_, _) => 0x1B3,
766            Instr::Acos(_, _) => 0x1B4,
767            Instr::Atan(_, _) => 0x1B5,
768            Instr::Atan2(_, _) => 0x1B6,
769            Instr::Jfeq(_, _, _, _) => 0x1C0,
770            Instr::Jfne(_, _, _, _) => 0x1C1,
771            Instr::Jflt(_, _, _) => 0x1C2,
772            Instr::Jfle(_, _, _) => 0x1C3,
773            Instr::Jfgt(_, _, _) => 0x1C4,
774            Instr::Jfge(_, _, _) => 0x1C5,
775            Instr::Jisnan(_, _) => 0x1C8,
776            Instr::Jisinf(_, _) => 0x1C9,
777            Instr::Numtod(_, _, _) => 0x200,
778            Instr::Dtonumz(_, _, _) => 0x201,
779            Instr::Dtonumn(_, _, _) => 0x202,
780            Instr::Ftod(_, _, _) => 0x203,
781            Instr::Dtof(_, _, _) => 0x204,
782            Instr::Dceil(_, _, _, _) => 0x208,
783            Instr::Dfloor(_, _, _, _) => 0x209,
784            Instr::Dadd(_, _, _, _, _, _) => 0x210,
785            Instr::Dsub(_, _, _, _, _, _) => 0x211,
786            Instr::Dmul(_, _, _, _, _, _) => 0x212,
787            Instr::Ddiv(_, _, _, _, _, _) => 0x213,
788            Instr::Dmodr(_, _, _, _, _, _) => 0x214,
789            Instr::Dmodq(_, _, _, _, _, _) => 0x215,
790            Instr::Dsqrt(_, _, _, _) => 0x218,
791            Instr::Dexp(_, _, _, _) => 0x219,
792            Instr::Dlog(_, _, _, _) => 0x21A,
793            Instr::Dpow(_, _, _, _, _, _) => 0x21B,
794            Instr::Dsin(_, _, _, _) => 0x220,
795            Instr::Dcos(_, _, _, _) => 0x221,
796            Instr::Dtan(_, _, _, _) => 0x222,
797            Instr::Dasin(_, _, _, _) => 0x223,
798            Instr::Dacos(_, _, _, _) => 0x224,
799            Instr::Datan(_, _, _, _) => 0x225,
800            Instr::Datan2(_, _, _, _, _, _) => 0x226,
801            Instr::Jdeq(_, _, _, _, _, _, _) => 0x230,
802            Instr::Jdne(_, _, _, _, _, _, _) => 0x231,
803            Instr::Jdlt(_, _, _, _, _) => 0x232,
804            Instr::Jdle(_, _, _, _, _) => 0x233,
805            Instr::Jdgt(_, _, _, _, _) => 0x234,
806            Instr::Jdge(_, _, _, _, _) => 0x235,
807            Instr::Jdisnan(_, _, _) => 0x238,
808            Instr::Jdisinf(_, _, _) => 0x239,
809        }
810    }
811
812    /// Resolves all labels in the instruction to produce a [`RawInstr`].
813    pub(crate) fn resolve<R>(
814        &self,
815        mut position: u32,
816        resolver: &R,
817    ) -> Result<RawInstr, AssemblerError<L>>
818    where
819        R: Resolver<Label = L>,
820    {
821        let opcode = self.opcode();
822        let opcode_length = u32::try_from(opcode_len(opcode)).unwrap();
823
824        position = position
825            .checked_add(opcode_length)
826            .ok_or(AssemblerError::Overflow)?;
827
828        let operands = match self {
829            Instr::Nop => resolve!(position, resolver,),
830            Instr::Add(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
831            Instr::Sub(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
832            Instr::Mul(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
833            Instr::Div(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
834            Instr::Mod(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
835            Instr::Neg(l1, s1) => resolve!(position, resolver, l1, s1),
836            Instr::Bitand(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
837            Instr::Bitor(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
838            Instr::Bitxor(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
839            Instr::Bitnot(l1, s1) => resolve!(position, resolver, l1, s1),
840            Instr::Shiftl(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
841            Instr::Ushiftr(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
842            Instr::Sshiftr(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
843            Instr::Jump(l1) => resolve!(position, resolver, l1),
844            Instr::Jz(l1, l2) => resolve!(position, resolver, l1, l2),
845            Instr::Jnz(l1, l2) => resolve!(position, resolver, l1, l2),
846            Instr::Jeq(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
847            Instr::Jne(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
848            Instr::Jlt(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
849            Instr::Jle(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
850            Instr::Jgt(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
851            Instr::Jge(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
852            Instr::Jltu(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
853            Instr::Jleu(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
854            Instr::Jgtu(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
855            Instr::Jgeu(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
856            Instr::Jumpabs(l1) => resolve!(position, resolver, l1),
857            Instr::Copy(l1, s1) => resolve!(position, resolver, l1, s1),
858            Instr::Copys(l1, s1) => resolve!(position, resolver, l1, s1),
859            Instr::Copyb(l1, s1) => resolve!(position, resolver, l1, s1),
860            Instr::Sexs(l1, s1) => resolve!(position, resolver, l1, s1),
861            Instr::Sexb(l1, s1) => resolve!(position, resolver, l1, s1),
862            Instr::Astore(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
863            Instr::Aload(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
864            Instr::Astores(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
865            Instr::Aloads(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
866            Instr::Astoreb(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
867            Instr::Aloadb(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
868            Instr::Astorebit(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
869            Instr::Aloadbit(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
870            Instr::Stkcount(s1) => resolve!(position, resolver, s1),
871            Instr::Stkpeek(l1, s1) => resolve!(position, resolver, l1, s1),
872            Instr::Stkswap => resolve!(position, resolver,),
873            Instr::Stkcopy(l1) => resolve!(position, resolver, l1),
874            Instr::Stkroll(l1, l2) => resolve!(position, resolver, l1, l2),
875            Instr::Call(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
876            Instr::Callf(l1, s1) => resolve!(position, resolver, l1, s1),
877            Instr::Callfi(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
878            Instr::Callfii(l1, l2, l3, s1) => {
879                resolve!(position, resolver, l1, l2, l3, s1)
880            }
881            Instr::Callfiii(l1, l2, l3, l4, s1) => {
882                resolve!(position, resolver, l1, l2, l3, l4, s1)
883            }
884            Instr::Return(l1) => resolve!(position, resolver, l1),
885            Instr::Tailcall(l1, l2) => resolve!(position, resolver, l1, l2),
886            Instr::Catch(s1, l1) => resolve!(position, resolver, s1, l1),
887            Instr::Throw(l1, l2) => resolve!(position, resolver, l1, l2),
888            Instr::Getmemsize(s1) => resolve!(position, resolver, s1),
889            Instr::Setmemsize(l1, s1) => resolve!(position, resolver, l1, s1),
890            Instr::Malloc(l1, s1) => resolve!(position, resolver, l1, s1),
891            Instr::Mfree(l1) => resolve!(position, resolver, l1),
892            Instr::Quit => resolve!(position, resolver,),
893            Instr::Restart => resolve!(position, resolver,),
894            Instr::Save(l1, s1) => resolve!(position, resolver, l1, s1),
895            Instr::Restore(l1, s1) => resolve!(position, resolver, l1, s1),
896            Instr::Saveundo(s1) => resolve!(position, resolver, s1),
897            Instr::Restoreundo(s1) => resolve!(position, resolver, s1),
898            Instr::Hasundo(s1) => resolve!(position, resolver, s1),
899            Instr::Discardundo => resolve!(position, resolver,),
900            Instr::Protect(l1, l2) => resolve!(position, resolver, l1, l2),
901            Instr::Verify(s1) => resolve!(position, resolver, s1),
902            Instr::Getiosys(s1, s2) => resolve!(position, resolver, s1, s2),
903            Instr::Setiosys(l1, l2) => resolve!(position, resolver, l1, l2),
904            Instr::Streamchar(l1) => resolve!(position, resolver, l1),
905            Instr::Streamunichar(l1) => resolve!(position, resolver, l1),
906            Instr::Streamnum(l1) => resolve!(position, resolver, l1),
907            Instr::Streamstr(l1) => resolve!(position, resolver, l1),
908            Instr::Getstringtbl(s1) => resolve!(position, resolver, s1),
909            Instr::Setstringtbl(l1) => resolve!(position, resolver, l1),
910            Instr::Numtof(l1, s1) => resolve!(position, resolver, l1, s1),
911            Instr::Ftonumz(l1, s1) => resolve!(position, resolver, l1, s1),
912            Instr::Ftonumn(l1, s1) => resolve!(position, resolver, l1, s1),
913            Instr::Fadd(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
914            Instr::Fsub(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
915            Instr::Fmul(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
916            Instr::Fdiv(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
917            Instr::Fmod(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
918            Instr::Ceil(l1, s1) => resolve!(position, resolver, l1, s1),
919            Instr::Floor(l1, s1) => resolve!(position, resolver, l1, s1),
920            Instr::Sqrt(l1, s1) => resolve!(position, resolver, l1, s1),
921            Instr::Exp(l1, s1) => resolve!(position, resolver, l1, s1),
922            Instr::Log(l1, s1) => resolve!(position, resolver, l1, s1),
923            Instr::Pow(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
924            Instr::Sin(l1, s1) => resolve!(position, resolver, l1, s1),
925            Instr::Cos(l1, s1) => resolve!(position, resolver, l1, s1),
926            Instr::Tan(l1, s1) => resolve!(position, resolver, l1, s1),
927            Instr::Asin(l1, s1) => resolve!(position, resolver, l1, s1),
928            Instr::Acos(l1, s1) => resolve!(position, resolver, l1, s1),
929            Instr::Atan(l1, s1) => resolve!(position, resolver, l1, s1),
930            Instr::Atan2(l1, s1) => resolve!(position, resolver, l1, s1),
931            Instr::Numtod(l1, s1, s2) => resolve!(position, resolver, l1, s1, s2),
932            Instr::Dtonumz(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
933            Instr::Dtonumn(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
934            Instr::Ftod(l1, s1, s2) => resolve!(position, resolver, l1, s1, s2),
935            Instr::Dtof(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
936            Instr::Dadd(l1, l2, l3, l4, s1, s2) => {
937                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
938            }
939            Instr::Dsub(l1, l2, l3, l4, s1, s2) => {
940                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
941            }
942            Instr::Dmul(l1, l2, l3, l4, s1, s2) => {
943                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
944            }
945            Instr::Ddiv(l1, l2, l3, l4, s1, s2) => {
946                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
947            }
948            Instr::Dmodr(l1, l2, l3, l4, s1, s2) => {
949                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
950            }
951            Instr::Dmodq(l1, l2, l3, l4, s1, s2) => {
952                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
953            }
954            Instr::Dceil(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
955            Instr::Dfloor(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
956            Instr::Dsqrt(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
957            Instr::Dexp(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
958            Instr::Dlog(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
959            Instr::Dpow(l1, l2, l3, l4, s1, s2) => {
960                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
961            }
962            Instr::Dsin(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
963            Instr::Dcos(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
964            Instr::Dtan(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
965            Instr::Dasin(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
966            Instr::Dacos(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
967            Instr::Datan(l1, l2, s1, s2) => resolve!(position, resolver, l1, l2, s1, s2),
968            Instr::Datan2(l1, l2, l3, l4, s1, s2) => {
969                resolve!(position, resolver, l1, l2, l3, l4, s1, s2)
970            }
971            Instr::Jisnan(l1, l2) => resolve!(position, resolver, l1, l2),
972            Instr::Jisinf(l1, l2) => resolve!(position, resolver, l1, l2),
973            Instr::Jfeq(l1, l2, l3, l4) => resolve!(position, resolver, l1, l2, l3, l4),
974            Instr::Jfne(l1, l2, l3, l4) => resolve!(position, resolver, l1, l2, l3, l4),
975            Instr::Jflt(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
976            Instr::Jfle(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
977            Instr::Jfgt(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
978            Instr::Jfge(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
979            Instr::Jdisnan(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
980            Instr::Jdisinf(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
981            Instr::Jdeq(l1, l2, l3, l4, l5, l6, l7) => {
982                resolve!(position, resolver, l1, l2, l3, l4, l5, l6, l7)
983            }
984            Instr::Jdne(l1, l2, l3, l4, l5, l6, l7) => {
985                resolve!(position, resolver, l1, l2, l3, l4, l5, l6, l7)
986            }
987            Instr::Jdlt(l1, l2, l3, l4, l5) => {
988                resolve!(position, resolver, l1, l2, l3, l4, l5)
989            }
990            Instr::Jdle(l1, l2, l3, l4, l5) => {
991                resolve!(position, resolver, l1, l2, l3, l4, l5)
992            }
993            Instr::Jdgt(l1, l2, l3, l4, l5) => {
994                resolve!(position, resolver, l1, l2, l3, l4, l5)
995            }
996            Instr::Jdge(l1, l2, l3, l4, l5) => {
997                resolve!(position, resolver, l1, l2, l3, l4, l5)
998            }
999            Instr::Random(l1, s1) => resolve!(position, resolver, l1, s1),
1000            Instr::Setrandom(l1) => resolve!(position, resolver, l1),
1001            Instr::Mzero(l1, l2) => resolve!(position, resolver, l1, l2),
1002            Instr::Mcopy(l1, l2, l3) => resolve!(position, resolver, l1, l2, l3),
1003            Instr::Linearsearch(l1, l2, l3, l4, l5, l6, l7, s1) => {
1004                resolve!(position, resolver, l1, l2, l3, l4, l5, l6, l7, s1)
1005            }
1006            Instr::Binarysearch(l1, l2, l3, l4, l5, l6, l7, s1) => {
1007                resolve!(position, resolver, l1, l2, l3, l4, l5, l6, l7, s1)
1008            }
1009            Instr::Linkedsearch(l1, l2, l3, l4, l5, l6, s1) => {
1010                resolve!(position, resolver, l1, l2, l3, l4, l5, l6, s1)
1011            }
1012            Instr::Accelfunc(l1, l2) => resolve!(position, resolver, l1, l2),
1013            Instr::Accelparam(l1, l2) => resolve!(position, resolver, l1, l2),
1014            Instr::Gestalt(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
1015            Instr::Debugtrap(l1) => resolve!(position, resolver, l1),
1016            Instr::Glk(l1, l2, s1) => resolve!(position, resolver, l1, l2, s1),
1017        };
1018
1019        Ok(RawInstr { opcode, operands })
1020    }
1021}
1022
1023impl<L> Display for Instr<L>
1024where
1025    L: Display,
1026{
1027    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1028        match self {
1029            Instr::Nop => write!(f, "nop")?,
1030            Instr::Add(l1, l2, s1) => write!(f, "add {l1} {l2} {s1}")?,
1031            Instr::Sub(l1, l2, s1) => write!(f, "sub {l1} {l2} {s1}")?,
1032            Instr::Mul(l1, l2, s1) => write!(f, "mul {l1} {l2} {s1}")?,
1033            Instr::Div(l1, l2, s1) => write!(f, "div {l1} {l2} {s1}")?,
1034            Instr::Mod(l1, l2, s1) => write!(f, "mod {l1} {l2} {s1}")?,
1035            Instr::Neg(l1, s1) => write!(f, "neg {l1} {s1}")?,
1036            Instr::Bitand(l1, l2, s1) => write!(f, "bitand {l1} {l2} {s1}")?,
1037            Instr::Bitor(l1, l2, s1) => write!(f, "bitor {l1} {l2} {s1}")?,
1038            Instr::Bitxor(l1, l2, s1) => write!(f, "bitxor {l1} {l2} {s1}")?,
1039            Instr::Bitnot(l1, s1) => write!(f, "bitnot {l1} {s1}")?,
1040            Instr::Shiftl(l1, l2, s1) => write!(f, "shiftl {l1} {l2} {s1}")?,
1041            Instr::Ushiftr(l1, l2, s1) => write!(f, "ushiftr {l1} {l2} {s1}")?,
1042            Instr::Sshiftr(l1, l2, s1) => write!(f, "sshiftr {l1} {l2} {s1}")?,
1043            Instr::Jump(bt) => write!(f, "jump {bt}")?,
1044            Instr::Jz(l1, bt) => write!(f, "jz {l1} {bt}")?,
1045            Instr::Jnz(l1, bt) => write!(f, "jnz {l1} {bt}")?,
1046            Instr::Jeq(l1, l2, bt) => write!(f, "jeq {l1} {l2} {bt}")?,
1047            Instr::Jne(l1, l2, bt) => write!(f, "jne {l1} {l2} {bt}")?,
1048            Instr::Jlt(l1, l2, bt) => write!(f, "jlt {l1} {l2} {bt}")?,
1049            Instr::Jle(l1, l2, bt) => write!(f, "jle {l1} {l2} {bt}")?,
1050            Instr::Jgt(l1, l2, bt) => write!(f, "jgt {l1} {l2} {bt}")?,
1051            Instr::Jge(l1, l2, bt) => write!(f, "jge {l1} {l2} {bt}")?,
1052            Instr::Jltu(l1, l2, bt) => write!(f, "jltu {l1} {l2} {bt}")?,
1053            Instr::Jleu(l1, l2, bt) => write!(f, "jleu {l1} {l2} {bt}")?,
1054            Instr::Jgtu(l1, l2, bt) => write!(f, "jgtu {l1} {l2} {bt}")?,
1055            Instr::Jgeu(l1, l2, bt) => write!(f, "jgeu {l1} {l2} {bt}")?,
1056            Instr::Jumpabs(l1) => write!(f, "jumpabs {l1}")?,
1057            Instr::Copy(l1, s1) => write!(f, "copy {l1} {s1}")?,
1058            Instr::Copys(l1, s1) => write!(f, "copys {l1} {s1}")?,
1059            Instr::Copyb(l1, s1) => write!(f, "copyb {l1} {s1}")?,
1060            Instr::Sexs(l1, s1) => write!(f, "sexs {l1} {s1}")?,
1061            Instr::Sexb(l1, s1) => write!(f, "sexb {l1} {s1}")?,
1062            Instr::Astore(l1, l2, l3) => write!(f, "astore {l1} {l2} {l3}")?,
1063            Instr::Aload(l1, l2, s1) => write!(f, "aload {l1} {l2} {s1}")?,
1064            Instr::Astores(l1, l2, l3) => write!(f, "astores {l1} {l2} {l3}")?,
1065            Instr::Aloads(l1, l2, s1) => write!(f, "aloads {l1} {l2} {s1}")?,
1066            Instr::Astoreb(l1, l2, l3) => write!(f, "astoreb {l1} {l2} {l3}")?,
1067            Instr::Aloadb(l1, l2, s1) => write!(f, "aloadb {l1} {l2} {s1}")?,
1068            Instr::Astorebit(l1, l2, l3) => write!(f, "astorebit {l1} {l2} {l3}")?,
1069            Instr::Aloadbit(l1, l2, s1) => write!(f, "aloadbit {l1} {l2} {s1}")?,
1070            Instr::Stkcount(s1) => write!(f, "stkcount {s1}")?,
1071            Instr::Stkpeek(l1, s1) => write!(f, "stkpeek {l1} {s1}")?,
1072            Instr::Stkswap => write!(f, "stkswap")?,
1073            Instr::Stkcopy(l1) => write!(f, "stkcopy {l1}")?,
1074            Instr::Stkroll(l1, l2) => write!(f, "stkroll {l1} {l2}")?,
1075            Instr::Call(l1, l2, s1) => write!(f, "call {l1} {l2} {s1}")?,
1076            Instr::Callf(l1, s1) => write!(f, "callf {l1} {s1}")?,
1077            Instr::Callfi(l1, l2, s1) => write!(f, "callfi {l1} {l2} {s1}")?,
1078            Instr::Callfii(l1, l2, l3, s1) => write!(f, "callfii {l1} {l2} {l3} {s1}")?,
1079            Instr::Callfiii(l1, l2, l3, l4, s1) => write!(f, "callfiii {l1} {l2} {l3} {l4} {s1}")?,
1080            Instr::Return(l1) => write!(f, "return {l1}")?,
1081            Instr::Tailcall(l1, l2) => write!(f, "tailcall {l1} {l2}")?,
1082            Instr::Catch(s1, bt) => write!(f, "catch {s1} {bt}")?,
1083            Instr::Throw(l1, l2) => write!(f, "throw {l1} {l2}")?,
1084            Instr::Getmemsize(s1) => write!(f, "getmemsize {s1}")?,
1085            Instr::Setmemsize(l1, s1) => write!(f, "setmemsize {l1} {s1}")?,
1086            Instr::Malloc(l1, s1) => write!(f, "malloc {l1} {s1}")?,
1087            Instr::Mfree(l1) => write!(f, "mfree {l1}")?,
1088            Instr::Quit => write!(f, "quit")?,
1089            Instr::Restart => write!(f, "restart")?,
1090            Instr::Save(l1, s1) => write!(f, "save {l1} {s1}")?,
1091            Instr::Restore(l1, s1) => write!(f, "restore {l1} {s1}")?,
1092            Instr::Saveundo(s1) => write!(f, "saveundo {s1}")?,
1093            Instr::Restoreundo(s1) => write!(f, "restoreundo {s1}")?,
1094            Instr::Hasundo(s1) => write!(f, "hasundo {s1}")?,
1095            Instr::Discardundo => write!(f, "discardundo")?,
1096            Instr::Protect(l1, l2) => write!(f, "protect {l1} {l2}")?,
1097            Instr::Verify(s1) => write!(f, "verify {s1}")?,
1098            Instr::Getiosys(s1, s2) => write!(f, "getiosys {s1} {s2}")?,
1099            Instr::Setiosys(l1, l2) => write!(f, "setiosys {l1} {l2}")?,
1100            Instr::Streamchar(l1) => write!(f, "streamchar {l1}")?,
1101            Instr::Streamunichar(l1) => write!(f, "streamunichar {l1}")?,
1102            Instr::Streamnum(l1) => write!(f, "streamnum {l1}")?,
1103            Instr::Streamstr(l1) => write!(f, "streamstr {l1}")?,
1104            Instr::Getstringtbl(s1) => write!(f, "getstringtbl {s1}")?,
1105            Instr::Setstringtbl(l1) => write!(f, "setstringtbl {l1}")?,
1106            Instr::Numtof(l1, s1) => write!(f, "numtof {l1} {s1}")?,
1107            Instr::Ftonumz(l1, s1) => write!(f, "ftonumz {l1} {s1}")?,
1108            Instr::Ftonumn(l1, s1) => write!(f, "ftonumn {l1} {s1}")?,
1109            Instr::Fadd(l1, l2, s1) => write!(f, "fadd {l1} {l2} {s1}")?,
1110            Instr::Fsub(l1, l2, s1) => write!(f, "fsub {l1} {l2} {s1}")?,
1111            Instr::Fmul(l1, l2, s1) => write!(f, "fmul {l1} {l2} {s1}")?,
1112            Instr::Fdiv(l1, l2, s1) => write!(f, "fdiv {l1} {l2} {s1}")?,
1113            Instr::Fmod(l1, l2, s1, s2) => write!(f, "fmod {l1} {l2} {s1} {s2}")?,
1114            Instr::Ceil(l1, s1) => write!(f, "ceil {l1} {s1}")?,
1115            Instr::Floor(l1, s1) => write!(f, "floor {l1} {s1}")?,
1116            Instr::Sqrt(l1, s1) => write!(f, "sqrt {l1} {s1}")?,
1117            Instr::Exp(l1, s1) => write!(f, "exp {l1} {s1}")?,
1118            Instr::Log(l1, s1) => write!(f, "log {l1} {s1}")?,
1119            Instr::Pow(l1, l2, s1) => write!(f, "pow {l1} {l2} {s1}")?,
1120            Instr::Sin(l1, s1) => write!(f, "sin {l1} {s1}")?,
1121            Instr::Cos(l1, s1) => write!(f, "cos {l1} {s1}")?,
1122            Instr::Tan(l1, s1) => write!(f, "tan {l1} {s1}")?,
1123            Instr::Asin(l1, s1) => write!(f, "asin {l1} {s1}")?,
1124            Instr::Acos(l1, s1) => write!(f, "acos {l1} {s1}")?,
1125            Instr::Atan(l1, s1) => write!(f, "atan {l1} {s1}")?,
1126            Instr::Atan2(l1, s1) => write!(f, "atan2 {l1} {s1}")?,
1127            Instr::Numtod(l1, s1, s2) => write!(f, "numtod {l1} {s1} {s2}")?,
1128            Instr::Dtonumz(l1, l2, s1) => write!(f, "dtonumz {l1} {l2} {s1}")?,
1129            Instr::Dtonumn(l1, l2, s1) => write!(f, "dtonumn {l1} {l2} {s1}")?,
1130            Instr::Ftod(l1, s1, s2) => write!(f, "ftod {l1} {s1} {s2}")?,
1131            Instr::Dtof(l1, l2, s1) => write!(f, "dtof {l1} {l2} {s1}")?,
1132            Instr::Dadd(l1, l2, l3, l4, s1, s2) => write!(f, "dadd {l1} {l2} {l3} {l4} {s1} {s2}")?,
1133            Instr::Dsub(l1, l2, l3, l4, s1, s2) => write!(f, "dsub {l1} {l2} {l3} {l4} {s1} {s2}")?,
1134            Instr::Dmul(l1, l2, l3, l4, s1, s2) => write!(f, "dmul {l1} {l2} {l3} {l4} {s1} {s2}")?,
1135            Instr::Ddiv(l1, l2, l3, l4, s1, s2) => write!(f, "ddiv {l1} {l2} {l3} {l4} {s1} {s2}")?,
1136            Instr::Dmodr(l1, l2, l3, l4, s1, s2) => {
1137                write!(f, "dmodr {l1} {l2} {l3} {l4} {s1} {s2}")?
1138            }
1139            Instr::Dmodq(l1, l2, l3, l4, s1, s2) => {
1140                write!(f, "dmodq {l1} {l2} {l3} {l4} {s1} {s2}")?
1141            }
1142            Instr::Dceil(l1, l2, s1, s2) => write!(f, "dceil {l1} {l2} {s1} {s2}")?,
1143            Instr::Dfloor(l1, l2, s1, s2) => write!(f, "dfloor {l1} {l2} {s1} {s2}")?,
1144            Instr::Dsqrt(l1, l2, s1, s2) => write!(f, "dsqrt {l1} {l2} {s1} {s2}")?,
1145            Instr::Dexp(l1, l2, s1, s2) => write!(f, "dexp {l1} {l2} {s1} {s2}")?,
1146            Instr::Dlog(l1, l2, s1, s2) => write!(f, "dlog {l1} {l2} {s1} {s2}")?,
1147            Instr::Dpow(l1, l2, l3, l4, s1, s2) => write!(f, "dpow {l1} {l2} {l3} {l4} {s1} {s2}")?,
1148            Instr::Dsin(l1, l2, s1, s2) => write!(f, "dsin {l1} {l2} {s1} {s2}")?,
1149            Instr::Dcos(l1, l2, s1, s2) => write!(f, "dcos {l1} {l2} {s1} {s2}")?,
1150            Instr::Dtan(l1, l2, s1, s2) => write!(f, "dtan {l1} {l2} {s1} {s2}")?,
1151            Instr::Dasin(l1, l2, s1, s2) => write!(f, "dasin {l1} {l2} {s1} {s2}")?,
1152            Instr::Dacos(l1, l2, s1, s2) => write!(f, "dacos {l1} {l2} {s1} {s2}")?,
1153            Instr::Datan(l1, l2, s1, s2) => write!(f, "datan {l1} {l2} {s1} {s2}")?,
1154            Instr::Datan2(l1, l2, l3, l4, s1, s2) => {
1155                write!(f, "datan2 {l1} {l2} {l3} {l4} {s1} {s2}")?
1156            }
1157            Instr::Jisnan(l1, bt) => write!(f, "jisnan {l1} {bt}")?,
1158            Instr::Jisinf(l1, bt) => write!(f, "jisinf {l1} {bt}")?,
1159            Instr::Jfeq(l1, l2, l3, bt) => write!(f, "jfeq {l1} {l2} {l3} {bt}")?,
1160            Instr::Jfne(l1, l2, l3, bt) => write!(f, "jfne {l1} {l2} {l3} {bt}")?,
1161            Instr::Jflt(l1, l2, bt) => write!(f, "jflt {l1} {l2} {bt}")?,
1162            Instr::Jfle(l1, l2, bt) => write!(f, "jfle {l1} {l2} {bt}")?,
1163            Instr::Jfgt(l1, l2, bt) => write!(f, "jfgt {l1} {l2} {bt}")?,
1164            Instr::Jfge(l1, l2, bt) => write!(f, "jfge {l1} {l2} {bt}")?,
1165            Instr::Jdisnan(l1, l2, bt) => write!(f, "jdisnan {l1} {l2} {bt}")?,
1166            Instr::Jdisinf(l1, l2, bt) => write!(f, "jdisinf {l1} {l2} {bt}")?,
1167            Instr::Jdeq(l1, l2, l3, l4, l5, l6, bt) => {
1168                write!(f, "jdeq {l1} {l2} {l3} {l4} {l5} {l6} {bt}")?
1169            }
1170            Instr::Jdne(l1, l2, l3, l4, l5, l6, bt) => {
1171                write!(f, "jdne {l1} {l2} {l3} {l4} {l5} {l6} {bt}")?
1172            }
1173            Instr::Jdlt(l1, l2, l3, l4, bt) => write!(f, "jdlt {l1} {l2} {l3} {l4} {bt}")?,
1174            Instr::Jdle(l1, l2, l3, l4, bt) => write!(f, "jdle {l1} {l2} {l3} {l4} {bt}")?,
1175            Instr::Jdgt(l1, l2, l3, l4, bt) => write!(f, "jdgt {l1} {l2} {l3} {l4} {bt}")?,
1176            Instr::Jdge(l1, l2, l3, l4, bt) => write!(f, "jdge {l1} {l2} {l3} {l4} {bt}")?,
1177            Instr::Random(l1, s1) => write!(f, "random {l1} {s1}")?,
1178            Instr::Setrandom(l1) => write!(f, "setrandom {l1}")?,
1179            Instr::Mzero(l1, l2) => write!(f, "mzero {l1} {l2}")?,
1180            Instr::Mcopy(l1, l2, l3) => write!(f, "mcopy {l1} {l2} {l3}")?,
1181            Instr::Linearsearch(l1, l2, l3, l4, l5, l6, l7, s1) => {
1182                write!(f, "linearsearch {l1} {l2} {l3} {l4} {l5} {l6} {l7} {s1}")?
1183            }
1184            Instr::Binarysearch(l1, l2, l3, l4, l5, l6, l7, s1) => {
1185                write!(f, "binarysearch {l1} {l2} {l3} {l4} {l5} {l6} {l7} {s1}")?
1186            }
1187            Instr::Linkedsearch(l1, l2, l3, l4, l5, l6, s1) => {
1188                write!(f, "linkedsearch {l1} {l2} {l3} {l4} {l5} {l6} {s1}")?
1189            }
1190            Instr::Accelfunc(l1, l2) => write!(f, "accelfunc {l1} {l2}")?,
1191            Instr::Accelparam(l1, l2) => write!(f, "accelparam {l1} {l2}")?,
1192            Instr::Gestalt(l1, l2, s1) => write!(f, "gestalt {l1} {l2} {s1}")?,
1193            Instr::Debugtrap(l1) => write!(f, "debugtrap {l1}")?,
1194            Instr::Glk(l1, l2, s1) => write!(f, "glk {l1} {l2} {s1}")?,
1195        }
1196        Ok(())
1197    }
1198}
1199
1200impl RawInstr {
1201    /// Returns the serialized length of the instruction.
1202    pub(crate) fn len(&self) -> usize {
1203        opcode_len(self.opcode)
1204            + self.operands.len().div_ceil(2)
1205            + self.operands.iter().map(|op| op.len()).sum::<usize>()
1206    }
1207
1208    /// Serializes the instruction.
1209    pub(crate) fn serialize<B: BufMut>(&self, mut buf: B) {
1210        if self.opcode < 0x80 {
1211            buf.put_u8(
1212                self.opcode
1213                    .try_into()
1214                    .expect("opcode range should have already been checked"),
1215            )
1216        } else if self.opcode < 0x4000 {
1217            buf.put_u16(
1218                (self.opcode + 0x8000)
1219                    .try_into()
1220                    .expect("opcode range should have already been checked"),
1221            )
1222        } else {
1223            buf.put_u32(
1224                self.opcode
1225                    .checked_add(0xC0000000)
1226                    .expect("opcode should not exceed 0x0FFFFFFF"),
1227            )
1228        }
1229
1230        let mut odd = false;
1231        let mut modebyte: u8 = 0;
1232        for operand in &self.operands {
1233            if odd {
1234                modebyte += operand.mode() << 4;
1235                buf.put_u8(modebyte);
1236                odd = false;
1237            } else {
1238                modebyte = operand.mode();
1239                odd = true;
1240            }
1241        }
1242
1243        if odd {
1244            buf.put_u8(modebyte);
1245        }
1246
1247        for operand in &self.operands {
1248            operand.serialize(&mut buf)
1249        }
1250    }
1251}
1252
1253/// Returns the serialized length of the opcode.
1254fn opcode_len(opcode: u32) -> usize {
1255    if opcode < 0x80 {
1256        1
1257    } else if opcode < 0x4000 {
1258        2
1259    } else {
1260        4
1261    }
1262}