1use std::cmp::max;
2
3use colored::Colorize;
4use symboscript_types::lexer::{Token, TokenKind::*};
5
6pub fn output_tokens_colored(text: &str, tokens: &Vec<Token>, show_tokens: Option<bool>) {
7 let show_tokens = show_tokens.unwrap_or(false);
8 let mut last_start;
9 let mut last_end = 0;
10
11 for token in tokens {
12 last_start = token.start;
13 print!("{}", text[last_end..last_start].to_string());
14 last_end = token.end;
15
16 let s = if show_tokens {
17 format!("<{}>", text[token.start..token.end].to_string())
18 } else {
19 format!("{}", text[token.start..token.end].to_string())
20 };
21
22 print!("{}", {
23 match token.kind {
24 Identifier => s.yellow(),
25
26 Plus | Minus | Star | Slash | Caret | Assign | Equal | Range | FormulaAssign
27 | AmpersandAmpersand | PipePipe | Xor | ExclamationMark | Ampersand | Pipe
28 | Tilde | BitXor | BitLeftShift | BitRightShift => s.green(),
29
30 Number => s.blue(),
31
32 LParen | RParen | LAngle | RAngle => s.cyan(),
33
34 If | Else | While | For | Loop | Let | Return | Break | Continue | Function
35 | True | False | In => s.magenta(),
36
37 Str => s.truecolor(206, 145, 120),
38
39 DocComment | Comment => s.green(),
40
41 _ => s.into(),
42 }
43 });
44 }
45
46 print!("{}", text[last_end..].to_string());
47
48 println!();
49}
50
51pub fn report_error(path: &str, source: &str, error: &str, start: usize, end: usize) {
52 let line_start = max(source[..start].lines().count(), 1);
53 let line_end = max(source[..end].lines().count(), 1);
54
55 let mut column_start = start - source[..start].rfind('\n').unwrap_or(0);
56 let mut column_end = end - source[..end].rfind('\n').unwrap_or(0);
57
58 if line_start == 1 || line_end == 1 {
59 column_end += 1;
60 column_start += 1;
61 }
62
63 if column_end < column_start {
64 column_end = source[..end].rfind('\n').unwrap_or(0);
65 }
66
67 let near_text = source.lines().nth(line_end - 1).unwrap_or("").trim_end();
68
69 let line_n = format!("{line_end} |");
70
71 let error_pointer = (" ".repeat(column_start + line_n.len())
72 + "^".repeat(column_end - column_start).as_str())
73 .red()
74 .bold();
75
76 let error_pointer_text = error
77 .replace(
78 "\n",
79 &format!(
80 "\n{} ",
81 " ".repeat(column_end - column_start) + &" ".repeat(column_start + line_n.len())
82 ),
83 )
84 .red()
85 .bold();
86
87 let file_src = format!(
88 "--> {}:{}:{}-{}:{} ({start} - {end})",
89 path, line_start, column_start, line_end, column_end
90 );
91
92 println!("{}", file_src.blue().bold());
93
94 for i in line_start..line_end {
95 println!(
96 "{} {}",
97 format!("{} |", i).blue().bold(),
98 source.lines().nth(i - 1).unwrap_or("")
99 );
100 }
101
102 println!(
103 "{} {near_text}\n{error_pointer} {error_pointer_text}",
104 line_n.to_string().blue().bold(),
105 );
106
107 std::process::exit(1);
108}