1use crate::Arguments;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5pub enum ArgumentError {
6 #[error(
7 "argument index {index} is out of range: {value} (expected between {start} and {end})"
8 )]
9 ArgOutOfRangeUnsigned { index: usize, value: u32, start: u32, end: u32 },
10 #[error(
11 "argument index {index} is out of range: {value} (expected between {start} and {end})"
12 )]
13 ArgOutOfRangeSigned { index: usize, value: i32, start: i32, end: i32 },
14 #[error("unexpected number of arguments: {value} (expected at most {expected})")]
15 ArgCount { value: usize, expected: usize },
16 #[error("unknown instruction mnemonic")]
17 UnknownMnemonic,
18}
19
20#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
21pub enum Argument {
22 #[default]
23 None,
24 Unsigned(u32),
25 Signed(i32),
26}
27
28pub const fn parse_unsigned(
29 args: &Arguments,
30 index: usize,
31 start: u32,
32 end: u32,
33) -> Result<u32, ArgumentError> {
34 match args[index] {
35 Argument::Unsigned(value) => {
36 if value >= start && value <= end {
37 Ok(value)
38 } else {
39 Err(ArgumentError::ArgOutOfRangeUnsigned { index, value, start, end })
40 }
41 }
42 Argument::Signed(value) => {
43 if value >= start as i32 && value <= end as i32 {
44 Ok(value as u32)
45 } else {
46 Err(ArgumentError::ArgOutOfRangeUnsigned { index, value: value as u32, start, end })
47 }
48 }
49 Argument::None => Err(ArgumentError::ArgCount { value: index, expected: index + 1 }),
50 }
51}
52
53pub const fn parse_signed(
54 args: &Arguments,
55 index: usize,
56 start: i32,
57 end: i32,
58) -> Result<i32, ArgumentError> {
59 match args[index] {
60 Argument::Unsigned(value) => {
61 if (start < 0 || value >= start as u32) && value <= end as u32 {
62 Ok(value as i32)
63 } else {
64 Err(ArgumentError::ArgOutOfRangeSigned { index, value: value as i32, start, end })
65 }
66 }
67 Argument::Signed(value) => {
68 if value >= start && value <= end {
69 Ok(value)
70 } else {
71 Err(ArgumentError::ArgOutOfRangeSigned { index, value, start, end })
72 }
73 }
74 Argument::None => Err(ArgumentError::ArgCount { value: index, expected: index + 1 }),
75 }
76}
77
78pub const fn arg_count(args: &Arguments) -> usize {
79 let mut i = 0;
80 while i < args.len() && !matches!(args[i], Argument::None) {
81 i += 1;
82 }
83 i
84}
85
86pub const fn check_arg_count(args: &Arguments, expected: usize) -> Result<(), ArgumentError> {
87 let value = arg_count(args);
88 if value == expected {
89 Ok(())
90 } else {
91 Err(ArgumentError::ArgCount { value, expected })
92 }
93}