From c74293f7a87cea3ce60a4df1c905501d4b749067 Mon Sep 17 00:00:00 2001 From: Alex Tokarev Date: Sun, 11 Oct 2020 20:30:55 +0300 Subject: Improve error message when parsing unquoted string (#385) * Improve error message when parsing unquoted string * Remove conversion to lowercase in parse_keylike() Converting keys to lowercase goes against TOML specification for floats. * Change error message for unquoted string --- src/de.rs | 25 ++++++++++++++++++++++--- test-suite/tests/datetime.rs | 6 +++--- test-suite/tests/invalid.rs | 4 ++-- test-suite/tests/parser.rs | 19 ++++++++++++++----- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/de.rs b/src/de.rs index 6c18ae3..6411293 100644 --- a/src/de.rs +++ b/src/de.rs @@ -191,6 +191,9 @@ enum ErrorKind { available: &'static [&'static str], }, + /// Unquoted string was found when quoted one was expected + UnquotedString, + #[doc(hidden)] __Nonexhaustive, } @@ -1428,7 +1431,7 @@ impl<'a> Deserializer<'a> { start, end, }, - Some((span, Token::Keylike(key))) => self.number_or_date(span, key)?, + Some((span, Token::Keylike(key))) => self.parse_keylike(at, span, key)?, Some((span, Token::Plus)) => self.number_leading_plus(span)?, Some((Span { start, .. }, Token::LeftBrace)) => { self.inline_table().map(|(Span { end, .. }, table)| Value { @@ -1451,13 +1454,25 @@ impl<'a> Deserializer<'a> { expected: "a value", found: token.1.describe(), }, - )) + )); } None => return Err(self.eof()), }; Ok(value) } + fn parse_keylike(&mut self, at: usize, span: Span, key: &'a str) -> Result, Error> { + if key == "inf" || key == "nan" { + return self.number_or_date(span, key); + } + + let first_char = key.chars().next().expect("key should not be empty here"); + match first_char { + '-' | '0'..='9' => self.number_or_date(span, key), + _ => Err(self.error(at, ErrorKind::UnquotedString)), + } + } + fn number_or_date(&mut self, span: Span, s: &'a str) -> Result, Error> { if s.contains('T') || s.contains('t') @@ -2076,7 +2091,7 @@ impl std::convert::From for std::io::Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.inner.kind { + match &self.inner.kind { ErrorKind::UnexpectedEof => "unexpected eof encountered".fmt(f)?, ErrorKind::InvalidCharInString(c) => write!( f, @@ -2131,6 +2146,10 @@ impl fmt::Display for Error { "unexpected keys in table: `{:?}`, available keys: `{:?}`", keys, available )?, + ErrorKind::UnquotedString => write!( + f, + "invalid TOML value, did you mean to use a quoted string?" + )?, ErrorKind::__Nonexhaustive => panic!(), } diff --git a/test-suite/tests/datetime.rs b/test-suite/tests/datetime.rs index 74b5939..6c08748 100644 --- a/test-suite/tests/datetime.rs +++ b/test-suite/tests/datetime.rs @@ -68,15 +68,15 @@ fn bad_times() { ); bad!( "foo = T", - "failed to parse datetime for key `foo` at line 1 column 7" + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" ); bad!( "foo = T.", - "expected newline, found a period at line 1 column 8" + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" ); bad!( "foo = TZ", - "failed to parse datetime for key `foo` at line 1 column 7" + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" ); bad!( "foo = 1997-09-09T09:09:09.09+", diff --git a/test-suite/tests/invalid.rs b/test-suite/tests/invalid.rs index ccc9338..f04d860 100644 --- a/test-suite/tests/invalid.rs +++ b/test-suite/tests/invalid.rs @@ -197,7 +197,7 @@ test!( test!( text_after_array_entries, include_str!("invalid/text-after-array-entries.toml"), - "invalid number at line 2 column 46" + "invalid TOML value, did you mean to use a quoted string? at line 2 column 46" ); test!( text_after_integer, @@ -222,5 +222,5 @@ test!( test!( text_in_array, include_str!("invalid/text-in-array.toml"), - "invalid number at line 3 column 3" + "invalid TOML value, did you mean to use a quoted string? at line 3 column 3" ); diff --git a/test-suite/tests/parser.rs b/test-suite/tests/parser.rs index eab9f5a..169df79 100644 --- a/test-suite/tests/parser.rs +++ b/test-suite/tests/parser.rs @@ -491,7 +491,10 @@ fn number_underscores() { fn bad_underscores() { bad!("foo = 0_", "invalid number at line 1 column 7"); bad!("foo = 0__0", "invalid number at line 1 column 7"); - bad!("foo = __0", "invalid number at line 1 column 7"); + bad!( + "foo = __0", + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" + ); bad!("foo = 1_0_", "invalid number at line 1 column 7"); } @@ -537,14 +540,20 @@ fn booleans() { bad!( "foo = true2", - "failed to parse datetime for key `foo` at line 1 column 7" + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" + ); + bad!( + "foo = false2", + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" ); - bad!("foo = false2", "invalid number at line 1 column 7"); bad!( "foo = t1", - "failed to parse datetime for key `foo` at line 1 column 7" + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" + ); + bad!( + "foo = f2", + "invalid TOML value, did you mean to use a quoted string? at line 1 column 7" ); - bad!("foo = f2", "invalid number at line 1 column 7"); } #[test] -- cgit v1.2.3