glulx_asm/
decoding_table.rs

1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-Exception
2// Copyright 2024 Daniel Fox Franke.
3
4//! Definition and impls for [`DecodeNode`] and related types.
5
6use crate::cast::{CastSign, Overflow};
7use crate::error::AssemblerError;
8use crate::items::LabelRef;
9use crate::resolver::Resolver;
10use crate::strings::{MysteryString, Utf32String};
11use bytes::BufMut;
12
13/// A node in a decoding table.
14#[derive(Debug, Clone)]
15pub enum DecodeNode<L> {
16    /// Branch left on 0, right on 1.
17    Branch(Box<DecodeNode<L>>, Box<DecodeNode<L>>),
18    /// Terminate decoding.
19    StringTerminator,
20    /// Emit a character whose encoding is unspecified and determined by the IO
21    /// system (but probably Latin-1).
22    MysteryChar(u8),
23    /// Emit a string whose encoding is unspecified and determined by the IO
24    /// system (but probably Latin-1).
25    MysteryString(MysteryString),
26    /// Emit a Unicode character.
27    UnicodeChar(char),
28    /// Emit a Unicode string.
29    Utf32String(Utf32String),
30    /// Emit the string or call the function found by dereferencing the given
31    /// address.
32    IndirectRef(LabelRef<L>),
33    /// Emit the string or call the function found by doubly dereferencing the
34    /// given address.
35    DoubleIndirectRef(LabelRef<L>),
36    /// Call the function found by derefencing the given address, passing it the
37    /// given arguments.
38    IndirectRefWithArgs(LabelRef<L>, Vec<DecodeArg<L>>),
39    /// Call the function found by doubly derefencing the given address, passing
40    /// it the given arguments.
41    DoubleIndirectRefWithArgs(LabelRef<L>, Vec<DecodeArg<L>>),
42}
43
44pub(crate) enum ResolvedDecodeNode {
45    Branch(Box<ResolvedDecodeNode>, Box<ResolvedDecodeNode>),
46    StringTerminator,
47    MysteryChar(u8),
48    MysteryString(MysteryString),
49    UnicodeChar(char),
50    Utf32String(Utf32String),
51    IndirectRef(u32),
52    DoubleIndirectRef(u32),
53    IndirectRefWithArgs(u32, Vec<i32>),
54    DoubleIndirectRefWithArgs(u32, Vec<i32>),
55}
56
57/// Argument to a function invoked from a decoding table.
58#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
59pub enum DecodeArg<L> {
60    /// Argument is the absolute address of the given label+offset.
61    Label(LabelRef<L>),
62    /// Argument is the given literal.
63    Literal(i32),
64}
65
66impl<L> DecodeArg<L> {
67    /// Applies the given mapping function to the label within the argument, if any.
68    pub fn map<F, M>(self, f: F) -> DecodeArg<M>
69    where
70        F: FnMut(L) -> M,
71    {
72        match self {
73            DecodeArg::Label(l) => DecodeArg::Label(l.map(f)),
74            DecodeArg::Literal(x) => DecodeArg::Literal(x),
75        }
76    }
77
78    pub(crate) fn resolve<R>(&self, resolver: &R) -> Result<i32, AssemblerError<L>>
79    where
80        R: Resolver<Label = L>,
81    {
82        Ok(match self {
83            DecodeArg::Label(l) => l.resolve_absolute(resolver)?.cast_sign(),
84            DecodeArg::Literal(x) => *x,
85        })
86    }
87}
88
89impl<L> DecodeNode<L> {
90    /// Applies the given mapping function to all labels within the node.
91    pub fn map<F, M>(self, mut f: F) -> DecodeNode<M>
92    where
93        F: FnMut(L) -> M,
94    {
95        self.map_inner(&mut f)
96    }
97
98    // This method is recursive. This hack of taking a &mut F instead of an F is
99    // necessary in order have a type we can reborrow and avoid infinite
100    // recursion during trait resolution.
101    fn map_inner<F, M>(self, f: &mut F) -> DecodeNode<M>
102    where
103        F: FnMut(L) -> M,
104    {
105        match self {
106            DecodeNode::Branch(left, right) => DecodeNode::Branch(
107                Box::new(left.map_inner(&mut *f)),
108                Box::new(right.map_inner(&mut *f)),
109            ),
110            DecodeNode::StringTerminator => DecodeNode::StringTerminator,
111            DecodeNode::MysteryChar(x) => DecodeNode::MysteryChar(x),
112            DecodeNode::MysteryString(x) => DecodeNode::MysteryString(x),
113            DecodeNode::UnicodeChar(x) => DecodeNode::UnicodeChar(x),
114            DecodeNode::Utf32String(x) => DecodeNode::Utf32String(x),
115            DecodeNode::IndirectRef(r) => DecodeNode::IndirectRef(r.map(f)),
116            DecodeNode::DoubleIndirectRef(r) => DecodeNode::DoubleIndirectRef(r.map(f)),
117            DecodeNode::IndirectRefWithArgs(r, args) => DecodeNode::IndirectRefWithArgs(
118                r.map(&mut *f),
119                args.into_iter().map(|arg| arg.map(&mut *f)).collect(),
120            ),
121            DecodeNode::DoubleIndirectRefWithArgs(r, args) => {
122                DecodeNode::DoubleIndirectRefWithArgs(
123                    r.map(&mut *f),
124                    args.into_iter().map(|arg| arg.map(&mut *f)).collect(),
125                )
126            }
127        }
128    }
129
130    pub(crate) fn len(&self) -> usize {
131        match self {
132            DecodeNode::Branch(left, right) => left.len() + right.len() + 9,
133            DecodeNode::StringTerminator => 1,
134            DecodeNode::MysteryChar(_) => 2,
135            DecodeNode::MysteryString(s) => s.len() + 2,
136            DecodeNode::UnicodeChar(_) => 5,
137            DecodeNode::Utf32String(s) => s.byte_len() + 5,
138            DecodeNode::IndirectRef(_) => 5,
139            DecodeNode::DoubleIndirectRef(_) => 5,
140            DecodeNode::IndirectRefWithArgs(_, args) => 4 * args.len() + 9,
141            DecodeNode::DoubleIndirectRefWithArgs(_, args) => 4 * args.len() + 9,
142        }
143    }
144
145    pub(crate) fn resolve<R>(&self, resolver: &R) -> Result<ResolvedDecodeNode, AssemblerError<L>>
146    where
147        R: Resolver<Label = L>,
148    {
149        Ok(match self {
150            DecodeNode::Branch(left, right) => ResolvedDecodeNode::Branch(
151                Box::new(left.resolve(resolver)?),
152                Box::new(right.resolve(resolver)?),
153            ),
154            DecodeNode::StringTerminator => ResolvedDecodeNode::StringTerminator,
155            DecodeNode::MysteryChar(c) => ResolvedDecodeNode::MysteryChar(*c),
156            DecodeNode::MysteryString(s) => ResolvedDecodeNode::MysteryString(s.clone()),
157            DecodeNode::UnicodeChar(c) => ResolvedDecodeNode::UnicodeChar(*c),
158            DecodeNode::Utf32String(s) => ResolvedDecodeNode::Utf32String(s.clone()),
159            DecodeNode::IndirectRef(r) => {
160                ResolvedDecodeNode::IndirectRef(r.resolve_absolute(resolver)?)
161            }
162            DecodeNode::DoubleIndirectRef(r) => {
163                ResolvedDecodeNode::DoubleIndirectRef(r.resolve_absolute(resolver)?)
164            }
165            DecodeNode::IndirectRefWithArgs(r, args) => {
166                u32::try_from(args.len()).overflow()?; // We can't serialize this. Serialization is infallible, so check here instead.
167                let mut newargs = Vec::with_capacity(args.len());
168                for arg in args {
169                    newargs.push(arg.resolve(resolver)?);
170                }
171
172                ResolvedDecodeNode::IndirectRefWithArgs(r.resolve_absolute(resolver)?, newargs)
173            }
174            DecodeNode::DoubleIndirectRefWithArgs(r, args) => {
175                u32::try_from(args.len()).overflow()?;
176                let mut newargs = Vec::with_capacity(args.len());
177                for arg in args {
178                    newargs.push(arg.resolve(resolver)?);
179                }
180
181                ResolvedDecodeNode::DoubleIndirectRefWithArgs(
182                    r.resolve_absolute(resolver)?,
183                    newargs,
184                )
185            }
186        })
187    }
188}
189
190impl ResolvedDecodeNode {
191    pub(crate) fn count_nodes(&self) -> usize {
192        match self {
193            ResolvedDecodeNode::Branch(left, right) => 1 + left.count_nodes() + right.count_nodes(),
194            _ => 1,
195        }
196    }
197
198    pub(crate) fn len(&self) -> usize {
199        match self {
200            ResolvedDecodeNode::Branch(left, right) => left.len() + right.len() + 9,
201            ResolvedDecodeNode::StringTerminator => 1,
202            ResolvedDecodeNode::MysteryChar(_) => 2,
203            ResolvedDecodeNode::MysteryString(s) => s.len() + 2,
204            ResolvedDecodeNode::UnicodeChar(_) => 5,
205            ResolvedDecodeNode::Utf32String(s) => s.byte_len() + 5,
206            ResolvedDecodeNode::IndirectRef(_) => 5,
207            ResolvedDecodeNode::DoubleIndirectRef(_) => 5,
208            ResolvedDecodeNode::IndirectRefWithArgs(_, args) => 4 * args.len() + 9,
209            ResolvedDecodeNode::DoubleIndirectRefWithArgs(_, args) => 4 * args.len() + 9,
210        }
211    }
212
213    pub(crate) fn serialize<B>(&self, num: u32, mut buf: B)
214    where
215        B: BufMut,
216    {
217        self.serialize_inner(num, &mut buf)
218    }
219
220    fn serialize_inner<B>(&self, num: u32, buf: &mut B)
221    where
222        B: BufMut,
223    {
224        match self {
225            ResolvedDecodeNode::Branch(left, right) => {
226                let panic_msg = "decode tables with >= 2**32 nodes should have been rejected before serialization";
227                let left_num = num.checked_add(1).expect(panic_msg);
228                let right_num = left_num
229                    .checked_add(left.count_nodes().try_into().expect(panic_msg))
230                    .expect(panic_msg);
231                buf.put_u8(0);
232                left.serialize_inner(left_num, &mut *buf);
233                right.serialize_inner(right_num, &mut *buf);
234            }
235            ResolvedDecodeNode::StringTerminator => {
236                buf.put_u8(1);
237            }
238            ResolvedDecodeNode::MysteryChar(x) => {
239                buf.put_u8(2);
240                buf.put_u8(*x);
241            }
242            ResolvedDecodeNode::MysteryString(s) => {
243                buf.put_u8(3);
244                buf.put(s.to_bytes());
245                buf.put_u8(0);
246            }
247            ResolvedDecodeNode::UnicodeChar(c) => {
248                buf.put_u8(4);
249                buf.put_u32((*c).into());
250            }
251            ResolvedDecodeNode::Utf32String(s) => {
252                buf.put_u8(5);
253                buf.put(s.to_bytes());
254                buf.put_u32(0);
255            }
256            ResolvedDecodeNode::IndirectRef(r) => {
257                buf.put_u8(8);
258                buf.put_u32(*r);
259            }
260            ResolvedDecodeNode::DoubleIndirectRef(r) => {
261                buf.put_u8(9);
262                buf.put_u32(*r);
263            }
264            ResolvedDecodeNode::IndirectRefWithArgs(r, args) => {
265                buf.put_u8(0xa);
266                buf.put_u32(*r);
267                buf.put_u32(
268                    args.len().try_into().expect(
269                        "refs with >= 2**32 args should have been rejected during resolution",
270                    ),
271                );
272                for arg in args {
273                    buf.put_i32(*arg)
274                }
275            }
276            ResolvedDecodeNode::DoubleIndirectRefWithArgs(r, args) => {
277                buf.put_u8(0xb);
278                buf.put_u32(*r);
279                buf.put_u32(
280                    args.len().try_into().expect(
281                        "refs with >= 2**32 args should have been rejected during resolution",
282                    ),
283                );
284                for arg in args {
285                    buf.put_i32(*arg)
286                }
287            }
288        }
289    }
290}