1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
pub mod display;
mod list;

pub use self::list::get_error_desc;
pub use self::list::ErrorInfo;
pub use self::list::ErrorKind;
pub use self::list::ParserError;

macro_rules! error {
    ($kind:expr) => {{
        Err(ParserError {
            info: None,
            kind: $kind,
        })
    }};
}

fn get_line_num(source: &str, pos: usize) -> usize {
    let mut ptr = 0;
    let mut i = 0;

    let lines = source.lines();

    for line in lines {
        let lnlen = line.chars().count();
        ptr += lnlen + 1;

        if ptr > pos {
            break;
        }
        i += 1;
    }

    i
}

pub fn get_error_lines(source: &str, start: usize, end: usize) -> String {
    let l = if start < end { end - start } else { 1 };

    let lines = source.lines().skip(start).take(l);

    let mut s = String::new();

    for line in lines {
        s.push_str(line);
        s.push('\n');
    }

    String::from(s.trim_right())
}

pub fn get_error_slice(source: &str, start: usize, end: usize) -> &str {
    let len = source.chars().count();

    let start_pos;
    let mut slice_len = end - start;

    if len <= slice_len {
        start_pos = 0;
        slice_len = len;
    } else if start + slice_len >= len {
        start_pos = len - slice_len - 1;
    } else {
        start_pos = start;
    }

    let mut iter = source.chars();
    if start_pos > 0 {
        iter.by_ref().nth(start_pos - 1);
    }
    let slice = iter.as_str();
    let endp = slice
        .char_indices()
        .nth(slice_len)
        .map(|(n, _)| n)
        .unwrap_or(len);
    &slice[..endp]
}

pub fn get_error_info(
    source: &str,
    pos: usize,
    entry_start: usize,
    next_entry_start: usize,
) -> Option<ErrorInfo> {
    let first_line_num = get_line_num(source, entry_start);
    let next_entry_line = get_line_num(source, next_entry_start);

    let slice = get_error_lines(source, first_line_num, next_entry_line);

    Some(ErrorInfo {
        slice,
        line: first_line_num,
        pos: pos - entry_start,
    })
}