Getting Better nom Errors With nom_supreme
This page is a draft prototype effort to get more helpful error reporting when using the nom parsing library in rust.
My current approach is to use the nom_supreme crate to add extra context and create a custom error struct to pass back at the end of the parsing run. Here's what it looks like:
```cargo
[dependencies]
nom = "7.1.1"
nom-supreme = "0.8.0"
```
use nom_supreme::error::ErrorTree;
use nom::IResult;
use nom::Parser;
use nom_supreme::final_parser::final_parser;
use nom_supreme::error::GenericErrorTree;
use nom_supreme::final_parser::Location;
use nom_supreme::final_parser::RecreateContext;
use nom::bytes::complete::tag;
use nom_supreme::parser_ext::ParserExt;
#[derive(Debug)]
pub struct ParserError {
line: usize,
column: usize,
remainder: String,
source: String,
message: String,
}
fn main() {
let content = "the quick brown fox";
match parse(content) {
Ok(matched) => {
println!("Success: {}", matched)
}
Err(e) => {
println!(
"Error: {} - line {} - column: {}\nAT: {}\nFROM: {}",
e.message,
e.line,
e.column,
e.remainder,
e.source,
)
}
}
}
fn parse(source: &str) -> Result<&str, ParserError> {
match final_parser(do_parse)(source) {
Ok(text) => Ok(text),
Err(e) => Err(get_error(source, &e))
}
}
fn do_parse(source: &str) -> IResult<&str, &str, ErrorTree<&str>> {
let (source , _) = tag("the")
.context("should be the")
.parse(source)?;
let (source , result) = tag("slow")
.context("should be slow")
.parse(source)?;
Ok((source, result))
}
fn get_error(content: &str, tree: &ErrorTree<&str>) -> ParserError {
match tree {
GenericErrorTree::Base{ location, kind }=> {
let details = Location::recreate_context(content, location);
ParserError{
line: details.line,
column: details.column,
source: content.to_string(),
remainder: location.to_string(),
message: kind.to_string()
}
},
GenericErrorTree::Stack{ contexts, ..}=> {
let context = contexts[0];
let details = Location::recreate_context(content, context.0);
ParserError{
line: details.line,
column: details.column,
source: content.to_string(),
remainder: context.0.to_string(),
message: context.1.to_string()
}
},
GenericErrorTree::Alt(items) => {
get_error(content, &items[0])
},
}
}
Error: in section "should be slow" - line 1 - column: 4
AT: quick brown fox
FROM: the quick brown fox