charon_core 0.6.1

A simple concatenative programming language
Documentation
use charon_ariadne::{Color, Label, Report, ReportBuilder, ReportKind, Source};
use rayon::prelude::*;

use crate::stdlib::{COMPLEX_TYPES, FUNCTIONS};
use crate::{State, Token, Tokens};

pub fn convert(token: &Token) -> String {
    match token {
        Token::Value(x) => x.to_string(),
        Token::Atom(x) => format!(":{}", x),
        Token::Special(x) | Token::Container(x) | Token::Function(x) => x.to_string(),
        Token::Group(contents) => match token.is_string() {
            Some(x) => x,
            _ => format!("{{{}}}", contents.literal()),
        },
        Token::List(contents) => format!("[{}]", contents.literal()),
        Token::FunctionLiteral(x) | Token::ContainerLiteral(x) => format!("`{}`", x),
        _ => format!("{:?}", token),
    }
}

pub fn type_of(token: &Token) -> String {
    let mut buffer = String::new();

    for character in token.to_string().chars() {
        if character == '(' {
            break;
        } else {
            buffer.push(character);
        }
    }

    buffer
}

pub trait Utils {
    fn get_par(
        &mut self,
        func: Token,
        reference_code: Tokens,
        state: &State,
    ) -> Result<Tokens, Report>;
    fn as_nums(&self) -> Vec<f64>;
    fn bundle(&self) -> Tokens;
    fn special_pairs(&self, first: &str, second: &str) -> Option<(usize, usize)>;
    fn skin_content(&mut self);
    fn literal(&self) -> String;
    fn literal_enumerate(&self) -> (String, Vec<std::ops::Range<usize>>);
}

impl Token {
    fn is_string(&self) -> Option<String> {
        match self {
            Token::Group(contents) => {
                let mut result = String::new();

                for token in contents {
                    match token {
                        Token::Char(y) => result.push_str(&y.to_string()),
                        _ => return None,
                    }
                }

                Some(result)
            }
            _ => None,
        }
    }
}

impl Utils for Tokens {
    fn get_par(
        &mut self,
        func: Token,
        reference_code: Tokens,
        state: &State,
    ) -> Result<Tokens, Report> {
        let mut result = vec![];
        let parameters = match func {
            Token::Function(ident) => FUNCTIONS.get(&ident).unwrap().1.to_vec(),
            Token::Container(ident) => {
                let container = state.get(&ident).unwrap();

                fn highest_rec(tokens: Tokens, max: usize) -> usize {
                    let mut highest: usize = 0;

                    for token in tokens {
                        if let Token::Group(inner) | Token::List(inner) = token {
                            let inner_highest = highest_rec(inner, max);

                            if inner_highest > highest {
                                highest = inner_highest;
                            }
                        } else if let Token::Parameter(index) = token {
                            if index + 1 > highest {
                                highest = index + 1
                            }
                        }
                    }

                    highest
                }

                let all_tokens: Vec<Token> = container
                    .iter()
                    .fold(vec![], |acc, x| [acc, x.0.clone(), x.1.clone()].concat());

                let max: usize = highest_rec(all_tokens, self.len());

                vec!["Any"; max]
            }
            _ => unimplemented!(),
        };
        let literal = reference_code.literal_enumerate();
        let mut final_report: Option<ReportBuilder<std::ops::Range<usize>, Source>> = None;

        for (index, token_type) in parameters.clone().iter().enumerate() {
            match self.pop() {
                Some(content) => {
                    if *token_type == "Any" || type_of(&content) == *token_type {
                        result.push(content);
                        continue;
                    } else if let Some(complex_type) = COMPLEX_TYPES.get(token_type) {
                        if complex_type.contains(&type_of(&content).as_str()) {
                            result.push(content);
                            continue;
                        }
                    }

                    if let Some(report) = final_report {
                        final_report = Some(
                            report.with_label(
                                Label::new(literal.1[literal.1.len() - index - 2].clone())
                                    .with_message(format!(
                                        "This has the type of {} but expected {}.",
                                        type_of(&content),
                                        *token_type
                                    ))
                                    .with_color(Color::Red),
                            ),
                        )
                    } else {
                        final_report = Some(
                            Report::build(ReportKind::Error)
                                .with_message("Mismatched Types")
                                .with_label(
                                    Label::new(literal.1[literal.1.len() - index - 2].clone())
                                        .with_message(format!(
                                            "This has the type of {} but expected {}.",
                                            type_of(&content),
                                            *token_type
                                        ))
                                        .with_color(Color::Red),
                                ),
                        )
                    }
                }
                None => {
                    let mut report = Report::build(ReportKind::Error)
                        .with_message("Missing Parameters")
                        .with_label(
                            Label::new(literal.1[literal.1.len() - 1].clone())
                                .with_message(format!(
                                    "This function expects the parameters ({}).",
                                    parameters
                                        .clone()
                                        .iter()
                                        .fold("".to_string(), |x, acc| format!("{} {}", acc, x))
                                        .trim()
                                ))
                                .with_color(Color::Red),
                        );

                    if !result.is_empty() {
                        report = report.with_label(
                            Label::new(
                                literal.1[0].clone().start
                                    ..literal.1[literal.1.len() - 2].clone().end,
                            )
                            .with_message(format!("Only {} parameter(s) provided.", result.len()))
                            .with_color(Color::Yellow),
                        )
                    }

                    final_report = Some(report)
                }
            }
        }

        if let Some(report) = final_report {
            return Err(report.with_source(Source::from(literal.0)).finish());
        }

        Ok(result)
    }

