Skip to content

Instantly share code, notes, and snippets.

@zicklag
Created February 1, 2020 19:28
Show Gist options
  • Save zicklag/aad1944ef7f5dd256218892477f32c64 to your computer and use it in GitHub Desktop.
Save zicklag/aad1944ef7f5dd256218892477f32c64 to your computer and use it in GitHub Desktop.
Example of using rust-peg parser and chic error messages
[package]
name = "parserator"
version = "0.1.0"
authors = ["Zicklag"]
edition = "2018"
[dependencies]
peg = "0.6.1"
anyhow = "1.0.26"
chic = "1.2.2"
thiserror = "1.0.10"
error: Parser error
|
4 | [ 1, 3,4, 5,
5 | 6,
6 |
7 | 8, 9, 10, 7,10d]
| ^ Expected: one of ",", "]"
|
#[derive(thiserror::Error, Debug)]
#[error("Parser error")]
struct ParseratorError {
error: peg::error::ParseError<peg::str::LineCol>,
src: String,
}
impl ParseratorError {
fn new(error: peg::error::ParseError<peg::str::LineCol>, src: &str) -> Self {
ParseratorError {
error,
src: src.to_string(),
}
}
}
peg::parser! {
grammar list_parser() for str {
// Whitespace character
rule whitespace_char() = ['\t' | ' ']
// Line comment
rule line_comment() = "//" (!"\n" [_])* ("\n" / ![_])
// Inline comment
rule inline_comment() = "/*" (!"*/" [_])* "*/"
// Whitespace including comments
rule w() = quiet!{ (whitespace_char() / inline_comment())* }
// Whitespace including newlines and line comments
rule wn() = quiet!{ (whitespace_char() / "\n" / inline_comment() / line_comment())* }
rule number() -> u32
= quiet!{
n:$(['0'..='9']+) { n.parse().unwrap() }
} / expected!("number")
pub rule list() -> Vec<u32>
= "[" wn() n:number() ** (wn() "," wn()) "]" { n }
}
}
pub fn run() {
if let Err(e) = execute() {
if let Some(parserator_err) = e.downcast_ref::<ParseratorError>() {
let peg_err = &parserator_err.error;
let msg = chic::Error::new("Parser error")
.error(
peg_err.location.line,
peg_err.location.offset + peg_err.location.line - 1,
peg_err.location.offset + peg_err.location.line,
&parserator_err.src,
format!("Expected: {}", peg_err.expected),
)
.to_string();
eprintln!("{}", msg);
}
}
}
fn execute() -> anyhow::Result<()> {
dbg!(parse_list(
"[ 1, 3,4, 5,
6,
8, 9, 10, 7,10d]"
)?);
Ok(())
}
fn parse_list(data: &str) -> anyhow::Result<Vec<u32>> {
Ok(list_parser::list(data).map_err(|e| ParseratorError::new(e, data))?)
}
use parserator;
fn main() {
parserator::run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment