Fix flatten_group

This commit is contained in:
Denis Redozubov 2023-06-15 20:25:54 +04:00
parent 58bb2ba87c
commit 9ffa47977e
1 changed files with 100 additions and 72 deletions

View File

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