Skip to main content

bloqade_lanes_bytecode_core/isa/
parse_helpers.rs

1//! Field-level `#[parse_with]` helpers for [`super::Instruction`].
2//!
3//! The `.sst` text format writes location/lane/zone constants as `0x`-prefixed
4//! hexadecimal; vihaco's built-in integer parsers are decimal only, so these
5//! helpers parse the hex operands.
6
7use chumsky::error::Simple;
8use chumsky::extra;
9use chumsky::prelude::*;
10
11type E<'src> = extra::Err<Simple<'src, char>>;
12
13/// `0x` followed by one or more ASCII hex digits, collected as a `String`.
14fn hex_digits<'src>() -> impl Parser<'src, &'src str, String, E<'src>> {
15    just("0x").ignore_then(
16        any()
17            .filter(|c: &char| c.is_ascii_hexdigit())
18            .repeated()
19            .at_least(1)
20            .collect::<String>(),
21    )
22}
23
24/// Parse a `0x`-prefixed hexadecimal [`u64`] (`const_loc`, `const_lane`).
25pub fn hex_u64<'src>() -> impl Parser<'src, &'src str, u64, E<'src>> {
26    hex_digits().try_map(|s, span| u64::from_str_radix(&s, 16).map_err(|_| Simple::new(None, span)))
27}
28
29/// Parse a `0x`-prefixed hexadecimal [`u32`] (`const_zone`).
30pub fn hex_u32<'src>() -> impl Parser<'src, &'src str, u32, E<'src>> {
31    hex_digits().try_map(|s, span| u32::from_str_radix(&s, 16).map_err(|_| Simple::new(None, span)))
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn hex_u64_parses_full_range() {
40        assert_eq!(hex_u64().parse("0x0").into_result().unwrap(), 0);
41        assert_eq!(
42            hex_u64().parse("0xffffffffffffffff").into_result().unwrap(),
43            u64::MAX
44        );
45    }
46
47    #[test]
48    fn hex_u64_rejects_overflow() {
49        // 17 hex digits exceed u64, so `from_str_radix` fails and the parser
50        // surfaces an error rather than silently truncating.
51        assert!(
52            hex_u64()
53                .parse("0x1ffffffffffffffff")
54                .into_result()
55                .is_err()
56        );
57    }
58
59    #[test]
60    fn hex_u32_parses_and_rejects_overflow() {
61        assert_eq!(
62            hex_u32().parse("0xdeadbeef").into_result().unwrap(),
63            0xdead_beef
64        );
65        // 9 hex digits exceed u32.
66        assert!(hex_u32().parse("0x1ffffffff").into_result().is_err());
67    }
68
69    #[test]
70    fn hex_requires_prefix_and_digits() {
71        // Missing `0x` prefix, and a lone prefix with no digits, both fail.
72        assert!(hex_u64().parse("1234").into_result().is_err());
73        assert!(hex_u64().parse("0x").into_result().is_err());
74    }
75}