1#[cfg(test)]
2mod tests;
3
4use std::{error::Error, fmt::Display};
5
6pub type Register = u32;
7pub type Address = u32;
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Locator {
10 Address(Address),
11 FromRegister(Register),
12}
13pub type Bytes = (u8, u32, u32, u32);
14#[derive(Debug, Clone, Copy, PartialEq)]
15#[repr(u8)]
16pub enum ByteCode {
17 None,
18 Halt,
19 Jump {
20 addr: Locator,
21 },
22 JumpIf {
23 cond: Register,
24 addr: Locator,
25 },
26
27 String {
28 dst: Register,
29 addr: u32,
30 },
31 Int {
32 dst: Register,
33 value: u64,
34 },
35 Float {
36 dst: Register,
37 value: f64,
38 },
39 Bool {
40 dst: Register,
41 value: bool,
42 },
43
44 Move {
45 dst: Register,
46 src: Register,
47 },
48 Field {
49 dst: Register,
50 src: Register,
51 field: u32,
52 },
53 Call {
54 addr: Locator,
55 args: u32,
56 dst: Register
57 },
58
59 Binary {
60 op: BinaryOperation,
61 dst: Register,
62 left: Register,
63 right: Register,
64 },
65 Unary {
66 op: UnaryOperation,
67 dst: Register,
68 right: Register,
69 },
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73#[repr(u8)]
74pub enum BinaryOperation {
75 Add,
76 Sub,
77 Div,
78 Mul,
79}
80#[derive(Debug, Clone, PartialEq)]
81pub struct BinaryOperationError;
82impl TryFrom<u8> for BinaryOperation {
83 type Error = BinaryOperationError;
84 fn try_from(value: u8) -> Result<Self, Self::Error> {
85 match value {
86 0 => Ok(Self::Add),
87 1 => Ok(Self::Sub),
88 2 => Ok(Self::Div),
89 3 => Ok(Self::Mul),
90 _ => Err(BinaryOperationError),
91 }
92 }
93}
94impl From<BinaryOperation> for u8 {
95 fn from(val: BinaryOperation) -> Self {
96 match val {
97 BinaryOperation::Add => 0,
98 BinaryOperation::Sub => 1,
99 BinaryOperation::Div => 2,
100 BinaryOperation::Mul => 3,
101 }
102 }
103}
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105#[repr(u8)]
106pub enum UnaryOperation {
107 Neg,
108}
109#[derive(Debug, Clone, PartialEq)]
110pub struct UnaryOperationError;
111impl TryFrom<u8> for UnaryOperation {
112 type Error = UnaryOperationError;
113 fn try_from(value: u8) -> Result<Self, Self::Error> {
114 match value {
115 0 => Ok(Self::Neg),
116 _ => Err(UnaryOperationError),
117 }
118 }
119}
120impl From<UnaryOperation> for u8 {
121 fn from(val: UnaryOperation) -> Self {
122 match val {
123 UnaryOperation::Neg => 0,
124 }
125 }
126}
127
128impl From<Locator> for u32 {
129 fn from(value: Locator) -> Self {
130 match value {
131 Locator::FromRegister(addr) | Locator::Address(addr) => addr,
132 }
133 }
134}
135impl From<ByteCode> for Bytes {
136 fn from(value: ByteCode) -> Self {
137 match value {
138 ByteCode::None => (0x00, 0, 0, 0),
139 ByteCode::Halt => (0x01, 0, 0, 0),
140 ByteCode::Jump { addr } => match addr {
141 Locator::Address(addr) => (0x02, 0, addr, 0),
142 Locator::FromRegister(addr) => (0x03, 0, addr, 0),
143 }
144 ByteCode::JumpIf { cond, addr } => match addr {
145 Locator::Address(addr) => (0x04, cond, addr, 0),
146 Locator::FromRegister(addr) => (0x05, cond, addr, 0),
147 }
148 ByteCode::String { dst, addr } => (0x10, dst, addr, 0),
149 ByteCode::Int { dst, value } => {
150 (0x11, dst, value as u32, (value >> 32) as u32)
151 }
152 ByteCode::Float { dst, value } => {
153 let bits = value.to_bits();
154 (0x12, dst, bits as u32, (bits >> 32) as u32)
155 }
156 ByteCode::Bool { dst, value } => (0x13, dst, value.into(), 0),
157 ByteCode::Move { dst, src } => (0x20, dst, src, 0),
158 ByteCode::Field { dst, src, field } => (0x21, dst, src, field),
159 ByteCode::Call { addr, args, dst } => match addr {
160 Locator::Address(addr) => (0x22, addr, args, dst),
161 Locator::FromRegister(addr) => (0x23, addr, args, dst),
162 }
163 ByteCode::Binary { op, dst, left, right } => (0x30 + op as u8, dst, left, right),
164 ByteCode::Unary { op, dst, right } => (0x40 + op as u8, dst, right, 0),
165 }
166 }
167}
168
169#[derive(Debug, Clone, PartialEq)]
170pub enum ByteCodeError {
171 InvalidOperation,
172 InvalidBinaryOperation(u8),
173 InvalidUnaryOperation(u8),
174}
175impl Display for ByteCodeError {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 ByteCodeError::InvalidOperation => write!(f, "invalid operation"),
179 ByteCodeError::InvalidBinaryOperation(op) => {
180 write!(f, "invalid binary operation 0x20 + 0x{op:2x?}")
181 }
182 ByteCodeError::InvalidUnaryOperation(op) => {
183 write!(f, "invalid unary operation 0x30 + 0x{op:2x?}")
184 }
185 }
186 }
187}
188impl Error for ByteCodeError {}
189impl TryFrom<Bytes> for ByteCode {
190 type Error = ByteCodeError;
191 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
192 match value.0 {
193 0x00 => Ok(Self::None),
194 0x01 => Ok(Self::Halt),
195 0x02 => Ok(Self::Jump {
196 addr: Locator::Address(value.2),
197 }),
198 0x03 => Ok(Self::Jump {
199 addr: Locator::FromRegister(value.2),
200 }),
201 0x04 => Ok(Self::JumpIf {
202 cond: value.1,
203 addr: Locator::Address(value.2),
204 }),
205 0x05 => Ok(Self::JumpIf {
206 cond: value.1,
207 addr: Locator::FromRegister(value.2),
208 }),
209
210 0x10 => Ok(Self::String {
211 dst: value.1,
212 addr: value.2,
213 }),
214 0x11 => Ok(Self::Int {
215 dst: value.1,
216 value: (value.2 as u64) | ((value.3 as u64) << 32),
217 }),
218 0x12 => Ok(Self::Float {
219 dst: value.1,
220 value: f64::from_bits((value.2 as u64) | ((value.3 as u64) << 32)),
221 }),
222 0x13 => Ok(Self::Bool {
223 dst: value.1,
224 value: value.2 != 0,
225 }),
226
227 0x20 => Ok(Self::Move {
228 dst: value.1,
229 src: value.2,
230 }),
231 0x21 => Ok(Self::Field {
232 dst: value.1,
233 src: value.2,
234 field: value.3,
235 }),
236 0x22 => Ok(Self::Call {
237 addr: Locator::Address(value.1),
238 args: value.2,
239 dst: value.3
240 }),
241 0x23 => Ok(Self::Call {
242 addr: Locator::FromRegister(value.1),
243 args: value.2,
244 dst: value.3
245 }),
246
247 0x30..=0x3f => Ok(Self::Binary {
248 op: BinaryOperation::try_from(value.0 - 0x20)
249 .map_err(|_| ByteCodeError::InvalidBinaryOperation(value.0 - 0x20))?,
250 dst: value.1,
251 left: value.2,
252 right: value.3,
253 }),
254 0x40..=0x4f => Ok(Self::Unary {
255 op: UnaryOperation::try_from(value.0 - 0x20)
256 .map_err(|_| ByteCodeError::InvalidUnaryOperation(value.0 - 0x30))?,
257 dst: value.1,
258 right: value.2,
259 }),
260 _ => Err(ByteCodeError::InvalidOperation),
261 }
262 }
263}
264
265#[derive(Debug, Clone, PartialEq)]
266pub struct Program {
267 pub strings: Vec<String>,
268 pub code: Vec<ByteCode>,
269}
270#[derive(Debug, Clone, PartialEq)]
271pub enum ProgramParseError {
272 InsufficiantBytes,
273 ByteCodeError(ByteCodeError)
274}
275impl Display for ProgramParseError {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 match self {
278 ProgramParseError::InsufficiantBytes => write!(f, "insufficiant bytes"),
279 ProgramParseError::ByteCodeError(err) => err.fmt(f),
280 }
281 }
282}
283impl Error for ProgramParseError {}
284impl TryFrom<&[u8]> for Program {
285 type Error = ProgramParseError;
286 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
287 let mut bytes = value.iter();
288
289 let size = {
290 let (Some(n1), Some(n2), Some(n3), Some(n4)) = (bytes.next().copied(), bytes.next().copied(), bytes.next().copied(), bytes.next().copied()) else {
291 return Err(ProgramParseError::InsufficiantBytes);
292 };
293 u32::from_be_bytes([n1, n2, n3, n4])
294 };
295 let mut strings = Vec::with_capacity(size as usize);
296 for _ in 0..size {
297 let string_size = {
298 let (Some(n1), Some(n2), Some(n3), Some(n4)) = (bytes.next().copied(), bytes.next().copied(), bytes.next().copied(), bytes.next().copied()) else {
299 return Err(ProgramParseError::InsufficiantBytes);
300 };
301 u32::from_be_bytes([n1, n2, n3, n4])
302 };
303 let mut string = String::new();
304 for _ in 0..string_size {
305 let Some(c) = bytes.next().copied() else {
306 return Err(ProgramParseError::InsufficiantBytes);
307 };
308 string.push(c as char);
309 }
310 strings.push(string);
311 }
312
313 let mut code = vec![];
314 while let Some(instr) = bytes.next().copied() {
315 let arg1 = {
316 let (Some(n1), Some(n2), Some(n3), Some(n4)) = (bytes.next().copied(), bytes.next().copied(), bytes.next().copied(), bytes.next().copied()) else {
317 return Err(ProgramParseError::InsufficiantBytes);
318 };
319 u32::from_be_bytes([n1, n2, n3, n4])
320 };
321 let arg2 = {
322 let (Some(n1), Some(n2), Some(n3), Some(n4)) = (bytes.next().copied(), bytes.next().copied(), bytes.next().copied(), bytes.next().copied()) else {
323 return Err(ProgramParseError::InsufficiantBytes);
324 };
325 u32::from_be_bytes([n1, n2, n3, n4])
326 };
327 let arg3 = {
328 let (Some(n1), Some(n2), Some(n3), Some(n4)) = (bytes.next().copied(), bytes.next().copied(), bytes.next().copied(), bytes.next().copied()) else {
329 return Err(ProgramParseError::InsufficiantBytes);
330 };
331 u32::from_be_bytes([n1, n2, n3, n4])
332 };
333 code.push(ByteCode::try_from((instr, arg1, arg2, arg3)).map_err(ProgramParseError::ByteCodeError)?);
334 }
335
336 Ok(Self { strings, code })
337 }
338}
339impl From<Program> for Vec<u8> {
340 fn from(program: Program) -> Self {
341 let mut bytes = vec![];
342
343 bytes.extend((program.strings.len() as u32).to_be_bytes());
344 for string in program.strings {
345 bytes.extend((string.len() as u32).to_be_bytes());
346 bytes.extend(string.chars().map(|c| c as u8));
347 }
348
349 for bytecode in program.code {
350 let (instr, arg1, arg2, arg3): Bytes = bytecode.into();
351 bytes.push(instr);
352 bytes.extend(arg1.to_be_bytes());
353 bytes.extend(arg2.to_be_bytes());
354 bytes.extend(arg3.to_be_bytes());
355 }
356
357 bytes
358 }
359}