stak_code/ir/
instruction.rs

1use crate::Operand;
2#[cfg(feature = "alloc")]
3use alloc::vec::Vec;
4
5/// An instruction.
6#[derive(Debug, Eq, PartialEq)]
7pub enum Instruction {
8    /// A `constant` instruction.
9    Constant(Operand),
10    /// A `get` instruction.
11    Get(Operand),
12    /// A `set` instruction.
13    Set(Operand),
14    /// An `if` instruction.
15    #[cfg(feature = "alloc")]
16    If(Vec<Instruction>),
17    /// A `nop` instruction.
18    Nop(u64),
19    /// A `call` instruction.
20    Call(u64, Operand),
21    /// A `close` instruction.
22    ///
23    /// It is used only for encoding.
24    #[cfg(feature = "alloc")]
25    Close(u64, Vec<Instruction>),
26    /// A `skip` instruction.
27    ///
28    /// It is used only for encoding.
29    Skip(u64),
30}
31
32impl Instruction {
33    /// A `constant` instruction.
34    pub const CONSTANT: u8 = 0;
35    /// A `get` instruction.
36    pub const GET: u8 = 1;
37    /// A `set` instruction.
38    pub const SET: u8 = 2;
39    /// An `if` instruction.
40    pub const IF: u8 = 3;
41    /// A `nop` instruction.
42    pub const NOP: u8 = 4;
43    /// A `call` instruction.
44    pub const CALL: u8 = 5;
45    /// A `close` instruction.
46    pub const CLOSE: u8 = 6;
47    /// A `skip` instruction.
48    pub const SKIP: u8 = 7;
49}
50
51#[cfg(feature = "alloc")]
52mod display {
53    use super::*;
54    use core::fmt::{self, Display, Formatter};
55
56    impl Instruction {
57        /// Displays instructions in a slice.
58        pub fn display_slice(instructions: &[Self]) -> impl Display + '_ {
59            DisplayInstructionList::new(instructions, 0)
60        }
61    }
62
63    struct DisplayInstruction<'a> {
64        instruction: &'a Instruction,
65        indent: usize,
66    }
67
68    impl<'a> DisplayInstruction<'a> {
69        const fn new(instruction: &'a Instruction, indent: usize) -> Self {
70            Self {
71                instruction,
72                indent,
73            }
74        }
75    }
76
77    impl<'a> Display for DisplayInstruction<'a> {
78        fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
79            let indent = self.indent + 1;
80
81            write!(formatter, "- ")?;
82
83            match self.instruction {
84                Instruction::Constant(operand) => write!(formatter, "constant {operand}"),
85                Instruction::Get(operand) => write!(formatter, "get {operand}"),
86                Instruction::Set(operand) => write!(formatter, "set {operand}"),
87                Instruction::If(instructions) => {
88                    write!(formatter, "if")?;
89                    write!(
90                        formatter,
91                        "{}",
92                        DisplayInstructionList::new(instructions, indent)
93                    )
94                }
95                Instruction::Nop(operand) => write!(formatter, "nop {operand}"),
96                Instruction::Call(arity, operand) => {
97                    write!(formatter, "call {arity} {operand}")
98                }
99                Instruction::Close(arity, instructions) => {
100                    write!(formatter, "close {arity}")?;
101                    write!(
102                        formatter,
103                        "{}",
104                        DisplayInstructionList::new(instructions, indent)
105                    )
106                }
107                Instruction::Skip(count) => write!(formatter, "skip {count}"),
108            }
109        }
110    }
111
112    struct DisplayInstructionList<'a> {
113        instructions: &'a [Instruction],
114        indent: usize,
115    }
116
117    impl<'a> DisplayInstructionList<'a> {
118        const fn new(instructions: &'a [Instruction], indent: usize) -> Self {
119            Self {
120                instructions,
121                indent,
122            }
123        }
124    }
125
126    impl<'a> Display for DisplayInstructionList<'a> {
127        fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
128            for instruction in self.instructions {
129                writeln!(formatter)?;
130
131                for _ in 0..self.indent {
132                    write!(formatter, "  ")?
133                }
134
135                write!(
136                    formatter,
137                    "{}",
138                    DisplayInstruction::new(instruction, self.indent)
139                )?;
140            }
141
142            Ok(())
143        }
144    }
145}