1#[cfg(not(feature = "std"))]
2use alloc::{vec, vec::Vec};
3use core::fmt::Display;
4
5use crate::hints::{Hint, PythonicHint};
6use crate::operand::{CellRef, DerefOrImmediate, ResOperand};
7
8#[cfg(test)]
9#[path = "instructions_test.rs"]
10mod test;
11
12#[derive(Debug, Eq, PartialEq, Clone)]
14pub enum InstructionBody {
15 AddAp(AddApInstruction),
16 AssertEq(AssertEqInstruction),
17 Call(CallInstruction),
18 Jnz(JnzInstruction),
19 Jump(JumpInstruction),
20 Ret(RetInstruction),
21}
22impl InstructionBody {
23 pub fn op_size(&self) -> usize {
24 match self {
26 InstructionBody::AddAp(insn) => insn.op_size(),
27 InstructionBody::AssertEq(insn) => insn.op_size(),
28 InstructionBody::Call(insn) => insn.op_size(),
29 InstructionBody::Jump(insn) => insn.op_size(),
30 InstructionBody::Jnz(insn) => insn.op_size(),
31 InstructionBody::Ret(insn) => insn.op_size(),
32 }
33 }
34}
35impl Display for InstructionBody {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 match self {
38 InstructionBody::AddAp(insn) => write!(f, "{insn}",),
39 InstructionBody::AssertEq(insn) => write!(f, "{insn}",),
40 InstructionBody::Call(insn) => write!(f, "{insn}",),
41 InstructionBody::Jnz(insn) => write!(f, "{insn}",),
42 InstructionBody::Jump(insn) => write!(f, "{insn}",),
43 InstructionBody::Ret(insn) => write!(f, "{insn}",),
44 }
45 }
46}
47
48#[derive(Debug, Eq, PartialEq, Clone)]
50pub struct Instruction {
51 pub body: InstructionBody,
52 pub inc_ap: bool,
53 pub hints: Vec<Hint>,
54}
55impl Instruction {
56 pub fn new(body: InstructionBody, inc_ap: bool) -> Self {
57 Self { body, inc_ap, hints: vec![] }
58 }
59}
60
61impl Display for Instruction {
62 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63 for hint in &self.hints {
64 let hint_str = hint.get_pythonic_hint();
65 if hint_str.starts_with('\n') {
67 writeln!(f, "%{{{hint_str}%}}")
68 } else {
69 writeln!(f, "%{{ {hint_str} %}}")
70 }?
71 }
72
73 write!(f, "{}", self.body)?;
74 if self.inc_ap {
75 write!(f, ", ap++")?
76 };
77 Ok(())
78 }
79}
80
81#[derive(Debug, Eq, PartialEq, Clone)]
83pub struct CallInstruction {
84 pub target: DerefOrImmediate,
85 pub relative: bool,
86}
87impl Display for CallInstruction {
88 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89 write!(f, "call {} {}", if self.relative { "rel" } else { "abs" }, self.target,)
90 }
91}
92impl CallInstruction {
93 pub fn op_size(&self) -> usize {
94 match &self.target {
95 DerefOrImmediate::Deref(_) => 1,
96 DerefOrImmediate::Immediate(_) => 2,
97 }
98 }
99}
100
101#[derive(Debug, Eq, PartialEq, Clone)]
103pub struct JumpInstruction {
104 pub target: DerefOrImmediate,
105 pub relative: bool,
106}
107impl JumpInstruction {
108 pub fn op_size(&self) -> usize {
109 match &self.target {
110 DerefOrImmediate::Deref(_) => 1,
111 DerefOrImmediate::Immediate(_) => 2,
112 }
113 }
114}
115impl Display for JumpInstruction {
116 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117 write!(f, "jmp {} {}", if self.relative { "rel" } else { "abs" }, self.target,)
118 }
119}
120
121#[derive(Debug, Eq, PartialEq, Clone)]
123pub struct JnzInstruction {
124 pub jump_offset: DerefOrImmediate,
125 pub condition: CellRef,
126}
127impl JnzInstruction {
128 pub fn op_size(&self) -> usize {
129 match &self.jump_offset {
130 DerefOrImmediate::Deref(_) => 1,
131 DerefOrImmediate::Immediate(_) => 2,
132 }
133 }
134}
135impl Display for JnzInstruction {
136 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137 write!(f, "jmp rel {} if {} != 0", self.jump_offset, self.condition)
138 }
139}
140
141pub fn op_size_based_on_res_operands(operand: &ResOperand) -> usize {
143 match operand {
144 ResOperand::Deref(_) => 1,
145 ResOperand::DoubleDeref(_, _) => 1,
146 ResOperand::Immediate(_) => 2,
147 ResOperand::BinOp(op) => match op.b {
148 DerefOrImmediate::Immediate(_) => 2,
149 DerefOrImmediate::Deref(_) => 1,
150 },
151 }
152}
153
154#[derive(Debug, Eq, PartialEq, Clone)]
156pub struct AssertEqInstruction {
157 pub a: CellRef,
158 pub b: ResOperand,
159}
160impl AssertEqInstruction {
161 pub fn op_size(&self) -> usize {
162 op_size_based_on_res_operands(&self.b)
163 }
164}
165impl Display for AssertEqInstruction {
166 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167 write!(f, "{} = {}", self.a, self.b)
168 }
169}
170
171#[derive(Debug, Eq, PartialEq, Clone)]
173pub struct RetInstruction {}
174impl Display for RetInstruction {
175 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176 write!(f, "ret")
177 }
178}
179
180impl RetInstruction {
181 pub fn op_size(&self) -> usize {
182 1
183 }
184}
185
186#[derive(Debug, Eq, PartialEq, Clone)]
188pub struct AddApInstruction {
189 pub operand: ResOperand,
190}
191impl AddApInstruction {
192 pub fn op_size(&self) -> usize {
193 op_size_based_on_res_operands(&self.operand)
194 }
195}
196impl Display for AddApInstruction {
197 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198 write!(f, "ap += {}", self.operand)
199 }
200}