Skip to content

Commit 595eda0

Browse files
committed
parser: error for too large frets
Fixes #9. Has about 2% performance impact. I will allow it, because it is for correctness.
1 parent d73c54c commit 595eda0

File tree

6 files changed

+42
-14
lines changed

6 files changed

+42
-14
lines changed

src/backend/errors/backend_error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ impl BackendError {
8181
relevant_lines: line as usize..=line as usize,
8282
}
8383
}
84+
pub fn large_fret(line: u32, char: u32) -> Self {
85+
Self {
86+
main_location: ErrorLocation::LineAndChar(line, char),
87+
relevant_lines: line as usize..=line as usize,
88+
kind: BackendErrorKind::FretTooLarge,
89+
}
90+
}
8491
}
8592

8693
impl From<std::io::Error> for BackendError {

src/backend/errors/backend_error_kind.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub enum BackendErrorKind {
1111
BendOnInvalid,
1212
BothSlotsMultiChar,
1313
MultiBothSlotsFilled,
14+
FretTooLarge,
1415
}
1516

1617
impl BackendErrorKind {
@@ -57,7 +58,8 @@ In this position, you may have:
5758
- a rest
5859
- a single char element aligned left or right
5960
- another multichar element of the same cardinality"#.into()
60-
)
61+
),
62+
BackendErrorKind::FretTooLarge => ("Too large fret".to_string(), "The maximum allowed fret is 99.".to_string()),
6163
}
6264
}
6365
}

src/backend/fixup/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ impl Backend for FixupBackend {
104104
BackendErrorKind::InvalidStringName => {}
105105
BackendErrorKind::EmptyScore => {}
106106
BackendErrorKind::BothSlotsMultiChar => {} // todo: fix BothSlotsMultichar errors
107+
BackendErrorKind::FretTooLarge => {} // todo: fix FretTooLarge errors (add
108+
// space between)
107109
BackendErrorKind::MultiBothSlotsFilled => {
108110
let Some((line_idx, char_idx)) = err
109111
.main_location

src/parser/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ pub fn string_name() -> impl Fn(&str) -> Result<(&str, char), &str> {
2121
fn numeric(s: &str) -> Result<(&str, u8), &str> {
2222
let bytes = s.as_bytes();
2323
let mut i = 0;
24-
let mut sum = 0;
24+
let mut sum: u8 = 0;
2525
while i < bytes.len() && bytes[i].is_ascii_digit() {
26-
sum *= 10;
26+
sum = sum.checked_mul(10).ok_or(s)?;
2727
sum += bytes[i] - b'0';
2828
i += 1;
2929
}

src/parser/parser.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use super::{
22
string_name,
33
tab_element::{self, tab_element3, TabElement3},
44
};
5-
use crate::{backend::errors::backend_error::BackendError, debugln, traceln};
5+
use crate::{
6+
backend::errors::backend_error::BackendError, debugln, parser::tab_element::TabElementError,
7+
traceln,
8+
};
69
use std::ops::RangeInclusive;
710

811
pub fn line_is_valid(line: &str) -> bool {
@@ -136,13 +139,23 @@ pub fn parse(lines: &[String]) -> ParseResult {
136139
}
137140

138141
let len_before = part[s].len();
139-
let Ok((res, te)) = tab_element3(part[s]) else {
140-
let (line, char) =
141-
source_location_while_parsing(&r, part_first_line as u32, s as u32);
142-
let invalid_src = part[s].chars().next().unwrap_or('\0'); // TODO: do not use null byte here
143-
r.error = Some(BackendError::parse3_invalid_character(line, char, invalid_src));
144-
return r;
142+
let (res, te) = match tab_element3(part[s]) {
143+
Ok(x) => x,
144+
Err((_, err)) => {
145+
let (line, char) =
146+
source_location_while_parsing(&r, part_first_line as u32, s as u32);
147+
if let Some(TabElementError::FretTooLarge) = err {
148+
r.error = Some(BackendError::large_fret(line, char));
149+
} else {
150+
let invalid_src = part[s].chars().next().unwrap_or('\0'); // TODO: do not use null byte here
151+
let err =
152+
BackendError::parse3_invalid_character(line, char, invalid_src);
153+
r.error = Some(err);
154+
}
155+
return r;
156+
}
145157
};
158+
146159
let tab_element_len = len_before - res.len();
147160
is_multichar |= tab_element_len > 1;
148161
is_multi_on[s] = tab_element_len > 1;

src/parser/tab_element.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::parser::numeric;
1+
use crate::{backend::errors::backend_error::BackendError, parser::numeric, traceln};
22
use std::cmp::max;
33

44
#[derive(Debug, PartialEq, Clone)]
@@ -14,14 +14,18 @@ pub enum TabElement3 {
1414
Vibrato,
1515
}
1616

17+
#[derive(Debug)]
18+
pub enum TabElementError {
19+
FretTooLarge,
20+
}
1721
#[inline(always)]
18-
pub fn tab_element3(s: &str) -> Result<(&str, TabElement3), &str> {
22+
pub fn tab_element3(s: &str) -> Result<(&str, TabElement3), (&str, Option<TabElementError>)> {
1923
let bytes = s.as_bytes();
2024
match bytes.first() {
2125
Some(b'-') => Ok((&s[1..], TabElement3::Rest)),
2226
Some(b'x') => Ok((&s[1..], TabElement3::DeadNote)),
2327
Some(48..=58) => {
24-
let (res, num) = numeric(s)?;
28+
let (res, num) = numeric(s).map_err(|s| (s, Some(TabElementError::FretTooLarge)))?;
2529
Ok((res, TabElement3::Fret(num)))
2630
}
2731
Some(b'b') => Ok((&s[1..], TabElement3::Bend)),
@@ -30,7 +34,7 @@ pub fn tab_element3(s: &str) -> Result<(&str, TabElement3), &str> {
3034
Some(b'r') => Ok((&s[1..], TabElement3::Release)),
3135
Some(b'/') | Some(b'\\') => Ok((&s[1..], TabElement3::Slide)),
3236
Some(b'~') => Ok((&s[1..], TabElement3::Vibrato)),
33-
Some(_) | None => Err(s),
37+
Some(_) | None => Err((s, None)),
3438
}
3539
}
3640
impl TabElement3 {

0 commit comments

Comments
 (0)