Handle hex or decimal digits in #WAVE macro.

Now with tests!
This commit is contained in:
Lyle Mantooth 2024-02-04 23:40:19 -05:00
parent 99eb9f048f
commit 3018db7dd1
Signed by: IslandUsurper
GPG key ID: 6DB52EAE123A5789

View file

@ -1,14 +1,16 @@
use nom::{
branch::alt,
bytes::complete::tag_no_case,
character::complete::{hex_digit1, line_ending, not_line_ending, space1},
combinator::{map_parser, map_res, opt},
character::complete::{digit1, hex_digit1, line_ending, not_line_ending, space1},
combinator::{map_parser, map_res, opt, success, value},
error::{Error, ErrorKind},
multi::fold_many0,
sequence::{preceded, separated_pair, terminated},
multi::fold_many1,
sequence::{preceded, separated_pair, terminated, tuple},
IResult,
};
#[derive(Default)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct InstrumentSet([u8; 32]);
impl InstrumentSet {
@ -20,10 +22,10 @@ impl InstrumentSet {
}
fn parse<'i>(input: &'i str) -> IResult<&'i str, Self> {
fold_many0(
fold_many1(
terminated(
opt(preceded(
tag_no_case("#WAVE"),
tag_no_case("#WAVE "),
map_parser(not_line_ending, wave_numbers),
)),
line_ending,
@ -31,7 +33,7 @@ impl InstrumentSet {
Self::default,
|mut set, bytes: Option<(usize, u8)>| match bytes {
Some((slot, sample)) => {
let pos = slot - 0x20;
let pos = (slot - 0x20) * 2;
set.0[pos] = sample;
set
}
@ -41,18 +43,55 @@ impl InstrumentSet {
}
}
fn hexordecimal(input: &str) -> IResult<&str, (u32, &str)> {
alt((
tuple((value(16, tag_no_case("0x")), hex_digit1)),
tuple((success(10), digit1)),
))(input)
}
fn wave_numbers(input: &str) -> IResult<&str, (usize, u8)> {
separated_pair(
map_res(hex_digit1, |s: &str| {
s.parse::<usize>().map_err(|_| nom::error::make_error::<&str, Error<&str>>(s, ErrorKind::HexDigit)).and_then(|n| {
if (0x20..0x30).contains(&n) {
Ok(n)
} else {
Err(nom::error::make_error(s, ErrorKind::MapRes))
}
})
map_res(hexordecimal, |(radix, s)| {
usize::from_str_radix(s, radix)
.map_err(|_| nom::error::make_error::<&str, Error<&str>>(s, ErrorKind::HexDigit))
.and_then(|n| {
if (0x20..0x30).contains(&n) {
Ok(n)
} else {
Err(nom::error::make_error(s, ErrorKind::MapRes))
}
})
}),
space1,
map_res(hex_digit1, |s: &str| s.parse::<u8>()),
map_res(hexordecimal, |(radix, s)| {
u8::from_str_radix(s, radix)
}),
)(input)
}
#[cfg(test)]
mod test {
use super::InstrumentSet;
#[test]
fn parse_waves() {
let input = "
#WAVE 0x20 0xA5 flute
#WAVE 0x21 0x95 clari
#WAVE 0x22 0x65 strings
#WAVE 0x23 0x63 ostrings
#WAVE 0x24 0x34 guitar
#WAVE 0x25 0x53 fbass
";
assert_eq!(
InstrumentSet::generate(input),
InstrumentSet([
0xa5, 0x00, 0x95, 0x00, 0x65, 0x00, 0x63, 0x00, 0x34, 0x00, 0x53, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
])
);
}
}