brono 0.0.0

A programming language that compiles down to Brainfuck.
Documentation
#![allow(dead_code)]

use owo_colors::OwoColorize;

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
pub enum MessageType {
    Info,
    Warning,
    Error,
    Todo,
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
pub enum MessageLocation<'a> {
    None,
    File(&'a str, MessageSpan<'a>, Option<(usize, usize)>),
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
pub struct MessageSpan<'a> {
    text: &'a str,
    start: usize,
    end: usize,
}

impl<'a> MessageSpan<'a> {
    pub fn new(text: &'a str, start: usize) -> Self {
        return Self {
            text,
            start,
            end: start + text.chars().into_iter().collect::<Vec<char>>().len(),
        };
    }

    pub fn empty() -> Self {
        return Self {
            text: "",
            start: 0,
            end: 1,
        };
    }

    pub fn is_empty(&self) -> bool {
        return *self == Self::empty();
    }
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
pub struct Message<'a> {
    msg: &'a str,
    msg_type: MessageType,
    location: MessageLocation<'a>,
}

impl<'a> Message<'a> {
    pub fn new(msg: &'a str, msg_type: MessageType, location: MessageLocation<'a>) -> Self {
        return Self {
            msg,
            msg_type,
            location,
        };
    }

    pub fn print(&self) {
        match self.location {
            MessageLocation::None => {
                println!(
                    "{} {} {}",
                    colorize("COMPILER", self.msg_type).on_black().reversed().bold(),
                    "::".bright_black().bold(),
                    self.msg.bold(),
                );
            },
            MessageLocation::File(file, area, problem_area) => {
                let tab = "    ";

                println!(
                    "{} {} {}",
                    colorize(file, self.msg_type).on_black().reversed().bold(),
                    "::".bright_black().bold(),
                    self.msg.bold(),
                );

                if area.is_empty() {
                    return;
                }

                let length = area.end - area.start;

                println!(
                    "{tab}{tab}{} (start: {} | end: {} | length: {})",
                    area.text,
                    colorize(&area.start.to_string(), self.msg_type).bold(),
                    colorize(&area.end.to_string(), self.msg_type).bold(),
                    colorize(&length.to_string(), self.msg_type).bold(),
                );

                if let Some(problem_area) = problem_area {
                    let start = problem_area.0 - area.start;
                    let end = (problem_area.1 - problem_area.0) + start;

                    print!("{tab}{tab}");

                    for i in 0..length {
                        if i >= start && i < end {
                            print!("{}", colorize("^", self.msg_type).bold());
                        }

                        else {
                            print!(" ");
                        }
                    }

                    println!("");
                }
            },
        };
    }
}

fn colorize(text: &str, msg_type: MessageType) -> String {
    return match msg_type {
        MessageType::Info => text.bright_green().to_string(),
        MessageType::Warning => text.bright_yellow().to_string(),
        MessageType::Error => text.bright_red().to_string(),
        MessageType::Todo => text.bright_cyan().to_string(),
    };
}