1use utils::prelude::*;
5
6#[derive(Clone, Debug)]
7pub(crate) struct Interpreter {
8    instruction_pointer: Register,
9    instructions: Vec<Instruction>,
10}
11
12utils::enumerable_enum! {
14    #[repr(u32)]
15    #[derive(Copy, Clone, Debug, PartialEq)]
16    pub(crate) enum Register {
17        A,
18        B,
19        C,
20        D,
21        E,
22        F,
23    }
24}
25
26#[derive(Copy, Clone, Debug)]
27pub(crate) enum Instruction {
28    Addr(Register, Register, Register),
29    Addi(Register, u32, Register),
30    Mulr(Register, Register, Register),
31    Muli(Register, u32, Register),
32    Banr(Register, Register, Register),
33    Bani(Register, u32, Register),
34    Borr(Register, Register, Register),
35    Bori(Register, u32, Register),
36    Setr(Register, Register),
37    Seti(u32, Register),
38    Gtir(u32, Register, Register),
39    Gtri(Register, u32, Register),
40    Gtrr(Register, Register, Register),
41    Eqir(u32, Register, Register),
42    Eqri(Register, u32, Register),
43    Eqrr(Register, Register, Register),
44}
45
46#[derive(Copy, Clone, Debug)]
47pub(crate) enum HookControlFlow {
48    Execute,
49    Next,
50    Halt,
51}
52
53impl Interpreter {
54    pub fn new(input: &str) -> Result<Self, InputError> {
55        let register =
56            parser::byte_range(b'0'..=b'5').map(|b| Register::from_discriminant((b - b'0') as u32));
57        let rrr_instructions = parser::literal_map!(
58            "addr " => Instruction::Addr as fn(_, _, _) -> _,
59            "mulr " => Instruction::Mulr,
60            "banr " => Instruction::Banr,
61            "borr " => Instruction::Borr,
62            "gtrr " => Instruction::Gtrr,
63            "eqrr " => Instruction::Eqrr,
64        );
65        let rir_instructions = parser::literal_map!(
66            "addi " => Instruction::Addi as fn(_, _, _) -> _,
67            "muli " => Instruction::Muli,
68            "bani " => Instruction::Bani,
69            "bori " => Instruction::Bori,
70            "gtri " => Instruction::Gtri,
71            "eqri " => Instruction::Eqri,
72        );
73        let instruction = parser::parse_tree!(
74            (i @ rrr_instructions, a @ register, b' ', b @ register, b' ', c @ register) => i(a, b, c),
75            (i @ rir_instructions, a @ register, b' ', b @ parser::u32(), b' ', c @ register) => i(a, b, c),
76            ("setr ", a @ register, b' ', parser::u32(), b' ', c @ register) => Instruction::Setr(a, c),
77            ("seti ", a @ parser::u32(), b' ', parser::u32(), b' ', c @ register) => Instruction::Seti(a, c),
78            ("gtir ", a @ parser::u32(), b' ', b @ register, b' ', c @ register) => Instruction::Gtir(a, b, c),
79            ("eqir ", a @ parser::u32(), b' ', b @ register, b' ', c @ register) => Instruction::Eqir(a, b, c),
80        );
81
82        let (instruction_pointer, instructions) = register
83            .with_prefix("#ip ")
84            .with_suffix(parser::eol())
85            .then(instruction.repeat(parser::eol(), 1))
86            .parse_complete(input)?;
87
88        Ok(Self {
89            instruction_pointer,
90            instructions,
91        })
92    }
93
94    #[inline]
95    pub fn run(
96        &self,
97        reg: &mut [u32; 6],
98        mut hook: impl FnMut(&[Instruction], Register, &mut [u32; 6]) -> HookControlFlow,
99    ) {
100        while let addr = reg[self.instruction_pointer] as usize
101            && addr < self.instructions.len()
102        {
103            match hook(&self.instructions, self.instruction_pointer, reg) {
104                HookControlFlow::Execute => {}
105                HookControlFlow::Next => continue,
106                HookControlFlow::Halt => return,
107            }
108
109            match self.instructions[addr] {
110                Instruction::Addr(a, b, c) => reg[c] = reg[a].wrapping_add(reg[b]),
111                Instruction::Addi(a, b, c) => reg[c] = reg[a].wrapping_add(b),
112                Instruction::Mulr(a, b, c) => reg[c] = reg[a].wrapping_mul(reg[b]),
113                Instruction::Muli(a, b, c) => reg[c] = reg[a].wrapping_mul(b),
114                Instruction::Banr(a, b, c) => reg[c] = reg[a] & reg[b],
115                Instruction::Bani(a, b, c) => reg[c] = reg[a] & b,
116                Instruction::Borr(a, b, c) => reg[c] = reg[a] | reg[b],
117                Instruction::Bori(a, b, c) => reg[c] = reg[a] | b,
118                Instruction::Setr(a, c) => reg[c] = reg[a],
119                Instruction::Seti(a, c) => reg[c] = a,
120                Instruction::Gtir(a, b, c) => reg[c] = u32::from(a > reg[b]),
121                Instruction::Gtri(a, b, c) => reg[c] = u32::from(reg[a] > b),
122                Instruction::Gtrr(a, b, c) => reg[c] = u32::from(reg[a] > reg[b]),
123                Instruction::Eqir(a, b, c) => reg[c] = u32::from(a == reg[b]),
124                Instruction::Eqri(a, b, c) => reg[c] = u32::from(reg[a] == b),
125                Instruction::Eqrr(a, b, c) => reg[c] = u32::from(reg[a] == reg[b]),
126            }
127
128            reg[self.instruction_pointer] += 1;
129        }
130    }
131
132    #[inline]
133    #[must_use]
134    pub fn instruction_pointer(&self) -> Register {
135        self.instruction_pointer
136    }
137
138    #[inline]
139    #[must_use]
140    pub fn instructions(&self) -> &[Instruction] {
141        &self.instructions
142    }
143}
144
145impl Instruction {
146    #[inline]
147    pub fn registers(self) -> impl Iterator<Item = Register> {
148        match self {
149            Instruction::Addr(r1, r2, r3)
150            | Instruction::Mulr(r1, r2, r3)
151            | Instruction::Banr(r1, r2, r3)
152            | Instruction::Borr(r1, r2, r3)
153            | Instruction::Gtrr(r1, r2, r3)
154            | Instruction::Eqrr(r1, r2, r3) => [r1, r2, r3].into_iter().take(3),
155            Instruction::Addi(r1, _, r2)
156            | Instruction::Muli(r1, _, r2)
157            | Instruction::Bani(r1, _, r2)
158            | Instruction::Bori(r1, _, r2)
159            | Instruction::Setr(r1, r2)
160            | Instruction::Gtir(_, r1, r2)
161            | Instruction::Gtri(r1, _, r2)
162            | Instruction::Eqir(_, r1, r2)
163            | Instruction::Eqri(r1, _, r2) => [r1, r2, Register::A].into_iter().take(2),
164            Instruction::Seti(_, r1) => [r1, Register::A, Register::A].into_iter().take(1),
165        }
166    }
167}