summaryrefslogtreecommitdiff
path: root/parser/src/error.rs
blob: ca684421415c5cf3d4fe1fdb8fd74e70657530b5 (plain) (blame)
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
97
98
99
100
101
102
103
104
105
106
use std::{i64, process::exit};

use colored::Colorize;
use unicode_width::UnicodeWidthStr;

#[derive(Debug)]
pub enum Exit {
    Code(i32),
    IoError(std::io::Error),
    SyntaxError {
        content: String,
        reason: String,
        line: i64,
        begin: i64,
        end: i64,
    },
}

impl From<std::io::Error> for Exit {
    fn from(error: std::io::Error) -> Self {
        Exit::IoError(error)
    }
}

pub fn handle_exit(e: Exit) {
    match e {
        Exit::Code(code) => exit(code),
        Exit::IoError(error) => print_parse_error(error.to_string()),
        Exit::SyntaxError {
            content,
            reason,
            line,
            begin,
            end,
        } => {
            print_syntax_error(content, reason, line, begin, end);
        }
    }
}

fn print_parse_error(content: impl AsRef<str>) {
    eprintln!("Parse Error !");
    eprintln!("{}", content.as_ref().trim());
    exit(1);
}

macro_rules! line {
    ($line:expr, $N:expr) => {
        if $line + $N <= 0 {
            " ".to_string()
        } else {
            ($line + $N).to_string()
        }
    };
}

pub fn print_syntax_error(content: String, reason: String, line: i64, begin: i64, end: i64) {
    let content_len = content.width() as i64;
    let end = end.clamp(begin, content_len);

    eprintln!("{}", "Parse Failed: Syntax Error".bright_yellow());
    eprintln!("{}{}", line!(line, -1), "|");

    let before: String = content.chars().take(begin.max(0) as usize).collect();
    let highlight_len = (end - begin).max(1) as usize;
    let highlight: String = content
        .chars()
        .skip(begin.max(0) as usize)
        .take(highlight_len)
        .collect();
    let after: String = content
        .chars()
        .skip((begin.max(0) + highlight_len as i64) as usize)
        .collect();

    eprintln!(
        "{}{} {}{}{}",
        line.to_string().cyan(),
        "|".cyan(),
        before.cyan(),
        highlight.bright_cyan(),
        after.cyan()
    );

    let prefix_chars: String = content.chars().take(begin.max(0) as usize).collect();
    let prefix_width = prefix_chars.width() as usize;

    eprintln!(
        "{}{} {}",
        line!(line, 1),
        "|",
        format!(
            "{}{}____ {}",
            " ".repeat(prefix_width),
            "^".repeat(((end - begin).max(1)) as usize),
            reason
        )
        .bright_cyan()
    );
    eprintln!("{}{}", line!(line, 2), "|");
    eprintln!(
        "{}",
        "Please fix the issue and run the program again".bright_yellow()
    );
    exit(1);
}