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
use colored::Colorize;
use symboscript_types::lexer::{Token, TokenKind::*};

pub fn output_tokens_colored(text: &str, tokens: &Vec<Token>, show_tokens: Option<bool>) {
    let show_tokens = show_tokens.unwrap_or(false);
    let mut last_start;
    let mut last_end = 0;

    for token in tokens {
        last_start = token.start;
        print!("{}", text[last_end..last_start].to_string());
        last_end = token.end;

        let s = if show_tokens {
            format!("<{}>", text[token.start..token.end].to_string())
        } else {
            format!("{}", text[token.start..token.end].to_string())
        };

        match token.kind {
            Identifier => print!("{}", s.yellow()),

            Plus | Minus | Star | Slash | Power | Assign | Equal | Range | FormulaAssign | And
            | Or | Xor | Not | BitAnd | BitOr | BitNot | BitXor | BitLeftShift | BitRightShift => {
                print!("{}", s.green())
            }

            Number => print!("{}", s.blue()),

            LParen | RParen | LBrace | RBrace => print!("{}", s.cyan()),

            If | Else | While | For | Loop | Let | Return | Break | Continue | Function | True
            | False | In => print!("{}", s.magenta()),

            String => print!("{}", s.truecolor(206, 145, 120)),

            Comment => print!("{}", s.green()),

            _ => print!("{}", s),
        }
    }

    print!("{}", text[last_end..].to_string());

    println!();
}

pub fn report_error(path: &str, source: &str, error: &str, start: usize, end: usize) {
    let line = source[..start + 1].lines().count();
    let line_end = line - 1 + source[start..end].lines().count();

    let column = start - source[..start].rfind('\n').unwrap_or(0);
    let column_end = end - source[..start].rfind('\n').unwrap_or(0);

    let near_text = source.lines().nth(line - 1).unwrap_or(&"").trim_end();

    let line_n = format!("{line} |");

    let error_pointer = (" ".repeat(column + line_n.len()) + "^".repeat(end - start).as_str())
        .red()
        .bold();
    let error_pointer_text = (&error).red().bold();

    println!(
        "{}\n{} {near_text}\n{error_pointer} {error_pointer_text}",
        format!(
            "--> {}:{}:{}-{}:{}",
            path, line, column, line_end, column_end
        )
        .blue()
        .bold(),
        line_n.to_string().blue().bold(),
    );

    std::process::exit(1);
}