1use combine::easy::{Errors, Error};
2
3use tokenizer::Token;
4use position::Pos;
5
6pub type InternalError<'a> = Errors<Token<'a>, Token<'a>, Pos>;
7
8
9#[derive(Fail, Debug)]
14#[fail(display="parse error: {}", _0)]
15pub struct ParseError(Errors<String, String, Pos>);
16
17#[cfg(not(feature="fuzzy_errors"))]
18impl<'a> From<InternalError<'a>> for ParseError {
19 fn from(e: InternalError<'a>) -> ParseError {
20 ParseError(e
21 .map_token(|t| t.value.to_string())
22 .map_range(|t| t.value.to_string()))
23 }
24}
25
26fn convert(error: Error<Token, Token>) -> Error<String, String> {
27 error
28 .map_token(|t| t.value.to_string())
29 .map_range(|t| t.value.to_string())
30}
31
32#[cfg(feature="fuzzy_errors")]
33impl<'a> From<InternalError<'a>> for ParseError {
34 fn from(e: InternalError<'a>) -> ParseError {
35 use strsim::jaro_winkler;
36 use combine::easy::{Info};
37
38 let mut error_buf = Vec::new();
39 let mut expected_buf = Vec::new();
40 let mut unexpected = None;
41 for item in e.errors {
44 match item {
45 Error::Expected(info) => {
46 expected_buf.push(info);
47 continue;
48 }
49 Error::Unexpected(ref val) => {
50 unexpected = Some(val.to_string());
51 }
52 _ => {}
53 }
54 error_buf.push(convert(item));
55 }
56 println!("Unexpected {:?}, expected {:?}", unexpected, expected_buf);
57 if let Some(unexpected) = unexpected {
58 if expected_buf.len() > 3 {
59 let mut close = Vec::new();
60 for item in &expected_buf {
61 match item {
62 Info::Borrowed(item) => {
63 let conf = jaro_winkler(&unexpected, item);
64 if conf > 0.8 {
65 close.push((item, conf));
66 }
67 }
68 _ => {
69 }
72 }
73 }
74 close.sort_by_key(|&(_, ref x)| (10000. - 10000. * x) as u32);
75 close.truncate(3);
76 for (item, _) in &close {
77 error_buf.push(convert(Error::Expected(
78 Info::Borrowed(item))));
79 }
80 if close.len() < expected_buf.len() {
81 error_buf.push(Error::Expected(Info::Owned(format!(
82 "one of {} options",
83 expected_buf.len() - close.len(),
84 ))));
85 }
86 } else {
87 for e in expected_buf {
88 error_buf.push(convert(Error::Expected(e)));
89 }
90 }
91 } else {
92 for e in expected_buf {
93 error_buf.push(convert(Error::Expected(e)));
94 }
95 }
96 return ParseError(Errors { position: e.position, errors: error_buf })
97 }
98}