Skip to content

Commit 1c46d16

Browse files
pretty error (#3)
Co-authored-by: chenyan-dfinity <[email protected]>
1 parent 979765c commit 1c46d16

File tree

5 files changed

+76
-3
lines changed

5 files changed

+76
-3
lines changed

Cargo.lock

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ candid = { git = "https://github.com/dfinity/candid.git", branch = "fix-beta", f
1212
rustyline = "8.0"
1313
rustyline-derive = "0.4"
1414
ansi_term = "0.12"
15+
codespan-reporting = "0.11"
16+
pretty = "0.10.0"
1517
ic-agent = { git = "https://github.com/dfinity/agent-rs.git", branch = "yan/test" }
1618
tokio = { version = "1.5.0", features = ["full"] }
1719
delay = "0.3.1"

src/command.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::error::pretty_parse;
12
use super::helper::{MyHelper, NameEnv};
23
use super::token::{ParserError, Spanned, Tokenizer};
34
use anyhow::{anyhow, Context};
@@ -176,7 +177,7 @@ impl Command {
176177
let line_end = script.find('\n').unwrap_or(0);
177178
script.drain(..line_end);
178179
}
179-
let cmds = script.parse::<Commands>()?;
180+
let cmds = pretty_parse::<Commands>(&file, &script)?;
180181
helper.base_path = path.parent().unwrap().to_path_buf();
181182
for cmd in cmds.0.iter() {
182183
println!("> {:?}", cmd);

src/error.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use crate::token::ParserError;
2+
use codespan_reporting::diagnostic::{Diagnostic, Label};
3+
use codespan_reporting::files::SimpleFile;
4+
use codespan_reporting::term::{self, termcolor::StandardStream};
5+
6+
fn report(e: &ParserError) -> Diagnostic<()> {
7+
use lalrpop_util::ParseError::*;
8+
let mut diag = Diagnostic::error().with_message("parser error");
9+
let label = match e {
10+
User { error } => Label::primary((), error.span.clone()).with_message(&error.err),
11+
InvalidToken { location } => {
12+
Label::primary((), *location..location + 1).with_message("Invalid token")
13+
}
14+
UnrecognizedEOF { location, expected } => {
15+
diag = diag.with_notes(report_expected(&expected));
16+
Label::primary((), *location..location + 1).with_message("Unexpected EOF")
17+
}
18+
UnrecognizedToken { token, expected } => {
19+
diag = diag.with_notes(report_expected(&expected));
20+
Label::primary((), token.0..token.2).with_message("Unexpected token")
21+
}
22+
ExtraToken { token } => Label::primary((), token.0..token.2).with_message("Extra token"),
23+
};
24+
diag.with_labels(vec![label])
25+
}
26+
27+
fn report_expected(expected: &[String]) -> Vec<String> {
28+
if expected.is_empty() {
29+
return Vec::new();
30+
}
31+
use pretty::RcDoc;
32+
let doc: RcDoc<()> = RcDoc::intersperse(
33+
expected.iter().map(RcDoc::text),
34+
RcDoc::text(",").append(RcDoc::softline()),
35+
);
36+
let header = if expected.len() == 1 {
37+
"Expects"
38+
} else {
39+
"Expects one of"
40+
};
41+
let doc = RcDoc::text(header).append(RcDoc::softline().append(doc));
42+
vec![doc.pretty(70).to_string()]
43+
}
44+
45+
pub fn pretty_parse<T>(name: &str, str: &str) -> Result<T, ParserError>
46+
where
47+
T: std::str::FromStr<Err = ParserError>,
48+
{
49+
str.parse::<T>().map_err(|e| {
50+
let writer = StandardStream::stderr(term::termcolor::ColorChoice::Auto);
51+
let config = term::Config::default();
52+
let file = SimpleFile::new(name, str);
53+
term::emit(&mut writer.lock(), &config, &file, &report(&e)).unwrap();
54+
e
55+
})
56+
}

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ use rustyline::CompletionType;
55
use tokio::runtime::Runtime;
66

77
mod command;
8+
mod error;
89
mod grammar;
910
mod helper;
1011
mod token;
1112
use crate::command::Command;
13+
use crate::error::pretty_parse;
1214
use crate::helper::MyHelper;
1315

1416
fn unwrap<T, E, F>(v: Result<T, E>, f: F)
@@ -69,7 +71,7 @@ fn repl(opts: Opts) -> anyhow::Result<()> {
6971
match input {
7072
Ok(line) => {
7173
rl.add_history_entry(&line);
72-
unwrap(line.parse::<Command>(), |cmd| {
74+
unwrap(pretty_parse::<Command>("stdin", &line), |cmd| {
7375
let mut helper = rl.helper_mut().unwrap();
7476
helper.history.push(line.clone());
7577
unwrap(cmd.run(&mut helper), |_| {});

0 commit comments

Comments
 (0)