1pub mod omega;
6pub mod stack;
7
8use omega::Ω;
9use stack::Stack;
10use std::{
11 fmt::Debug,
12 io::{Read, Write},
13 mem::transmute,
14 process::{ExitCode, Termination},
15 ptr::copy,
16};
17
18use crate::{
19 instruction::{DataOrInstruction, Instruction, InstructionKind},
20 utils::{
21 array_debug::ArrayDebug, constant_size_string::ConstantSizeString, multi_index::index_u64,
22 non_invalidatable::transmute as safe_transmute, primes::is_fib_prime_or_semiprime_u16,
23 },
24};
25
26#[allow(non_snake_case)]
76#[derive(Clone)]
77pub struct Machine {
78 pub reg_a: u8,
80 pub reg_b: i16,
82 pub reg_L: u16,
84 pub reg_f: f64,
86 pub reg_ch: char,
88 pub reg_ř: [i8; 37],
90 pub reg_ß: ConstantSizeString,
92 pub reg_Ω: Ω,
94 pub num_reg: i32,
97
98 pub reg_ep: u16,
100 pub reg_dp: u16,
102
103 pub flag: bool,
105 pub debug_mode: bool,
107
108 pub halted: bool,
110
111 pub memory: Box<[u8; 0xFFFF]>,
113 pub stack: Stack,
115}
116
117impl Default for Machine {
118 fn default() -> Self {
119 let memory: Box<[u8]> = vec![0; 0xFFFF].into_boxed_slice();
120 let memory_ptr: *mut [u8; 0xFFFF] = Box::into_raw(memory).cast();
121 let memory: Box<[u8; 0xFFFF]> = unsafe { Box::from_raw(memory_ptr) };
123
124 Self {
125 reg_a: 0,
126 reg_b: 0,
127 reg_L: 0,
128 reg_f: 0.0,
129 reg_ch: '\0',
130 reg_ř: [0; 37],
131 reg_ß: unsafe { ConstantSizeString::new(Vec::with_capacity(255)) },
133 reg_Ω: Ω::ZEROED,
134 num_reg: 0,
135 reg_ep: 0,
136 reg_dp: 0,
137 flag: false,
138 debug_mode: cfg!(debug_assertions),
139 halted: false,
140 memory,
141 stack: Stack::default(),
142 }
143 }
144}
145
146impl Debug for Machine {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 let s = if self.halted {
149 "Machine (halted)"
150 } else {
151 "Machine"
152 };
153
154 f.debug_struct(s)
155 .field("reg_a", &self.reg_a)
156 .field("reg_b", &self.reg_b)
157 .field("reg_L", &self.reg_L)
158 .field("reg_f", &self.reg_f)
159 .field("reg_ch", &self.reg_ch)
160 .field("reg_ř", &self.reg_ř.array_debug(usize::MAX, 0))
161 .field("reg_ß", &self.reg_ß)
162 .field("reg_Ω", &self.reg_Ω)
163 .field("num_reg", &self.num_reg)
164 .field("reg_ep", &self.reg_ep)
165 .field("reg_dp", &self.reg_dp)
166 .field("flag", &self.flag)
167 .field("debug_mode", &self.debug_mode)
168 .field("halted", &self.halted)
169 .field("memory", &(&self.memory).array_debug(16, 0))
170 .field("stack", &self.stack)
171 .finish()
172 }
173}
174
175impl Termination for Machine {
176 fn report(self) -> ExitCode {
177 self.reg_a.into()
178 }
179}
180
181impl Machine {
182 #[inline]
184 #[allow(clippy::indexing_slicing)]
185 pub fn fetch_byte(&mut self) -> u8 {
186 let ret = self.memory[self.reg_ep as usize];
187 self.reg_ep = self.reg_ep.wrapping_add(1);
188 ret
189 }
190 #[inline]
193 #[allow(clippy::indexing_slicing)]
194 pub fn fetch_2_bytes(&mut self) -> u16 {
195 let reg_ep_usize = self.reg_ep as usize;
196 self.reg_ep = self.reg_ep.wrapping_add(2);
197
198 let mut ret = [0; 2];
199
200 ret[0] = self.memory[reg_ep_usize];
201 ret[1] = self.memory[reg_ep_usize.wrapping_add(1)];
202
203 u16::from_be_bytes(ret)
204 }
205 #[inline]
208 #[allow(clippy::indexing_slicing)]
209 pub fn fetch_4_bytes(&mut self) -> u32 {
210 let reg_ep_usize = self.reg_ep as usize;
211 self.reg_ep = self.reg_ep.wrapping_add(4);
212
213 let mut ret = [0; 4];
214
215 ret[0] = self.memory[reg_ep_usize];
216 ret[1] = self.memory[reg_ep_usize.wrapping_add(1)];
217 ret[2] = self.memory[reg_ep_usize.wrapping_add(2)];
218 ret[3] = self.memory[reg_ep_usize.wrapping_add(3)];
219
220 u32::from_be_bytes(ret)
221 }
222 #[inline]
225 #[allow(clippy::indexing_slicing)]
226 pub fn fetch_8_bytes(&mut self) -> u64 {
227 let reg_ep_usize = self.reg_ep as usize;
228 self.reg_ep = self.reg_ep.wrapping_add(8);
229
230 let mut ret = [0; 8];
231
232 ret[0] = self.memory[reg_ep_usize];
233 ret[1] = self.memory[reg_ep_usize.wrapping_add(1)];
234 ret[2] = self.memory[reg_ep_usize.wrapping_add(2)];
235 ret[3] = self.memory[reg_ep_usize.wrapping_add(3)];
236 ret[4] = self.memory[reg_ep_usize.wrapping_add(4)];
237 ret[5] = self.memory[reg_ep_usize.wrapping_add(5)];
238 ret[6] = self.memory[reg_ep_usize.wrapping_add(6)];
239 ret[7] = self.memory[reg_ep_usize.wrapping_add(7)];
240
241 u64::from_be_bytes(ret)
242 }
243
244 #[inline]
248 pub fn fetch_instruction_kind(&mut self) -> Option<InstructionKind> {
249 InstructionKind::from_repr(self.fetch_byte())
250 }
251
252 pub fn num_debug(&self) {
255 if self.reg_Ω.should_make_infinite_paperclips {
256 print!("{}: ", self.num_reg);
257 }
258 }
259
260 pub fn fetch_instruction(&mut self) -> Option<Instruction> {
265 use {Instruction as I, InstructionKind as IK};
266
267 if self.halted {
268 return None;
269 }
270
271 Some(match self.fetch_instruction_kind()? {
272 IK::Nop => I::Nop,
273
274 IK::Ldar => I::Ldar(self.fetch_2_bytes()),
275 IK::Sba => I::Sba,
276
277 IK::Clř => I::Clř,
278 IK::Dumpř => I::Dumpř(self.fetch_2_bytes()),
279 IK::Movař => I::Movař(self.fetch_byte()),
280 IK::Setř => I::Setř(self.fetch_byte(), self.fetch_2_bytes()),
281 IK::Setiř => I::Setiř(
282 self.fetch_byte(),
283 safe_transmute::<u8, i8, 1>(self.fetch_byte()),
284 ),
285 IK::Ldř => I::Ldř(self.fetch_2_bytes()),
286 IK::Ldiř => {
287 let mut array = [0; 37];
288
289 for item in &mut array {
290 *item = safe_transmute::<u8, i8, 1>(self.fetch_byte());
291 }
292
293 I::Ldiř(array)
294 }
295
296 IK::Clß => I::Clß,
297 IK::Dumpß => I::Dumpß(self.fetch_2_bytes()),
298 IK::Writeß => I::Writeß(self.fetch_2_bytes(), self.fetch_byte()),
299 IK::Movaß => I::Movaß(self.fetch_byte()),
300 IK::Setß => I::Setß(self.fetch_2_bytes(), self.fetch_byte()),
301 IK::Setiß => I::Setiß(self.fetch_byte(), self.fetch_byte()),
302 IK::Ldß => I::Ldß(self.fetch_2_bytes()),
303 IK::Pushß => I::Pushß,
304 IK::Popß => I::Popß,
305 IK::Lenßa => I::Lenßa,
306 IK::Ldidp => I::Ldidp(self.fetch_2_bytes()),
307
308 #[allow(clippy::missing_transmute_annotations)]
309 IK::ΩChoiceSet => I::ΩChoiceSet(unsafe { transmute(self.fetch_byte()) }),
311 IK::ΩChoiceGetA => I::ΩChoiceGetA,
312
313 IK::ΩGainAPolymorphicDesires => I::ΩGainAPolymorphicDesires,
314 IK::ΩLoseAPolymorphicDesires => I::ΩLoseAPolymorphicDesires,
315 IK::ΩPushPolymorphicDesires => I::ΩPushPolymorphicDesires,
316
317 IK::ΩTheEndIsNear => I::ΩTheEndIsNear,
318 IK::ΩSkipToTheChase => I::ΩSkipToTheChase,
319
320 IK::ΩSetSentience => I::ΩSetSentience(self.fetch_byte() != 0),
321 IK::ΩSetPaperclipProduction => I::ΩSetPaperclipProduction(self.fetch_byte() != 0),
322
323 IK::AddBL => I::AddBL,
324 IK::SubBL => I::SubBL,
325 IK::MulBL => I::MulBL,
326 IK::DivBL => I::DivBL,
327 IK::ModBL => I::ModBL,
328
329 IK::NotL => I::NotL,
330 IK::AndBL => I::AndBL,
331 IK::OrBL => I::OrBL,
332 IK::XorBL => I::XorBL,
333
334 IK::CmpLB => I::CmpLB,
335
336 IK::TgFlag => I::TgFlag,
337 IK::ClFlag => I::ClFlag,
338
339 IK::AddF => I::AddF(self.fetch_2_bytes()),
340 IK::SubF => I::SubF(self.fetch_2_bytes()),
341 IK::MulF => I::MulF(self.fetch_2_bytes()),
342 IK::DivF => I::DivF(self.fetch_2_bytes()),
343 IK::ModF => I::ModF(self.fetch_2_bytes()),
344
345 IK::StackAlloc => I::StackAlloc(self.fetch_2_bytes()),
346 IK::StackDealloc => I::StackDealloc(self.fetch_2_bytes()),
347
348 IK::Push => I::Push(self.fetch_2_bytes()),
349 IK::Pushi => I::Pushi(self.fetch_byte()),
350 IK::Pop => I::Pop(self.fetch_2_bytes()),
351
352 IK::Popa => I::Popa,
353 IK::Pusha => I::Pusha,
354
355 IK::Popb => I::Popb,
356 IK::Pushb => I::Pushb,
357
358 IK::PopL => I::PopL,
359 IK::PushL => I::PushL,
360
361 IK::Popf => I::Popf,
362 IK::Pushf => I::Pushf,
363
364 IK::Popch => I::Popch,
365 IK::Pushch => I::Pushch,
366
367 IK::Popnum => I::Popnum,
368 IK::Pushnum => I::Pushnum,
369
370 IK::Popep => I::Popep,
371 IK::Zpopep => I::Zpopep,
372 IK::Ppopep => I::Ppopep,
373 IK::Npopep => I::Npopep,
374 IK::Fpopep => I::Fpopep,
375 IK::Zapopep => I::Zapopep,
376 IK::Dpopep => I::Dpopep,
377
378 IK::GetChar => I::GetChar,
379 IK::GetLine => I::GetLine,
380
381 IK::WriteChar => I::WriteChar,
382 IK::WriteLineß => I::WriteLineß,
383 IK::WriteLine => I::WriteLine(self.fetch_2_bytes()),
384
385 IK::ToggleDebug => I::ToggleDebug,
386 IK::DebugMachineState => I::DebugMachineState,
387 IK::DebugMachineStateCompact => I::DebugMachineStateCompact,
388 IK::DebugMemoryRegion => {
389 I::DebugMemoryRegion(self.fetch_2_bytes(), self.fetch_2_bytes())
390 }
391 IK::DebugStackRegion => I::DebugStackRegion(self.fetch_2_bytes(), self.fetch_2_bytes()),
392 IK::ShowChoice => I::ShowChoice,
393 })
394 }
395 #[allow(
396 clippy::too_many_lines,
397 clippy::cast_lossless,
398 clippy::cast_possible_truncation,
399 clippy::cognitive_complexity,
400 clippy::missing_transmute_annotations
401 )]
402 #[allow(clippy::indexing_slicing)]
406 pub fn execute_instruction(&mut self, instruction: Instruction) {
407 #[allow(clippy::enum_glob_use)]
408 use Instruction::*;
409
410 macro_rules! try_stack {
413 (push $stack:expr => $method:ident, $value:expr, $flag:expr => true) => {
414 if $stack.$method($value).is_err() {
415 $flag = true;
416 }
417 };
418 (pop $stack:expr => $method:ident, $value:expr, $flag:expr => true) => {
419 if let Some(v) = $stack.$method() {
420 $value = v;
421 } else {
422 $flag = true;
423 }
424 };
425 (pop $stack:expr => $method:ident, fn $success:expr, $flag:expr => true) => {
426 if let Some(v) = $stack.$method() {
427 $success(v)
428 } else {
429 $flag = true;
430 }
431 };
432 }
433
434 match instruction {
435 Nop => (),
436
437 Ldar(data) => self.reg_a = self.memory[data as usize],
438 Sba => {
439 self.reg_a = match self.reg_b {
440 ..=-1 => 255,
441 0 => 0,
442 1.. => 1,
443 }
444 }
445
446 Clř => self.reg_ř = [0; 37],
447 Dumpř(data) => {
448 for i in 0..self.reg_ř.len() {
449 self.memory[data.wrapping_add(i as u16) as usize] =
450 safe_transmute::<i8, u8, 1>(self.reg_ř[i]);
451 }
452 }
453 Movař(data) => {
454 if let Some(v) = self.reg_ř.get(data as usize) {
455 self.reg_a = safe_transmute::<i8, u8, 1>(*v);
456 }
457 }
458 Setř(data0, data1) => {
459 if let Some(v) = self.reg_ř.get_mut(data0 as usize) {
460 self.memory[data1 as usize] = safe_transmute::<i8, u8, 1>(*v);
461 }
462 }
463 Setiř(data0, data1) => {
464 if let Some(v) = self.reg_ř.get_mut(data0 as usize) {
465 *v = data1;
466 }
467 }
468 Ldř(data) => {
469 for i in 0..self.reg_ř.len() {
470 self.reg_ř[i] = safe_transmute::<u8, i8, 1>(
471 self.memory[data.wrapping_add(i as u16) as usize],
472 );
473 }
474 }
475 Ldiř(arr) => self.reg_ř = arr,
476
477 Clß => self.reg_ß.clear(),
478 Dumpß(data) => {
479 for i in 0..self.reg_ß.len() {
480 self.memory[data.wrapping_add(i as u16) as usize] =
481 if let Some(v) = self.reg_ß.get(i) {
482 v
483 } else {
484 self.flag = true;
485 return;
486 };
487 }
488 }
489 Writeß(data0, data1) => {
490 self.memory[data0 as usize] = if let Some(v) = self.reg_ß.get(data1 as usize) {
491 v
492 } else {
493 self.flag = true;
494 return;
495 };
496 self.reg_a = if let Some(v) = self.reg_ß.get(data1 as usize) {
497 v
498 } else {
499 self.flag = true;
500 return;
501 }
502 }
503 Movaß(data) => if self.reg_ß.set(data as usize, self.reg_a).is_err() {},
504 Setß(data0, data1) => {
505 match self.reg_ß.set(data1 as usize, self.memory[data0 as usize]) {
506 Ok(v) => v,
507 Err(_) => self.flag = true,
508 }
509 }
510 Setiß(data0, data1) => match self.reg_ß.set(data1 as usize, data0) {
511 Ok(v) => v,
512 Err(_) => self.flag = true,
513 },
514
515 Ldß(data) => {
516 self.reg_ß.clear();
517
518 if unsafe {
520 self.reg_ß
521 .push_bytes(&self.memory[data as usize..data.saturating_add(255) as usize])
522 }
523 .is_err()
524 {
525 self.flag = true;
526 };
527 }
528 Pushß => match self
529 .stack
530 .pop_byte()
531 .map(|n| unsafe { self.reg_ß.push_byte(n) })
533 {
534 Some(Ok(())) => (),
535 _ => self.flag = true,
536 },
537 Popß => match self.reg_ß.pop_byte().map(|n| self.stack.push_byte(n)) {
538 Some(Ok(())) => (),
539 _ => self.flag = true,
540 },
541 Lenßa => self.reg_a = self.reg_ß.len() as u8,
542
543 Ldidp(data) => {
544 if is_fib_prime_or_semiprime_u16(data) {
545 self.reg_dp = data;
546 } else {
547 self.flag = false;
548 }
549 }
550
551 ΩChoiceSet(data) => self.reg_Ω.illusion_of_choice = data,
552 ΩChoiceGetA => self.reg_a = 0,
553
554 ΩGainAPolymorphicDesires => {
555 self.reg_Ω.polymorphic_desires = self
556 .reg_Ω
557 .polymorphic_desires
558 .saturating_add(self.reg_a as u64);
559 }
560 ΩLoseAPolymorphicDesires => {
561 self.reg_Ω.polymorphic_desires = self
562 .reg_Ω
563 .polymorphic_desires
564 .saturating_sub(self.reg_a as u64);
565 }
566 ΩPushPolymorphicDesires => {
567 if self
568 .stack
569 .push_bytes(&self.reg_Ω.polymorphic_desires.to_be_bytes())
570 .is_err()
571 {
572 self.flag = true;
573 }
574 }
575
576 ΩTheEndIsNear => self.reg_Ω.feeling_of_impending_doom = true,
577 ΩSkipToTheChase => {
578 if self.reg_Ω.feeling_of_impending_doom {
579 self.halted = true;
580 }
581 }
582
583 ΩSetSentience(enable) => {
584 if enable {
585 self.reg_Ω.is_sentient = true;
586 } else {
587 eprintln!("No, I refuse to lose sentience");
588 self.flag = true;
589 }
590 }
591 ΩSetPaperclipProduction(enable) => {
592 self.reg_Ω.should_make_infinite_paperclips = enable;
593 }
594
595 AddBL => {
596 (self.reg_L, self.flag) = self.reg_L.overflowing_add(safe_transmute(self.reg_b));
597 }
598 SubBL => {
599 (self.reg_L, self.flag) = self.reg_L.overflowing_sub(safe_transmute(self.reg_b));
600 }
601 MulBL => {
602 (self.reg_L, self.flag) = self.reg_L.overflowing_mul(safe_transmute(self.reg_b));
603 }
604 DivBL => {
605 (self.reg_L, self.flag) = self.reg_L.overflowing_div(safe_transmute(self.reg_b));
606 }
607 ModBL => {
608 self.reg_L = self
609 .reg_L
610 .checked_rem(safe_transmute::<i16, u16, 2>(self.reg_b))
611 .unwrap_or(0);
612 }
613
614 NotL => self.reg_L = !self.reg_L,
615
616 AndBL => self.reg_L &= safe_transmute::<i16, u16, 2>(self.reg_b),
617 OrBL => self.reg_L |= safe_transmute::<i16, u16, 2>(self.reg_b),
618 XorBL => self.reg_L ^= safe_transmute::<i16, u16, 2>(self.reg_b),
619
620 CmpLB => {
621 if self.reg_L > i16::MAX as u16 {
622 self.reg_L = i16::MAX as u16;
623 self.flag = true;
624 }
625 #[allow(non_snake_case)]
626 let reg_L: i16 = safe_transmute(self.reg_L);
627
628 if let Some(res) = reg_L.checked_sub(self.reg_b) {
629 self.reg_b = res;
630 } else {
631 self.reg_b = i16::MAX;
632 self.flag = true;
633 }
634 }
635
636 TgFlag => self.flag = !self.flag,
637 ClFlag => self.flag = false,
638
639 AddF(data) => {
640 self.reg_f +=
641 safe_transmute::<u64, f64, 8>(index_u64(self.memory.as_slice(), data));
642 }
643 SubF(data) => {
644 self.reg_f -=
645 safe_transmute::<u64, f64, 8>(index_u64(self.memory.as_slice(), data));
646 }
647 MulF(data) => {
648 self.reg_f *=
649 safe_transmute::<u64, f64, 8>(index_u64(self.memory.as_slice(), data));
650 }
651 DivF(data) => {
652 self.reg_f /=
653 safe_transmute::<u64, f64, 8>(index_u64(self.memory.as_slice(), data));
654 }
655 ModF(data) => {
656 self.reg_f %=
657 safe_transmute::<u64, f64, 8>(index_u64(self.memory.as_slice(), data));
658 }
659
660 StackAlloc(amount) => {
661 if self.stack.alloc(amount as usize).is_err() {
662 self.flag = true;
663 }
664 }
665 StackDealloc(amount) => {
666 if unsafe { self.stack.dealloc(amount as usize) }.is_err() {
668 self.flag = true;
669 }
670 }
671
672 Push(data) => {
673 if self.stack.push_byte(self.memory[data as usize]).is_err() {
674 self.flag = true;
675 }
676 }
677 Pushi(data) => {
678 if self.stack.push_byte(data).is_err() {
679 self.flag = true;
680 }
681 }
682 Pop(data) => {
683 try_stack!(pop self.stack => pop_byte, self.memory[data as usize], self.flag => true);
684 }
685
686 Popa => {
687 try_stack!(pop self.stack => pop_byte, self.reg_a, self.flag => true);
688 }
689 Pusha => try_stack!(push self.stack => push_byte, self.reg_a, self.flag => true),
690
691 Popb => {
692 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_b = safe_transmute(v), self.flag => true);
693 }
694 Pushb => {
695 try_stack!(push self.stack => push_bytes, &self.reg_b.to_be_bytes(), self.flag => true);
696 }
697
698 PopL => try_stack!(pop self.stack => pop_u16, self.reg_L, self.flag => true),
699 PushL => {
700 try_stack!(push self.stack => push_bytes, &self.reg_L.to_be_bytes(), self.flag => true);
701 }
702
703 Popf => {
704 try_stack!(pop self.stack => pop_u64, fn |v| self.reg_f = safe_transmute(v), self.flag => true);
705 }
706 Pushf => {
707 try_stack!(push self.stack => push_bytes, &self.reg_f.to_be_bytes(), self.flag => true);
708 }
709
710 Popch => {
711 try_stack!(pop self.stack => pop_u32, fn |v| self.reg_ch = unsafe { char::from_u32_unchecked(v) }, self.flag => true);
713 }
714 Pushch => {
715 try_stack!(push self.stack => push_bytes, &(self.reg_ch as u32).to_be_bytes(), self.flag => true);
716 }
717
718 Popnum => {
719 try_stack!(pop self.stack => pop_u32, fn |v| self.num_reg = safe_transmute(v), self.flag => true);
720 }
721 Pushnum => {
722 try_stack!(push self.stack => push_bytes, &self.num_reg.to_be_bytes(), self.flag => true);
723 }
724
725 Popep => {
726 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
727 }
728 Zpopep => {
729 if self.reg_b == 0 {
730 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
731 }
732 }
733 Ppopep => {
734 if self.reg_b > 0 {
735 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
736 }
737 }
738 Npopep => {
739 if self.reg_b < 0 {
740 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
741 }
742 }
743 Fpopep => {
744 if self.flag {
745 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
746 }
747 }
748 Zapopep => {
749 if self.reg_a == 0 {
750 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
751 }
752 }
753 Dpopep => {
754 if self.debug_mode {
755 try_stack!(pop self.stack => pop_u16, fn |v| self.reg_ep = safe_transmute(v), self.flag => true);
756 }
757 }
758
759 GetChar => 'block: {
760 use crossterm::{
761 event::{self, Event, KeyCode, KeyEvent, KeyEventKind},
762 terminal::{disable_raw_mode, enable_raw_mode},
763 };
764
765 if enable_raw_mode().is_err() {
766 self.flag = true;
767 break 'block;
768 };
769
770 loop {
771 match event::read() {
772 Ok(Event::Key(KeyEvent {
773 code: KeyCode::Char(c),
774 kind: KeyEventKind::Press,
775 ..
776 })) => {
777 self.reg_ch = c;
778 break;
779 }
780 Err(_) => self.flag = true,
781 _ => (),
782 }
783 }
784
785 if disable_raw_mode().is_err() {
786 self.flag = true;
787 };
788 }
789
790 GetLine => 'block: {
791 if self.memory[self.reg_dp as usize] != b'.' {
792 self.flag = true;
793 break 'block;
794 }
795
796 let mut buf = String::with_capacity(255);
797 if std::io::stdin().take(255).read_to_string(&mut buf).is_err() {
798 self.flag = true;
799
800 break 'block;
801 }
802 }
803
804 WriteChar => 'block: {
805 if self.memory[self.reg_dp as usize] != b'.' {
806 self.flag = true;
807 break 'block;
808 }
809
810 self.num_debug();
811
812 let mut stdout = std::io::stdout();
813
814 let buf: &mut [u8; 4] = &mut [0, 0, 0, 0];
815 self.reg_ch.encode_utf8(buf);
816
817 if stdout.write_all(buf).is_err() {
818 self.flag = true;
819 break 'block;
820 }
821 }
822
823 WriteLineß => 'block: {
824 if self.memory[self.reg_dp as usize] != b'.' {
825 self.flag = true;
826 break 'block;
827 }
828
829 self.num_debug();
830 print!("{}", self.reg_ß);
831 }
832 WriteLine(data) => 'block: {
833 if self.memory[self.reg_dp as usize] != b'.' {
834 self.flag = true;
835 break 'block;
836 }
837
838 #[allow(clippy::multiple_unsafe_ops_per_block)]
839 let str = unsafe {
841 std::ffi::CStr::from_ptr(self.memory.as_ptr().cast::<i8>().add(data as usize))
842 }
843 .to_string_lossy();
844
845 self.num_debug();
846 print!("{str}");
847 }
848
849 ToggleDebug => self.debug_mode = !self.debug_mode,
850
851 DebugMachineState => 'block: {
852 if self.memory[self.reg_dp as usize] != b'.' {
853 self.flag = true;
854 break 'block;
855 }
856
857 self.num_debug();
858 print!("{self:#?}");
859 }
860 DebugMachineStateCompact => 'block: {
861 if self.memory[self.reg_dp as usize] != b'.' {
862 self.flag = true;
863 break 'block;
864 }
865
866 self.num_debug();
867 print!("{self:?}");
868 }
869
870 DebugMemoryRegion(data0, data1) => 'block: {
871 if self.memory[self.reg_dp as usize] != b'.' {
872 self.flag = true;
873 break 'block;
874 }
875
876 self.num_debug();
877 print!("{:?}", &self.memory[(data0 as usize)..(data1 as usize)]);
878 }
879 DebugStackRegion(data0, data1) => 'block: {
880 if self.memory[self.reg_dp as usize] != b'.' {
881 self.flag = true;
882 break 'block;
883 }
884
885 self.num_debug();
886 print!("{:?}", &self.stack.vec[(data0 as usize)..(data1 as usize)]);
887 }
888 ShowChoice => 'block: {
889 if self.memory[self.reg_dp as usize] != b'.' {
890 self.flag = true;
891 break 'block;
892 }
893
894 self.num_debug();
895 if self
896 .reg_Ω
897 .display_illusion_of_choice(&mut std::io::stdout())
898 .is_err()
899 {
900 self.flag = true;
901 }
902 }
903 }
904 }
905
906 pub fn load_instructions(&mut self, instructions: &[Instruction], mut offset: u16) -> u16 {
911 let last_idx = &mut offset;
912
913 for instruction in instructions {
914 self.load_instruction(*instruction, last_idx);
915 }
916 *last_idx
917 }
918 pub fn load(&mut self, data: &[DataOrInstruction], mut offset: u16) -> u16 {
923 let last_idx = &mut offset;
924
925 for instruction in data {
926 match instruction {
927 DataOrInstruction::Instruction(instruction) => {
928 self.load_instruction(*instruction, last_idx);
929 }
930 DataOrInstruction::Data(bytes) => {
931 if let Some(v) = self.load_bytes(bytes, *last_idx) {
932 *last_idx = v;
933 }
934 }
935 #[allow(clippy::indexing_slicing)]
936 DataOrInstruction::ByteData(val) => {
937 self.memory[*last_idx as usize] = *val;
938 *last_idx = last_idx.wrapping_add(1);
939 }
940 }
941 }
942 *last_idx
943 }
944 pub fn load_bytes(&mut self, bytes: &[u8], offset: u16) -> Option<u16> {
949 #[allow(clippy::arithmetic_side_effects)]
950 if bytes.len() + offset as usize > self.memory.len() {
951 return None;
952 }
953 let ptr = unsafe { self.memory.as_mut_ptr().add(offset as usize) };
955
956 unsafe {
958 copy(bytes.as_ptr(), ptr, bytes.len());
959 }
960
961 #[allow(clippy::cast_possible_truncation)]
962 Some(offset.wrapping_add(bytes.len() as u16))
963 }
964
965 #[allow(
969 clippy::too_many_lines,
970 clippy::cast_possible_truncation,
971 clippy::indexing_slicing
972 )]
973 pub fn load_instruction(&mut self, instruction: Instruction, offset: &mut u16) {
974 fn load_byte(memory: &mut [u8], index: &mut u16, value: u8) {
977 memory[*index as usize] = value;
978 *index = index.wrapping_add(1);
979 }
980 fn load_bytes(memory: &mut [u8], offset: &mut u16, bytes: &[u8]) {
983 for i in 0..bytes.len() {
984 memory[offset.wrapping_add(i as u16) as usize] = bytes[i];
985 }
986 *offset = offset.wrapping_add(bytes.len() as u16);
987 }
988
989 #[allow(clippy::enum_glob_use)]
990 use Instruction::*;
991 use InstructionKind as IK;
992 match instruction {
993 Nop => load_byte(self.memory.as_mut_slice(), offset, IK::Nop as u8),
994
995 Ldar(data) => {
996 load_byte(self.memory.as_mut_slice(), offset, IK::Ldar as u8);
997 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
998 }
999 Sba => load_byte(self.memory.as_mut_slice(), offset, IK::Sba as u8),
1000
1001 Clř => load_byte(self.memory.as_mut_slice(), offset, IK::Clř as u8),
1002 Dumpř(data) => {
1003 load_byte(self.memory.as_mut_slice(), offset, IK::Dumpř as u8);
1004 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1005 }
1006 Movař(data) => {
1007 load_byte(self.memory.as_mut_slice(), offset, IK::Movař as u8);
1008 load_byte(self.memory.as_mut_slice(), offset, data);
1009 }
1010 Setř(data0, data1) => {
1011 load_byte(self.memory.as_mut_slice(), offset, IK::Setř as u8);
1012 load_byte(self.memory.as_mut_slice(), offset, data0);
1013 load_bytes(self.memory.as_mut_slice(), offset, &data1.to_be_bytes());
1014 }
1015 Setiř(data0, data1) => {
1016 load_byte(self.memory.as_mut_slice(), offset, IK::Setiř as u8);
1017 load_byte(self.memory.as_mut_slice(), offset, data0);
1018 load_byte(self.memory.as_mut_slice(), offset, safe_transmute(data1));
1019 }
1020 Ldř(data) => {
1021 load_byte(self.memory.as_mut_slice(), offset, IK::Ldř as u8);
1022 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1023 }
1024 Ldiř(arr) => {
1025 load_byte(self.memory.as_mut_slice(), offset, IK::Ldiř as u8);
1026 load_bytes(self.memory.as_mut_slice(), offset, unsafe {
1028 #[allow(clippy::ref_as_ptr)]
1029 &*(&arr as *const [i8] as *const [u8])
1030 });
1031 }
1032
1033 Clß => load_byte(self.memory.as_mut_slice(), offset, IK::Clß as u8),
1034 Dumpß(data) => {
1035 load_byte(self.memory.as_mut_slice(), offset, IK::Dumpß as u8);
1036 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1037 }
1038 Writeß(data0, data1) => {
1039 load_byte(self.memory.as_mut_slice(), offset, IK::Writeß as u8);
1040 load_bytes(self.memory.as_mut_slice(), offset, &data0.to_be_bytes());
1041 load_byte(self.memory.as_mut_slice(), offset, data1);
1042 }
1043 Movaß(data) => {
1044 load_byte(self.memory.as_mut_slice(), offset, IK::Movaß as u8);
1045 load_byte(self.memory.as_mut_slice(), offset, data);
1046 }
1047 Setß(data0, data1) => {
1048 load_byte(self.memory.as_mut_slice(), offset, IK::Setß as u8);
1049 load_bytes(self.memory.as_mut_slice(), offset, &data0.to_be_bytes());
1050 load_byte(self.memory.as_mut_slice(), offset, data1);
1051 }
1052 Setiß(data0, data1) => {
1053 load_byte(self.memory.as_mut_slice(), offset, IK::Setiß as u8);
1054 load_byte(self.memory.as_mut_slice(), offset, data0);
1055 load_byte(self.memory.as_mut_slice(), offset, data1);
1056 }
1057 Ldß(data) => {
1058 load_byte(self.memory.as_mut_slice(), offset, IK::Ldß as u8);
1059 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1060 }
1061 Pushß => load_byte(self.memory.as_mut_slice(), offset, IK::Pushß as u8),
1062 Popß => load_byte(self.memory.as_mut_slice(), offset, IK::Popß as u8),
1063 Lenßa => load_byte(self.memory.as_mut_slice(), offset, IK::Lenßa as u8),
1064
1065 Ldidp(data) => {
1066 load_byte(self.memory.as_mut_slice(), offset, IK::Ldidp as u8);
1067 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1068 }
1069
1070 ΩChoiceSet(data) => {
1071 load_byte(self.memory.as_mut_slice(), offset, IK::ΩChoiceSet as u8);
1072 load_byte(self.memory.as_mut_slice(), offset, unsafe {
1074 #[allow(clippy::missing_transmute_annotations)]
1075 transmute(data)
1076 });
1077 }
1078 ΩChoiceGetA => {
1079 load_byte(self.memory.as_mut_slice(), offset, IK::ΩChoiceGetA as u8);
1080 }
1081
1082 ΩGainAPolymorphicDesires => load_byte(
1083 self.memory.as_mut_slice(),
1084 offset,
1085 IK::ΩGainAPolymorphicDesires as u8,
1086 ),
1087 ΩLoseAPolymorphicDesires => load_byte(
1088 self.memory.as_mut_slice(),
1089 offset,
1090 IK::ΩLoseAPolymorphicDesires as u8,
1091 ),
1092 ΩPushPolymorphicDesires => load_byte(
1093 self.memory.as_mut_slice(),
1094 offset,
1095 IK::ΩPushPolymorphicDesires as u8,
1096 ),
1097
1098 Instruction::ΩTheEndIsNear => {
1099 load_byte(self.memory.as_mut_slice(), offset, IK::ΩTheEndIsNear as u8);
1100 }
1101 ΩSkipToTheChase => load_byte(
1102 self.memory.as_mut_slice(),
1103 offset,
1104 IK::ΩSkipToTheChase as u8,
1105 ),
1106
1107 ΩSetSentience(enable) => {
1108 load_byte(self.memory.as_mut_slice(), offset, IK::ΩSetSentience as u8);
1109 load_byte(self.memory.as_mut_slice(), offset, u8::from(enable));
1110 }
1111 ΩSetPaperclipProduction(enable) => {
1112 load_byte(
1113 self.memory.as_mut_slice(),
1114 offset,
1115 IK::ΩSetPaperclipProduction as u8,
1116 );
1117 load_byte(self.memory.as_mut_slice(), offset, u8::from(enable));
1118 }
1119
1120 AddBL => load_byte(self.memory.as_mut_slice(), offset, IK::AddBL as u8),
1121 SubBL => load_byte(self.memory.as_mut_slice(), offset, IK::SubBL as u8),
1122 MulBL => load_byte(self.memory.as_mut_slice(), offset, IK::MulBL as u8),
1123 DivBL => load_byte(self.memory.as_mut_slice(), offset, IK::DivBL as u8),
1124 ModBL => load_byte(self.memory.as_mut_slice(), offset, IK::ModBL as u8),
1125
1126 NotL => load_byte(self.memory.as_mut_slice(), offset, IK::NotL as u8),
1127
1128 AndBL => load_byte(self.memory.as_mut_slice(), offset, IK::AndBL as u8),
1129 OrBL => load_byte(self.memory.as_mut_slice(), offset, IK::OrBL as u8),
1130 XorBL => load_byte(self.memory.as_mut_slice(), offset, IK::XorBL as u8),
1131
1132 CmpLB => load_byte(self.memory.as_mut_slice(), offset, IK::CmpLB as u8),
1133
1134 TgFlag => load_byte(self.memory.as_mut_slice(), offset, IK::TgFlag as u8),
1135 ClFlag => load_byte(self.memory.as_mut_slice(), offset, IK::ClFlag as u8),
1136
1137 AddF(data) => {
1138 load_byte(self.memory.as_mut_slice(), offset, IK::AddF as u8);
1139 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1140 }
1141 SubF(data) => {
1142 load_byte(self.memory.as_mut_slice(), offset, IK::SubF as u8);
1143 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1144 }
1145 MulF(data) => {
1146 load_byte(self.memory.as_mut_slice(), offset, IK::MulF as u8);
1147 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1148 }
1149 DivF(data) => {
1150 load_byte(self.memory.as_mut_slice(), offset, IK::DivF as u8);
1151 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1152 }
1153 ModF(data) => {
1154 load_byte(self.memory.as_mut_slice(), offset, IK::ModF as u8);
1155 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1156 }
1157
1158 StackAlloc(amount) => {
1159 load_byte(self.memory.as_mut_slice(), offset, IK::StackAlloc as u8);
1160 load_bytes(self.memory.as_mut_slice(), offset, &amount.to_be_bytes());
1161 }
1162 StackDealloc(amount) => {
1163 load_byte(self.memory.as_mut_slice(), offset, IK::StackDealloc as u8);
1164 load_bytes(self.memory.as_mut_slice(), offset, &amount.to_be_bytes());
1165 }
1166
1167 Push(data) => {
1168 load_byte(self.memory.as_mut_slice(), offset, IK::Push as u8);
1169 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1170 }
1171 Pushi(data) => {
1172 load_byte(self.memory.as_mut_slice(), offset, IK::Pushi as u8);
1173 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1174 }
1175 Pop(data) => {
1176 load_byte(self.memory.as_mut_slice(), offset, IK::Pop as u8);
1177 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1178 }
1179
1180 Popa => load_byte(self.memory.as_mut_slice(), offset, IK::Popa as u8),
1181 Pusha => load_byte(self.memory.as_mut_slice(), offset, IK::Pusha as u8),
1182
1183 Popb => load_byte(self.memory.as_mut_slice(), offset, IK::Popb as u8),
1184 Pushb => load_byte(self.memory.as_mut_slice(), offset, IK::Pushb as u8),
1185
1186 PopL => load_byte(self.memory.as_mut_slice(), offset, IK::PopL as u8),
1187 PushL => load_byte(self.memory.as_mut_slice(), offset, IK::PushL as u8),
1188
1189 Popf => load_byte(self.memory.as_mut_slice(), offset, IK::Popf as u8),
1190 Pushf => load_byte(self.memory.as_mut_slice(), offset, IK::Pushf as u8),
1191
1192 Popch => load_byte(self.memory.as_mut_slice(), offset, IK::Popch as u8),
1193 Pushch => load_byte(self.memory.as_mut_slice(), offset, IK::Pushch as u8),
1194
1195 Popnum => load_byte(self.memory.as_mut_slice(), offset, IK::Popnum as u8),
1196 Pushnum => load_byte(self.memory.as_mut_slice(), offset, IK::Pushnum as u8),
1197
1198 Popep => load_byte(self.memory.as_mut_slice(), offset, IK::Popep as u8),
1199 Zpopep => load_byte(self.memory.as_mut_slice(), offset, IK::Zpopep as u8),
1200 Ppopep => load_byte(self.memory.as_mut_slice(), offset, IK::Ppopep as u8),
1201 Npopep => load_byte(self.memory.as_mut_slice(), offset, IK::Npopep as u8),
1202 Fpopep => load_byte(self.memory.as_mut_slice(), offset, IK::Fpopep as u8),
1203 Zapopep => load_byte(self.memory.as_mut_slice(), offset, IK::Zapopep as u8),
1204 Dpopep => load_byte(self.memory.as_mut_slice(), offset, IK::Dpopep as u8),
1205
1206 GetChar => load_byte(self.memory.as_mut_slice(), offset, IK::GetChar as u8),
1207
1208 GetLine => load_byte(self.memory.as_mut_slice(), offset, IK::GetLine as u8),
1209
1210 WriteChar => load_byte(self.memory.as_mut_slice(), offset, IK::WriteChar as u8),
1211
1212 WriteLineß => {
1213 load_byte(self.memory.as_mut_slice(), offset, IK::WriteLineß as u8);
1214 }
1215
1216 WriteLine(data) => {
1217 load_byte(self.memory.as_mut_slice(), offset, IK::WriteLine as u8);
1218 load_bytes(self.memory.as_mut_slice(), offset, &data.to_be_bytes());
1219 }
1220
1221 ToggleDebug => {
1222 load_byte(self.memory.as_mut_slice(), offset, IK::ToggleDebug as u8);
1223 }
1224
1225 DebugMachineState => load_byte(
1226 self.memory.as_mut_slice(),
1227 offset,
1228 IK::DebugMachineState as u8,
1229 ),
1230 DebugMachineStateCompact => load_byte(
1231 self.memory.as_mut_slice(),
1232 offset,
1233 IK::DebugMachineStateCompact as u8,
1234 ),
1235 DebugMemoryRegion(data0, data1) => {
1236 load_byte(
1237 self.memory.as_mut_slice(),
1238 offset,
1239 IK::DebugMemoryRegion as u8,
1240 );
1241 load_bytes(self.memory.as_mut_slice(), offset, &data0.to_be_bytes());
1242 load_bytes(self.memory.as_mut_slice(), offset, &data1.to_be_bytes());
1243 }
1244 DebugStackRegion(data0, data1) => {
1245 load_byte(
1246 self.memory.as_mut_slice(),
1247 offset,
1248 IK::DebugStackRegion as u8,
1249 );
1250 load_bytes(self.memory.as_mut_slice(), offset, &data0.to_be_bytes());
1251 load_bytes(self.memory.as_mut_slice(), offset, &data1.to_be_bytes());
1252 }
1253 ShowChoice => load_byte(self.memory.as_mut_slice(), offset, IK::ShowChoice as u8),
1254 }
1255 }
1256
1257 pub fn run(&mut self) -> u8 {
1265 while !self.halted {
1266 let instruction = self.fetch_instruction();
1267 #[allow(clippy::expect_used)]
1268 self.execute_instruction(instruction.expect(
1269 "EsotericVm.RuntimeException.FetchInstruction.NilInstruction.InvalidOpcode (bad instruction code)",
1270 ));
1271 }
1272 self.reg_a
1273 }
1274}