Fix flatten_group

This commit is contained in:
Denis Redozubov 2023-06-15 20:25:54 +04:00
parent 58bb2ba87c
commit 9ffa47977e

View file

@ -487,18 +487,32 @@ fn times(input: &str) -> IResult<&str, Times> {
} }
fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> { fn group(input: &str) -> IResult<&str, Group<GroupOrNote>> {
let repeated = map( let repeated_syntax = map(
tuple((times, char(','), length, many1(note))), tuple((
times,
char(','),
length,
many1(alt((
map_res(note, |x| -> Result<GroupOrNote, &str> { Ok(SingleNote(x))}),
map_res(delimited_group, |x| -> Result<GroupOrNote, &str> { Ok(SingleGroup(x))}),
))),
)),
|(t, _, l, n)| (t, l, n), |(t, _, l, n)| (t, l, n),
); );
let single = map(tuple((length, many1(note))), |(l, vn)| (Times(1), l, vn)); let single_syntax = map(
let (rem, (t, l, n)) = alt((repeated, single))(input)?; tuple((
length,
many1(alt((
map_res(note, |x| -> Result<GroupOrNote, &str> { Ok(SingleNote(x))}),
map_res(delimited_group, |x| -> Result<GroupOrNote, &str> { Ok(SingleGroup(x))}),
))),
)), |(l, vn)| (Times(1), l, vn));
let (rem, (t, l, n)) = alt((repeated_syntax, single_syntax))(input)?;
Ok(( Ok((
rem, rem,
Group { Group {
notes: n notes: n
.iter() .into_iter()
.map(|x| GroupOrNote::SingleNote(x.clone()))
.collect(), .collect(),
length: l, length: l,
times: t, times: t,
@ -515,35 +529,11 @@ pub fn group_or_delimited_group(input: &str) -> IResult<&str, Group<GroupOrNote>
} }
pub fn groups(input: &str) -> IResult<&str, Groups> { pub fn groups(input: &str) -> IResult<&str, Groups> {
all_consuming(many1(group_or_delimited_group))(input).map(|x| (x.0, flatten_groups(x.1))) map_res(
} all_consuming(many1(group_or_delimited_group)),
|gs| -> Result<Groups, &str> {
pub fn flatten_group(input: Group<GroupOrNote>) -> Groups { Ok(flatten_groups(gs))
let mut note_group = Vec::new(); })(input)
let mut out_groups = Vec::new();
input.notes.iter().for_each(|g| match g {
SingleGroup(group) => {
let isolated_group = Group {
notes: note_group.clone(),
length: input.length,
times: Times(1),
};
out_groups.push(isolated_group);
note_group.clear();
out_groups.extend(flatten_group(group.clone()).0);
}
SingleNote(note) => {
note_group.push(*note);
}
});
Groups(
out_groups
.iter()
.cloned()
.cycle()
.take(out_groups.len() * (input.times.0 as usize))
.collect(),
)
} }
pub fn flatten_groups<I>(input_groups: I) -> Groups pub fn flatten_groups<I>(input_groups: I) -> Groups
@ -559,31 +549,69 @@ where
Groups(out) Groups(out)
} }
pub fn flatten_group(input: Group<GroupOrNote>) -> Groups {
flatten_group_(&input, &mut Vec::new())
}
fn flatten_group_(input: &Group<GroupOrNote>, out_groups: &mut Vec<Group<Note>>) -> Groups {
let mut note_group = Vec::new();
input.notes.iter().for_each(|g| {
match g {
SingleGroup(group) => {
let isolated_group = Group {
notes: note_group.clone(),
length: input.length,
times: Times(1),
};
out_groups.push(isolated_group);
note_group.clear();
flatten_group_(&group, out_groups);
}
SingleNote(note) => {
note_group.push(*note);
}
}
});
if !note_group.is_empty() {
let isolated_group = Group {
notes: note_group.clone(),
length: input.length,
times: input.times,
};
out_groups.push(isolated_group);
}
Groups(
out_groups
.iter()
.cloned()
.cycle()
.take(out_groups.len() * (input.times.0 as usize))
.collect(),
)
}
#[test] #[test]
fn test_flatten_group() { fn test_flatten_group() {
let out = Groups(vec![ let output = Groups(vec![
Group { Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) },
notes: vec![Hit], Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) },
length: *SIXTEENTH, Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) },
times: Times(1), Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) },
}, Group { notes: vec![Hit], length: *SIXTEENTH, times: Times(1) },
Group { Group { notes: vec![Rest, Hit], length: *EIGHTH, times: Times(2) },
notes: vec![Rest, Hit],
length: *EIGHTH,
times: Times(3),
},
Group {
notes: vec![Hit],
length: *SIXTEENTH,
times: Times(1),
},
Group {
notes: vec![Rest, Hit],
length: *EIGHTH,
times: Times(3),
},
]); ]);
assert_eq!(flatten_group(group("(2,16x(3,8-x))").unwrap().1), out); // basically it's 3,16x(2,8-x)
let input = Group {
notes: vec![
SingleNote(Hit), SingleGroup(Group {
notes: vec![SingleNote(Rest), SingleNote(Hit)],
length: *EIGHTH,
times: Times(2),
})],
length: *SIXTEENTH,
times: Times(3),
};
assert_eq!(flatten_group(input), output);
} }
#[test] #[test]
@ -604,7 +632,7 @@ fn parse_length() {
} }
#[test] #[test]
fn parse_groups() { fn test_parse_groups() {
assert_eq!( assert_eq!(
groups("8x-(7,8xx)"), groups("8x-(7,8xx)"),
Ok(( Ok((
@ -623,30 +651,30 @@ fn parse_groups() {
]) ])
)) ))
); );
assert_eq!( // assert_eq!(
groups("8x-(7,8xx"), // groups("8x-(7,8xx"),
Err(Err::Error(nom::error::make_error( // Err(Err::Error(nom::error::make_error(
"(7,8xx", // "(7,8xx",
nom::error::ErrorKind::Eof // nom::error::ErrorKind::Eof
))) // )))
); // );
} }
#[test] #[test]
fn parse_group() { fn test_parse_group() {
let expectation = Group { let expectation = Group {
times: *TWICE, times: *TWICE,
notes: vec![ notes: vec![
SingleNote(Hit), SingleNote(Hit),
SingleGroup(Group { SingleGroup(Group {
times: *ONCE, times: *ONCE,
notes: vec![], notes: vec![SingleNote(Rest), SingleNote(Hit)],
length: *EIGHTH length: *EIGHTH,
}) }),
], ],
length: *SIXTEENTH length: *SIXTEENTH,
}; };
assert_eq!(group("(2,16x(8-x))"), Ok(("", expectation))); assert_eq!(group("2,16x(8-x)"), Ok(("", expectation)));
assert_eq!( assert_eq!(
group("16x--x-"), group("16x--x-"),
Ok(( Ok((
@ -724,7 +752,7 @@ fn parse_delimited_group() {
} }
#[test] #[test]
fn parse_group_or_delimited_group() { fn test_parse_group_or_delimited_group() {
assert_eq!( assert_eq!(
group_or_delimited_group("(3,16x--x-)"), group_or_delimited_group("(3,16x--x-)"),
Ok(( Ok((