Skip to content

Commit ebf6d86

Browse files
committed
Fix parsing of collections, short values.
This fixes a regression introduced in c730bdf in which an unterminated collection string (e.g. "[") would cause the parser to loop infinitely. It also fixes a regression in which the parser would discard the latter part of a string if the earlier part parsed as a valid value while the latter did not, e.g. " [discarded" in "okay [discarded". Fixes #120.
1 parent 3f9f333 commit ebf6d86

File tree

1 file changed

+43
-35
lines changed

1 file changed

+43
-35
lines changed

src/value/parse.rs

+43-35
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@ pub enum Error {
1616
Eof,
1717
}
1818

19-
type Result<'a, T> = std::result::Result<T, Error>;
19+
type Result<T> = std::result::Result<T, Error>;
2020

2121
impl<'a> Parser<'a> {
2222
fn new(cursor: &'a str) -> Self {
2323
Self { cursor }
2424
}
2525

2626
fn peek(&self, c: char) -> bool {
27-
self.cursor.chars().next() == Some(c)
27+
self.peek_next() == Some(c)
28+
}
29+
30+
fn eof(&self) -> bool {
31+
self.cursor.is_empty()
2832
}
2933

3034
fn peek_next(&self) -> Option<char> {
@@ -104,46 +108,39 @@ impl<'a> Parser<'a> {
104108
}
105109
}
106110

107-
fn dict(&mut self) -> Result<Dict> {
108-
self.eat('{')?;
111+
fn delimited<T, V, F>(&mut self, start: char, end: char, value: F) -> Result<T>
112+
where T: Extend<V> + Default, F: Fn(&mut Self) -> Result<V>,
113+
{
114+
let mut collection = T::default();
115+
self.eat(start)?;
116+
self.skip_whitespace();
117+
118+
while !self.peek(end) {
119+
collection.extend(Some(value(self)?));
109120

110-
let mut dict = Dict::new();
111-
loop {
112121
self.skip_whitespace();
113-
if self.eat('}').is_ok() {
122+
if self.eat(',').is_err() {
114123
break;
115124
}
116125

117-
let key = self.key()?;
118126
self.skip_whitespace();
119-
self.eat('=')?;
120-
self.skip_whitespace();
121-
let value = self.value()?;
122-
dict.insert(key.to_string(), value);
123-
124-
self.skip_whitespace();
125-
let _ = self.eat(',');
126127
}
127128

128-
Ok(dict)
129+
self.eat(end)?;
130+
Ok(collection)
129131
}
130132

131-
fn array(&mut self) -> Result<Vec<Value>> {
132-
self.eat('[')?;
133-
let mut values = Vec::new();
134-
135-
loop {
136-
self.skip_whitespace();
137-
if self.eat(']').is_ok() {
138-
break;
139-
}
140-
141-
values.push(self.value()?);
142-
self.skip_whitespace();
143-
let _ = self.eat(',');
144-
}
133+
fn dict(&mut self) -> Result<Dict> {
134+
self.delimited('{', '}', |parser| {
135+
let key = parser.key()?;
136+
(parser.skip_whitespace(), parser.eat('=')?, parser.skip_whitespace());
137+
let value = parser.value()?;
138+
Ok((key.to_string(), value))
139+
})
140+
}
145141

146-
Ok(values)
142+
fn array(&mut self) -> Result<Vec<Value>> {
143+
self.delimited('[', ']', |parser| parser.value())
147144
}
148145

149146
fn value(&mut self) -> Result<Value> {
@@ -152,6 +149,7 @@ impl<'a> Parser<'a> {
152149
!matches!(byte, ',' | '{' | '}' | '[' | ']')
153150
}
154151

152+
self.skip_whitespace();
155153
let value = match self.peek_next() {
156154
Some('"') => Value::from(self.quoted_str()?.to_string()),
157155
Some('\'') => Value::from(self.quoted_char()?),
@@ -187,11 +185,12 @@ impl<'a> Parser<'a> {
187185
impl std::str::FromStr for Value {
188186
type Err = std::convert::Infallible;
189187

190-
fn from_str(s: &str) -> std::result::Result<Self, std::convert::Infallible> {
191-
let mut parser = Parser::new(s.trim());
188+
fn from_str(string: &str) -> std::result::Result<Self, std::convert::Infallible> {
189+
let string = string.trim();
190+
let mut parser = Parser::new(string);
192191
match parser.value() {
193-
Ok(value) => Ok(value),
194-
Err(_) => Ok(Value::from(s)),
192+
Ok(value) if parser.eof() => Ok(value),
193+
_ => Ok(Value::from(string)),
195194
}
196195
}
197196
}
@@ -231,13 +230,19 @@ mod tests {
231230
" -0" => 0i8,
232231
" -2" => -2,
233232
" 123 " => 123u8,
233+
"a,b" => "a,b",
234+
" a,b" => "a,b",
234235
"\"a\"" => "a",
235236
"a " => "a",
236237
" a " => "a",
237238
"\" a\"" => " a",
238239
"\"a \"" => "a ",
239240
"\" a \"" => " a ",
240241
"1.2" => 1.2,
242+
"[" => "[",
243+
"[a" => "[a",
244+
"[a b" => "[a b",
245+
"]" => "]",
241246
" 1.2" => 1.2,
242247
"3.14159" => 3.14159,
243248
"\"\\t\"" => "\t",
@@ -263,6 +268,9 @@ mod tests {
263268
"[1,2,3]" => vec![1u8, 2u8, 3u8],
264269
"[ 1 , 2 ,3]" => vec![1u8, 2u8, 3u8],
265270
" [ 1 , 2 , 3 ] " => vec![1u8, 2u8, 3u8],
271+
" [ a , b ,, d ] " => vec!["a", "b", "", "d"],
272+
" [ a , b c,] " => vec!["a", "b c"],
273+
" [ a , b c,,] " => vec!["a", "b c", ""],
266274
"{a=b}" => map!["a" => "b"],
267275
" { a = b } " => map!["a" => "b"],
268276
"{\"a\"=b}" => map!["a" => "b"],

0 commit comments

Comments
 (0)