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
use crate::unicodes::*;
use colored::*;
pub struct Traceback;
impl Traceback {
fn line_number(program: &str, program_counter: usize) -> Result<usize, ()> {
let mut acc = program_counter as isize;
let mut current_line: isize = -1;
while acc >= 0 {
acc -= program
.lines()
.nth((current_line + 1) as usize)
.ok_or(())?
.chars()
.count() as isize;
current_line += 1;
}
Ok(current_line as usize)
}
fn char_number(program: &str, line_nr: usize, program_counter: usize) -> usize {
let chars_before_current_line: &usize = &program
.lines()
.take(line_nr)
.fold(0, |sum, l| sum + l.chars().count());
program_counter - chars_before_current_line
}
fn highlight_current_char_in_line<'a>(
current_line: &'a UnicodeString,
char_nr: usize,
) -> Result<String, ()> {
let before_current_char = current_line
.iter()
.take(char_nr)
.fold(String::new(), |acc, x| acc + x);
let current_char = current_line
.iter()
.nth(char_nr)
.ok_or(())?
.red();
let after_current_char = current_line
.iter()
.skip(char_nr + 1)
.take(current_line.len() - char_nr)
.fold(String::new(), |acc, x| acc + x);
Ok( format!("{}{}{}", before_current_char, current_char, after_current_char) )
}
pub fn traceback(program: &str, program_counter: usize, error_msg: &str) -> Result<String, ()> {
let line_nr = Traceback::line_number(program, program_counter)?;
let current_line = program.lines().nth(line_nr).ok_or(())?;
let current_line = string_to_unicode_string(current_line);
let char_nr = Traceback::char_number(program, line_nr, program_counter);
let highlighted_current_line =
Traceback::highlight_current_char_in_line(¤t_line, char_nr)?;
Ok(format!(
"{}\non line {}, char {}:\n{}\n",
error_msg,
line_nr + 1,
char_nr + 1,
highlighted_current_line
))
}
}
#[cfg(test)]
mod test_traceback;