Change parse_number and parse_unit to return Results directly
This commit is contained in:
parent
54118ca879
commit
3dee08d6d4
1 changed files with 71 additions and 81 deletions
152
src/parse.rs
152
src/parse.rs
|
@ -21,12 +21,7 @@ pub fn parse(input: &str) -> Result<Vec<NonMetricQuantity>, ParseError> {
|
||||||
for token in tokenize(input) {
|
for token in tokenize(input) {
|
||||||
match (&state, token) {
|
match (&state, token) {
|
||||||
(Expect::Number, Token::Number(number)) => {
|
(Expect::Number, Token::Number(number)) => {
|
||||||
let number = match parse_number(&number) {
|
let number = parse_number(number)?;
|
||||||
Some(number) => number,
|
|
||||||
None => {
|
|
||||||
return Err(ParseError::NotValidNumber(number));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
amount = Some(number);
|
amount = Some(number);
|
||||||
state = Expect::Unit;
|
state = Expect::Unit;
|
||||||
}
|
}
|
||||||
|
@ -37,12 +32,7 @@ pub fn parse(input: &str) -> Result<Vec<NonMetricQuantity>, ParseError> {
|
||||||
unreachable!("token stream can't contain two numbers in a row");
|
unreachable!("token stream can't contain two numbers in a row");
|
||||||
}
|
}
|
||||||
(Expect::Unit, Token::Unit(unit)) => {
|
(Expect::Unit, Token::Unit(unit)) => {
|
||||||
let unit = match parse_unit(&unit) {
|
let unit = parse_unit(unit)?;
|
||||||
Some(unit) => unit,
|
|
||||||
None => {
|
|
||||||
return Err(ParseError::UnknownUnit(unit));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let quantity = NonMetricQuantity {
|
let quantity = NonMetricQuantity {
|
||||||
amount: amount.take().expect("must have read a number to be in this state"),
|
amount: amount.take().expect("must have read a number to be in this state"),
|
||||||
unit: unit,
|
unit: unit,
|
||||||
|
@ -63,51 +53,51 @@ pub fn parse(input: &str) -> Result<Vec<NonMetricQuantity>, ParseError> {
|
||||||
Ok(quantities)
|
Ok(quantities)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_number(input: &str) -> Option<f64> {
|
fn parse_number(input: String) -> Result<f64, ParseError> {
|
||||||
let no_whitespace: String = input.chars().filter(|c| !c.is_whitespace()).collect();
|
let no_whitespace: String = input.chars().filter(|c| !c.is_whitespace()).collect();
|
||||||
no_whitespace.parse().ok()
|
no_whitespace.parse().or_else(|_| Err(ParseError::NotValidNumber(input)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unit(input: &str) -> Option<NonMetric> {
|
fn parse_unit(input: String) -> Result<NonMetric, ParseError> {
|
||||||
match input {
|
match input.as_str() {
|
||||||
// Length
|
// Length
|
||||||
"inch" => Some(NonMetric::Inch),
|
"inch" => Ok(NonMetric::Inch),
|
||||||
"inches" => Some(NonMetric::Inch),
|
"inches" => Ok(NonMetric::Inch),
|
||||||
"in" => Some(NonMetric::Inch),
|
"in" => Ok(NonMetric::Inch),
|
||||||
"\"" => Some(NonMetric::Inch),
|
"\"" => Ok(NonMetric::Inch),
|
||||||
"″" => Some(NonMetric::Inch),
|
"″" => Ok(NonMetric::Inch),
|
||||||
|
|
||||||
"foot" => Some(NonMetric::Foot),
|
"foot" => Ok(NonMetric::Foot),
|
||||||
"feet" => Some(NonMetric::Foot),
|
"feet" => Ok(NonMetric::Foot),
|
||||||
"ft" => Some(NonMetric::Foot),
|
"ft" => Ok(NonMetric::Foot),
|
||||||
"'" => Some(NonMetric::Foot),
|
"'" => Ok(NonMetric::Foot),
|
||||||
"′" => Some(NonMetric::Foot),
|
"′" => Ok(NonMetric::Foot),
|
||||||
|
|
||||||
"yard" => Some(NonMetric::Yard),
|
"yard" => Ok(NonMetric::Yard),
|
||||||
"yards" => Some(NonMetric::Yard),
|
"yards" => Ok(NonMetric::Yard),
|
||||||
"yd" => Some(NonMetric::Yard),
|
"yd" => Ok(NonMetric::Yard),
|
||||||
|
|
||||||
"mile" => Some(NonMetric::Mile),
|
"mile" => Ok(NonMetric::Mile),
|
||||||
"miles" => Some(NonMetric::Mile),
|
"miles" => Ok(NonMetric::Mile),
|
||||||
"mi" => Some(NonMetric::Mile),
|
"mi" => Ok(NonMetric::Mile),
|
||||||
"m" => Some(NonMetric::Mile),
|
"m" => Ok(NonMetric::Mile),
|
||||||
|
|
||||||
// Weight
|
// Weight
|
||||||
"ounce" => Some(NonMetric::Ounce),
|
"ounce" => Ok(NonMetric::Ounce),
|
||||||
"ounces" => Some(NonMetric::Ounce),
|
"ounces" => Ok(NonMetric::Ounce),
|
||||||
"oz" => Some(NonMetric::Ounce),
|
"oz" => Ok(NonMetric::Ounce),
|
||||||
|
|
||||||
"pound" => Some(NonMetric::Pound),
|
"pound" => Ok(NonMetric::Pound),
|
||||||
"pounds" => Some(NonMetric::Pound),
|
"pounds" => Ok(NonMetric::Pound),
|
||||||
"lb" => Some(NonMetric::Pound),
|
"lb" => Ok(NonMetric::Pound),
|
||||||
"lbs" => Some(NonMetric::Pound),
|
"lbs" => Ok(NonMetric::Pound),
|
||||||
"#" => Some(NonMetric::Pound),
|
"#" => Ok(NonMetric::Pound),
|
||||||
|
|
||||||
"stone" => Some(NonMetric::Stone),
|
"stone" => Ok(NonMetric::Stone),
|
||||||
"stones" => Some(NonMetric::Stone),
|
"stones" => Ok(NonMetric::Stone),
|
||||||
"st" => Some(NonMetric::Stone),
|
"st" => Ok(NonMetric::Stone),
|
||||||
|
|
||||||
_ => None,
|
_ => Err(ParseError::UnknownUnit(input)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,56 +194,56 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn numbers() {
|
fn numbers() {
|
||||||
assert_eq!(parse_number(""), None);
|
assert_eq!(parse_number("".to_string()), Err(ParseError::NotValidNumber("".to_string())));
|
||||||
assert_eq!(parse_number("1"), Some(1.0));
|
assert_eq!(parse_number("1".to_string()), Ok(1.0));
|
||||||
assert_eq!(parse_number("1.0"), Some(1.0));
|
assert_eq!(parse_number("1.0".to_string()), Ok(1.0));
|
||||||
assert_eq!(parse_number("0.1"), Some(0.1));
|
assert_eq!(parse_number("0.1".to_string()), Ok(0.1));
|
||||||
assert_eq!(parse_number("0.1."), None);
|
assert_eq!(parse_number("0.1.".to_string()), Err(ParseError::NotValidNumber("0.1.".to_string())));
|
||||||
assert_eq!(parse_number("-10"), Some(-10.0));
|
assert_eq!(parse_number("-10".to_string()), Ok(-10.0));
|
||||||
assert_eq!(parse_number("10\t00\u{1680}000"), Some(10_00_000.0));
|
assert_eq!(parse_number("10\t00\u{1680}000".to_string()), Ok(10_00_000.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn units() {
|
fn units() {
|
||||||
// Length
|
// Length
|
||||||
assert_eq!(parse_unit("inch"), Some(NonMetric::Inch));
|
assert_eq!(parse_unit("inch".to_string()), Ok(NonMetric::Inch));
|
||||||
assert_eq!(parse_unit("inches"), Some(NonMetric::Inch));
|
assert_eq!(parse_unit("inches".to_string()), Ok(NonMetric::Inch));
|
||||||
assert_eq!(parse_unit("in"), Some(NonMetric::Inch));
|
assert_eq!(parse_unit("in".to_string()), Ok(NonMetric::Inch));
|
||||||
assert_eq!(parse_unit("\""), Some(NonMetric::Inch));
|
assert_eq!(parse_unit("\"".to_string()), Ok(NonMetric::Inch));
|
||||||
assert_eq!(parse_unit("″"), Some(NonMetric::Inch));
|
assert_eq!(parse_unit("″".to_string()), Ok(NonMetric::Inch));
|
||||||
|
|
||||||
assert_eq!(parse_unit("foot"), Some(NonMetric::Foot));
|
assert_eq!(parse_unit("foot".to_string()), Ok(NonMetric::Foot));
|
||||||
assert_eq!(parse_unit("feet"), Some(NonMetric::Foot));
|
assert_eq!(parse_unit("feet".to_string()), Ok(NonMetric::Foot));
|
||||||
assert_eq!(parse_unit("ft"), Some(NonMetric::Foot));
|
assert_eq!(parse_unit("ft".to_string()), Ok(NonMetric::Foot));
|
||||||
assert_eq!(parse_unit("'"), Some(NonMetric::Foot));
|
assert_eq!(parse_unit("'".to_string()), Ok(NonMetric::Foot));
|
||||||
assert_eq!(parse_unit("′"), Some(NonMetric::Foot));
|
assert_eq!(parse_unit("′".to_string()), Ok(NonMetric::Foot));
|
||||||
|
|
||||||
assert_eq!(parse_unit("yard"), Some(NonMetric::Yard));
|
assert_eq!(parse_unit("yard".to_string()), Ok(NonMetric::Yard));
|
||||||
assert_eq!(parse_unit("yards"), Some(NonMetric::Yard));
|
assert_eq!(parse_unit("yards".to_string()), Ok(NonMetric::Yard));
|
||||||
assert_eq!(parse_unit("yd"), Some(NonMetric::Yard));
|
assert_eq!(parse_unit("yd".to_string()), Ok(NonMetric::Yard));
|
||||||
|
|
||||||
assert_eq!(parse_unit("mile"), Some(NonMetric::Mile));
|
assert_eq!(parse_unit("mile".to_string()), Ok(NonMetric::Mile));
|
||||||
assert_eq!(parse_unit("miles"), Some(NonMetric::Mile));
|
assert_eq!(parse_unit("miles".to_string()), Ok(NonMetric::Mile));
|
||||||
assert_eq!(parse_unit("mi"), Some(NonMetric::Mile));
|
assert_eq!(parse_unit("mi".to_string()), Ok(NonMetric::Mile));
|
||||||
assert_eq!(parse_unit("m"), Some(NonMetric::Mile));
|
assert_eq!(parse_unit("m".to_string()), Ok(NonMetric::Mile));
|
||||||
|
|
||||||
// Weight
|
// Weight
|
||||||
assert_eq!(parse_unit("ounce"), Some(NonMetric::Ounce));
|
assert_eq!(parse_unit("ounce".to_string()), Ok(NonMetric::Ounce));
|
||||||
assert_eq!(parse_unit("ounces"), Some(NonMetric::Ounce));
|
assert_eq!(parse_unit("ounces".to_string()), Ok(NonMetric::Ounce));
|
||||||
assert_eq!(parse_unit("oz"), Some(NonMetric::Ounce));
|
assert_eq!(parse_unit("oz".to_string()), Ok(NonMetric::Ounce));
|
||||||
|
|
||||||
assert_eq!(parse_unit("pound"), Some(NonMetric::Pound));
|
assert_eq!(parse_unit("pound".to_string()), Ok(NonMetric::Pound));
|
||||||
assert_eq!(parse_unit("pounds"), Some(NonMetric::Pound));
|
assert_eq!(parse_unit("pounds".to_string()), Ok(NonMetric::Pound));
|
||||||
assert_eq!(parse_unit("lb"), Some(NonMetric::Pound));
|
assert_eq!(parse_unit("lb".to_string()), Ok(NonMetric::Pound));
|
||||||
assert_eq!(parse_unit("lbs"), Some(NonMetric::Pound));
|
assert_eq!(parse_unit("lbs".to_string()), Ok(NonMetric::Pound));
|
||||||
assert_eq!(parse_unit("#"), Some(NonMetric::Pound));
|
assert_eq!(parse_unit("#".to_string()), Ok(NonMetric::Pound));
|
||||||
|
|
||||||
assert_eq!(parse_unit("stone"), Some(NonMetric::Stone));
|
assert_eq!(parse_unit("stone".to_string()), Ok(NonMetric::Stone));
|
||||||
assert_eq!(parse_unit("stones"), Some(NonMetric::Stone));
|
assert_eq!(parse_unit("stones".to_string()), Ok(NonMetric::Stone));
|
||||||
assert_eq!(parse_unit("st"), Some(NonMetric::Stone));
|
assert_eq!(parse_unit("st".to_string()), Ok(NonMetric::Stone));
|
||||||
|
|
||||||
// Unknown unit
|
// Unknown unit
|
||||||
assert_eq!(parse_unit("hutenosa"), None);
|
assert_eq!(parse_unit("hutenosa".to_string()), Err(ParseError::UnknownUnit("hutenosa".to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue