Recursive Descent

One function per grammar rule, and errors that point at the problem.

Part 3 of 3Updated

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.