    fn as_nums(&self) -> Vec<f64> {
        self.iter()
            .map(|value| match value.clone() {
                Token::Value(n) => n,
                _ => 1.0,
            })
            .collect()
    }

    fn bundle(&self) -> Tokens {
        static BUNDLES: &[(&str, &str, &str); 3] =
            &[("(", ")", "Expr"), ("{", "}", "Group"), ("[", "]", "List")];

        let mut bundled = self.clone();

        for (first, second, collection) in BUNDLES {
            if let Some((x, y)) = self.special_pairs(first, second) {
                let bundled_token = match *collection {
                    "Expr" => Token::Expr,
                    "Group" => Token::Group,
                    "List" => Token::List,
                    _ => unimplemented!(),
                }(bundled[x + 1..y].to_vec().bundle());

                bundled.splice(x..y + 1, vec![bundled_token]);
                bundled = bundled.bundle();
            }
        }

        bundled
    }

    fn special_pairs(&self, first: &str, second: &str) -> Option<(usize, usize)> {
        let mut first_index: Option<usize> = None;
        let mut second_index: Option<usize> = None;

        for (index, value) in self.iter().enumerate() {
            if Token::Special(first.to_string()) == *value {
                first_index = Some(index);
                break;
            }
        }

        let mut count: i32 = 1;

        for (index, value) in self[first_index? + 1..].iter().enumerate() {
            if count == 0 {
                second_index = Some(index + first_index?);
                break;
            } else if Token::Special(first.to_string()) == *value {
                count += 1;
            } else if Token::Special(second.to_string()) == *value {
                count -= 1;
            }
        }

        if count == 0 && second_index.is_none() {
            second_index = Some(self[first_index? + 1..].len() + first_index?);
        }

        Some((first_index?, second_index?))
    }

    fn skin_content(&mut self) {
        if matches!(
            (self.first(), self.last()),
            (Some(Token::Special(_)), Some(Token::Special(_)))
        ) {
            let bracket_acc = self.iter().fold(0, |acc, x| {
                if matches!(x, Token::Special(y) if y == "(") {
                    acc + 1
                } else if matches!(x, Token::Special(y) if y == ")") {
                    acc - 1
                } else {
                    acc
                }
            });

            if bracket_acc == 0 {
                self.remove(0);
                self.pop();
            }
        }
    }

    fn literal(&self) -> String {
        self.iter()
            .fold(String::new(), |acc, x| format!("{} {}", acc, convert(x)))
            .trim()
            .to_string()
    }

    fn literal_enumerate(&self) -> (String, Vec<std::ops::Range<usize>>) {
        self.iter().fold((String::new(), vec![]), |mut acc, x| {
            let token_string = convert(x);

            let mut token_range = 0..token_string.len();

            if acc.0.is_empty() {
                acc = (token_string, vec![token_range]);
            } else {
                token_range.start = acc.0.len() + 1;
                acc.0 = format!("{} {}", acc.0, token_string);
                token_range.end += token_range.start;
                acc.1.push(token_range);
            }

            acc
        })
    }
}

pub fn encode_string(string: &str) -> Token {
    Token::Group(string.chars().map(Token::Char).collect::<Vec<_>>())
}

pub trait Function {
    fn resolve(&self, function: &Tokens, arr: &Tokens) -> Tokens;
}

impl Function for State {
    fn resolve(&self, function: &Tokens, arr: &Tokens) -> Tokens {
        let reversed: Tokens = arr.iter().cloned().rev().collect();
        function
            .par_iter()
            .map(|token| {
                if let Token::Parameter(index) = token {
                    reversed[*index].clone()
                } else {
                    token.clone()
                }
            })
            .collect()
    }
}