diff --git a/src/number_decoder.rs b/src/number_decoder.rs index ecb0903..e227a9a 100644 --- a/src/number_decoder.rs +++ b/src/number_decoder.rs @@ -2,7 +2,7 @@ use num_bigint::BigInt; use num_traits::cast::ToPrimitive; use std::ops::Range; -use lexical_core::{format as lexical_format, parse_partial_with_options, Error as LexicalError, ParseFloatOptions}; +use lexical_core::{format as lexical_format, parse_partial_with_options, ParseFloatOptions}; use crate::errors::{json_err, JsonResult}; @@ -62,17 +62,19 @@ pub struct NumberFloat; impl AbstractNumberDecoder for NumberFloat { type Output = f64; - fn decode(data: &[u8], index: usize, _first: u8) -> JsonResult<(Self::Output, usize)> { + fn decode(data: &[u8], index: usize, first: u8) -> JsonResult<(Self::Output, usize)> { let start = index; const JSON: u128 = lexical_format::JSON; let options = ParseFloatOptions::new(); match parse_partial_with_options::(&data[start..], &options) { Ok((float, index)) => Ok((float, index + start)), - Err(e) => { - // dbg!(e); - match e { - LexicalError::EmptyExponent(_) => json_err!(EofWhileParsingValue, index), - _ => json_err!(InvalidNumber, index), + Err(_) => { + // it's impossible to work out the right error from LexicalError here, so we parse again + // with NumberRange and use that error + match NumberRange::decode(data, start, first) { + Err(e) => Err(e), + // shouldn't happen + Ok(_) => json_err!(InvalidNumber, index), } } } diff --git a/src/parse.rs b/src/parse.rs index 1c7dc4b..2d33fda 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -199,36 +199,15 @@ impl<'a> Parser<'a> { } pub fn consume_true(&mut self) -> JsonResult<()> { - match self.data.get(self.index + 1..self.index + 4) { - Some(s) if s == TRUE_REST => { - self.index += 4; - Ok(()) - } - Some(_) => json_err!(ExpectedSomeIdent, self.index), - None => json_err!(EofWhileParsingValue, self.data.len()), - } + self.consume_ident(TRUE_REST) } pub fn consume_false(&mut self) -> JsonResult<()> { - match self.data.get(self.index + 1..self.index + 5) { - Some(s) if s == FALSE_REST => { - self.index += 5; - Ok(()) - } - Some(_) => json_err!(ExpectedSomeIdent, self.index), - None => json_err!(EofWhileParsingValue, self.data.len()), - } + self.consume_ident(FALSE_REST) } pub fn consume_null(&mut self) -> JsonResult<()> { - match self.data.get(self.index + 1..self.index + 4) { - Some(s) if s == NULL_REST => { - self.index += 4; - Ok(()) - } - Some(_) => json_err!(ExpectedSomeIdent, self.index), - None => json_err!(EofWhileParsingValue, self.data.len()), - } + self.consume_ident(NULL_REST) } pub fn consume_string<'s, 't, D: AbstractStringDecoder<'t>>( @@ -268,6 +247,26 @@ impl<'a> Parser<'a> { } } + fn consume_ident(&mut self, expected: [u8; SIZE]) -> JsonResult<()> { + match self.data.get(self.index + 1..self.index + SIZE + 1) { + Some(s) if s == expected => { + self.index += SIZE + 1; + Ok(()) + } + _ => { + self.index += 1; + for c in expected.iter() { + match self.data.get(self.index) { + Some(v) if v == c => self.index += 1, + Some(_) => return json_err!(ExpectedSomeIdent, self.index), + _ => break, + } + } + json_err!(EofWhileParsingValue, self.data.len()) + } + } + } + fn eat_whitespace(&mut self) -> Option { while let Some(next) = self.data.get(self.index) { match next { diff --git a/tests/main.rs b/tests/main.rs index 3da152a..a12c183 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -196,11 +196,12 @@ single_tests! { empty: err => "", "EofWhileParsingValue @ 1:0"; string_unclosed: err => r#""foobar"#, "EofWhileParsingString @ 1:7"; bad_int: err => "-", "EofWhileParsingValue @ 1:1"; - bad_true1: err => "truX", "ExpectedSomeIdent @ 1:0"; + bad_true1: err => "truX", "ExpectedSomeIdent @ 1:3"; bad_true2: err => "tru", "EofWhileParsingValue @ 1:3"; - bad_false1: err => "falsX", "ExpectedSomeIdent @ 1:0"; + bad_true3: err => "trX", "ExpectedSomeIdent @ 1:2"; + bad_false1: err => "falsX", "ExpectedSomeIdent @ 1:4"; bad_false2: err => "fals", "EofWhileParsingValue @ 1:4"; - bad_null1: err => "nulX", "ExpectedSomeIdent @ 1:0"; + bad_null1: err => "nulX", "ExpectedSomeIdent @ 1:3"; bad_null2: err => "nul", "EofWhileParsingValue @ 1:3"; object_trailing_comma: err => r#"{"foo": "bar",}"#, "TrailingComma @ 1:15"; array_trailing_comma: err => r#"[1, 2,]"#, "TrailingComma @ 1:7"; @@ -216,7 +217,9 @@ single_tests! { array_no_close: err => r#"["#, "EofWhileParsingList @ 1:1"; array_double_close: err => "[1]]", "TrailingCharacters @ 1:3"; double_zero: err => "001", "InvalidNumber @ 1:0"; - invalid_float: err => "0E", "EofWhileParsingValue @ 1:0"; + invalid_float_e_end: err => "0E", "EofWhileParsingValue @ 1:2"; + invalid_float_dot_end: err => "0.", "EofWhileParsingValue @ 1:2"; + invalid_float_bracket: err => "2E[", "InvalidNumber @ 1:2"; } #[test]