Recursive Descent
One function per grammar rule, and errors that point at the problem.
Recursive descent is the parsing technique where each grammar rule becomes a function that calls the functions for its sub-rules.
fn parse_value(&mut self) -> Result<Value, ParseError> {
match self.peek()? {
Token::LBrace => self.parse_object(),
Token::LBracket => self.parse_array(),
Token::String(_) => { /* ... */ }
Token::Number(_) => { /* ... */ }
Token::True => { self.next()?; Ok(Value::Bool(true)) }
Token::False => { self.next()?; Ok(Value::Bool(false)) }
Token::Null => { self.next()?; Ok(Value::Null) }
tok => Err(ParseError::Unexpected(format!("{tok:?}"), self.pos)),
}
}
fn parse_array(&mut self) -> Result<Value, ParseError> {
self.expect(Token::LBracket)?;
let mut items = Vec::new();
if self.peek()? != &Token::RBracket {
loop {
items.push(self.parse_value()?); // <- recursion
if !self.eat(Token::Comma) { break; }
}
}
self.expect(Token::RBracket)?;
Ok(Value::Array(items))
}
Test it against the JSONTestSuite โ it will find bugs you didnโt think were possible, especially around numbers and escaped surrogate pairs.
Add a depth counter before you ship: deeply nested input will blow the stack otherwise.