1use nom::{
6 self,
7 bytes::complete::{tag, take_until, take_while1, take_while_m_n},
8 multi::many_m_n,
9 AsChar,
10};
11
12use nom::error::{Error, ErrorKind};
13
14use std::{convert::TryFrom, num::ParseIntError};
15
16use crate::error::InstructionReadError;
17
18use zkevm_opcode_defs::{ImmMemHandlerFlags, RegOrImmFlags};
19
20#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21pub enum FullOperand {
22 Full(GenericOperand),
24 Register(RegisterOperand),
26 Constant(ConstantOperand),
28 GlobalVariable(GlobalVariable),
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
36pub struct ConstantOperand {
37 pub label: String,
39 pub register: RegisterOperand,
41 pub immediate: u64,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Hash)]
46pub struct GlobalVariable {
47 pub label: String,
49 pub register: RegisterOperand,
51 pub immediate: u64,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub struct GenericOperand {
60 pub r#type: ImmMemHandlerFlags,
61 pub immediate: u64,
63 pub register: RegisterOperand,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68pub enum RegisterOperand {
69 Null,
71 Register(u8),
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
79pub struct NonMemoryOperand {
80 pub r#type: RegOrImmFlags,
81 pub immediate: u64,
83 pub register: RegisterOperand,
85}
86
87impl NonMemoryOperand {
88 pub fn as_register_operand(
89 self,
90 index: usize,
91 ) -> Result<RegisterOperand, InstructionReadError> {
92 match self.r#type {
93 RegOrImmFlags::UseRegOnly => Ok(self.register),
94 RegOrImmFlags::UseImm16Only => {
95 Err(InstructionReadError::InvalidRegImmInPlaceOfReg { index, found: self })
96 }
97 }
98 }
99}
100
101fn is_imm(input: &str) -> (&str, bool) {
102 let t = tag("#")(input);
103 match t {
104 Ok((input, _)) => (input, true),
105 Err(nom::Err::Error(Error {
106 input,
107 code: ErrorKind::Tag,
108 })) => (input, false),
109 _ => {
110 unreachable!()
111 }
112 }
113}
114
115fn is_register(input: &str) -> (&str, bool, &str) {
116 let mut reg_parser = nom::sequence::tuple::<_, _, nom::error::Error<_>, _>((
117 nom::character::complete::space0,
118 tag("r"),
119 take_while_m_n(1, 2, |el: char| el.is_ascii_digit()),
120 ));
121
122 match reg_parser(input) {
123 Ok((rest, result)) => {
124 let reg_raw = result.2;
125
126 (rest, true, reg_raw)
127 }
128 _ => (input, false, ""),
129 }
130}
131
132fn is_label(input: &str) -> (&str, bool, &str) {
133 let label_name_parser =
134 take_while1(|c: char| c.is_alphanum() || (c.is_ascii() && (c as u8) == b"_"[0]));
135 let mut label_parser = nom::sequence::tuple::<_, _, nom::error::Error<_>, _>((
136 nom::character::complete::space0,
137 tag("."),
138 label_name_parser,
139 ));
140
141 let label_name_parser =
142 take_while1(|c: char| c.is_alphanum() || (c.is_ascii() && (c as u8) == b"_"[0]));
143 let mut pseudo_label_parser = nom::sequence::tuple::<_, _, nom::error::Error<_>, _>((
144 nom::character::complete::space0,
145 tag("."),
146 label_name_parser,
147 nom::sequence::pair(tag("["), take_until("]")),
148 ));
149
150 match pseudo_label_parser(input) {
153 Ok(_) => (input, false, ""),
154 _ => match label_parser(input) {
155 Ok((rest, result)) => {
156 let label_raw = result.2;
157
158 (rest, true, label_raw)
159 }
160 _ => (input, false, ""),
161 },
162 }
163}
164
165fn has_tag<'a>(input: &'a str, tag: &str) -> (bool, &'a str) {
166 match nom::bytes::complete::tag::<_, _, nom::error::Error<_>>(tag)(input) {
167 Ok((rest, _)) => (true, rest),
168 Err(nom::Err::Error(Error {
169 input,
170 code: ErrorKind::Tag,
171 })) => (false, input),
172 _ => {
173 unreachable!()
174 }
175 }
176}
177
178fn try_memory_offset<'a>(
179 input: &'a str,
180) -> Result<(&'a str, Vec<&'a str>, Vec<&'a str>, Vec<&'a str>), ()> {
181 let reg_parser = nom::sequence::tuple::<_, _, nom::error::Error<_>, _>((
182 nom::character::complete::space0,
183 tag("r"),
184 take_while_m_n(1, 2, |el: char| el.is_ascii_digit()),
185 ));
186
187 let sign_parser = nom::sequence::tuple((
188 nom::character::complete::space0,
189 many_m_n(0, 1, nom::branch::alt((tag("+"), tag("-")))),
190 nom::character::complete::space0,
191 ));
192
193 let mut parser = nom::sequence::tuple((
194 many_m_n(0, 1, reg_parser),
195 nom::character::complete::space0,
196 sign_parser,
197 ));
198
199 match parser(input) {
200 Ok((rest, result)) => {
201 let (reg_parsing, _, sign_parsing) = result;
202 let reg_may_be: Vec<_> = reg_parsing.into_iter().map(|el| el.2).collect();
203 let sign_may_be = sign_parsing.1;
204
205 if rest.is_empty() {
206 return Ok((rest, reg_may_be, sign_may_be, vec![]));
207 }
208
209 match many_m_n::<_, _, nom::error::Error<_>, _>(
211 0,
212 1,
213 nom::character::complete::alphanumeric0,
214 )(rest)
215 {
216 Ok((rest, result)) => Ok((rest, reg_may_be, sign_may_be, result)),
217 Err(nom::Err::Error(Error { input, code })) => {
218 dbg!(input);
219 dbg!(code);
220 Err(())
221 }
222 _ => Err(()),
223 }
224 }
225 _ => Err(()),
226 }
227}
228
229fn try_immediate<'a>(input: &'a str) -> Result<(&'a str, u64), ParseIntError> {
230 let (has_prefix, input) = has_tag(input, "0x");
231 if has_prefix {
232 match u64::from_str_radix(input, 16) {
233 Ok(imm) => Ok(("", imm)),
234 Err(e) => Err(e),
235 }
236 } else {
237 let (has_prefix, input) = has_tag(input, "0b");
238 if has_prefix {
239 match u64::from_str_radix(input, 2) {
240 Ok(imm) => Ok(("", imm)),
241 Err(e) => Err(e),
242 }
243 } else {
244 match u64::from_str_radix(input, 10) {
245 Ok(imm) => Ok(("", imm)),
246 Err(e) => Err(e),
247 }
248 }
249 }
250}
251
252impl FullOperand {
253 pub fn as_register_operand(
254 self,
255 index: usize,
256 ) -> Result<RegisterOperand, InstructionReadError> {
257 match self {
258 FullOperand::Register(reg) => Ok(reg),
259 other => Err(InstructionReadError::InvalidOperandForRegLocation {
260 index,
261 found: other,
262 }),
263 }
264 }
265
266 pub fn as_non_memory_operand(
267 self,
268 index: usize,
269 ) -> Result<NonMemoryOperand, InstructionReadError> {
270 match self {
271 FullOperand::Full(operand) => Ok(operand.as_non_memory_operand()),
272 other => Err(InstructionReadError::InvalidOperandForRegImmLocation {
273 index,
274 found: other,
275 }),
276 }
277 }
278
279 pub fn as_generic_operand(self, index: usize) -> Result<GenericOperand, InstructionReadError> {
280 match self {
281 FullOperand::Full(operand) => Ok(operand),
282 other => Err(InstructionReadError::InvalidOperandForGenericLocation {
283 index,
284 found: other,
285 }),
286 }
287 }
288
289 pub fn as_constant_operand(
290 self,
291 index: usize,
292 ) -> Result<ConstantOperand, InstructionReadError> {
293 match self {
294 FullOperand::Constant(operand) => Ok(operand),
295 other => Err(InstructionReadError::InvalidOperandForLabelLocation {
296 index,
297 found: other,
298 }),
299 }
300 }
301
302 pub fn as_global_variable(self, index: usize) -> Result<GlobalVariable, InstructionReadError> {
303 match self {
304 FullOperand::GlobalVariable(operand) => Ok(operand),
305 other => Err(InstructionReadError::InvalidOperandForLabelLocation {
306 index,
307 found: other,
308 }),
309 }
310 }
311
312 pub fn as_immediate(self, index: usize) -> Result<u64, InstructionReadError> {
313 match self {
314 FullOperand::Full(GenericOperand {
315 r#type: ImmMemHandlerFlags::UseImm16Only,
316 immediate: imm,
317 register: RegisterOperand::Null,
318 }) => Ok(imm),
319 other => Err(InstructionReadError::InvalidArgument {
320 index,
321 expected: "label or immediate",
322 found: format!("{:?}", other),
323 }),
324 }
325 }
326}
327
328impl GenericOperand {
329 pub fn as_word_offset_into_code_page(self) -> u64 {
330 let GenericOperand {
331 r#type,
332 immediate,
333 register,
334 } = self;
335 match register {
336 RegisterOperand::Null => {}
337 _ => {
338 panic!("Invalid linking result")
339 }
340 }
341 match r#type {
342 ImmMemHandlerFlags::UseCodePage => immediate,
343 _ => {
344 panic!("Invalid linking result")
345 }
346 }
347 }
348
349 pub fn as_pc_offset(self) -> u64 {
350 let GenericOperand {
351 r#type,
352 immediate,
353 register,
354 } = self;
355 match register {
356 RegisterOperand::Null => {}
357 _ => {
358 panic!("Invalid linking result")
359 }
360 }
361 match r#type {
362 ImmMemHandlerFlags::UseImm16Only => immediate,
363 _ => {
364 panic!("Invalid linking result")
365 }
366 }
367 }
368
369 pub fn as_non_memory_operand(self) -> NonMemoryOperand {
370 match self.r#type {
371 ImmMemHandlerFlags::UseRegOnly => {
372 assert!(self.immediate == 0);
373 NonMemoryOperand {
374 register: self.register,
375 r#type: RegOrImmFlags::UseRegOnly,
376 immediate: 0,
377 }
378 }
379 ImmMemHandlerFlags::UseImm16Only => {
380 match self.register {
381 RegisterOperand::Null => {}
382 _ => {
383 panic!("Register must be zero")
384 }
385 }
386 NonMemoryOperand {
387 register: self.register,
388 r#type: RegOrImmFlags::UseImm16Only,
389 immediate: self.immediate,
390 }
391 }
392 _ => {
393 panic!("Invalid reg/imm operand")
394 }
395 }
396 }
397}
398
399impl RegisterOperand {
400 pub fn is_void(&self) -> bool {
404 matches!(self, Self::Null)
405 }
406}
407
408impl TryFrom<&str> for RegisterOperand {
409 type Error = InstructionReadError;
410
411 fn try_from(input: &str) -> Result<Self, Self::Error> {
412 let index: u8 = input
413 .parse()
414 .map_err(|e| InstructionReadError::InvalidNumber(input.to_owned(), e))?;
415 if index == 0 {
416 return Ok(Self::Null);
417 }
418 if index as usize > zkevm_opcode_defs::REGISTERS_COUNT {
419 return Err(InstructionReadError::UnknownRegister(input.to_owned()));
420 }
421
422 Ok(Self::Register(index))
423 }
424}