ralix 0.2.0

A simple, type-safe, tree walking interpreter
use std::{error::Error, fmt::Display, io};

use crate::{Expression, Literal, Statement, Token, types::Type};

pub type ParserResult<N> = Result<N, ParserDiagnostic>;

#[derive(Debug)]
pub enum ParserDiagnostic {
    SyntaxError { expected: Token, got: Token },
    IsNotIdentifier(Token),
    Undefined(Literal),
    TypeMistake(Literal),
    ExpressionMistake(Token),
    IntegerParse(Literal),
    FloatParse(Literal),
    UnknownInfixOp(Literal),
    UnknownPrefixOp(Literal),
    CannotAssignTo(Box<Expression>),
    CannotBindUsing(Box<Type>),
    CannotExport(Box<Statement>),
    IsNotHashable(Box<Type>),
    FileModuleError(io::Error),
    UnacceptableConst,
}

#[derive(Debug)]
pub struct ProgramParseError {
    all: Vec<ParserDiagnostic>,
}

impl Error for ParserDiagnostic {}
impl Display for ParserDiagnostic {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use ParserDiagnostic as E;
        f.write_str(&match self {
            E::SyntaxError { expected, got } => {
                format!("Syntax Error: Expected `{expected}`, but found `{got}` instead")
            }
            E::IsNotIdentifier(got) => {
                format!("Syntax Error: Expected `<identifier>`, but found `{got}` instead")
            }
            E::Undefined(lit) => format!("`{lit}` is not found in the current scope"),
            E::TypeMistake(lit) => format!("`{lit}` cannot be use as a type definition"),
            E::ExpressionMistake(tok) => {
                format!("Expected an expression but `{tok}` is not avaliable to create expressions")
            }
            E::IntegerParse(int_lit) => format!("`{int_lit}` can't parse into a integer value"),
            E::FloatParse(float_parse) => {
                format!("`{float_parse}` can't parse into a floating point number value")
            }
            E::UnknownInfixOp(op) => {
                format!("`{op}` cannot be used as an opeartor in infix expressions")
            }
            E::UnknownPrefixOp(op) => {
                format!("`{op}` cannot be used as an opeartor in prefix expressions")
            }
            E::CannotAssignTo(expr) => format!("Cannot assign a value to a `{expr}` expression"),
            E::UnacceptableConst => {
                "`const` keyword can only be used in binding statements".to_string()
            }
            E::CannotBindUsing(ty) => format!("Type `{ty}` cannot be used in binding statements"),
            E::CannotExport(stmt) => {
                format!("Only functions, constant bindings, types and type aliases can be exported but got `{stmt}`")
            }
            E::IsNotHashable(ty) => format!("Type `{ty}` cannot be hashed"),
            E::FileModuleError(fme) => fme.to_string(),
        })
    }
}

impl Error for ProgramParseError {}
impl Display for ProgramParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for e in &self.all {
            writeln!(f, "{e}")?;
        }

        Ok(())
    }
}

impl ProgramParseError {
    pub fn new<U: IntoIterator>(errors: U) -> Self
    where
        Vec<ParserDiagnostic>: FromIterator<U::Item>,
    {
        Self {
            all: errors.into_iter().collect(),
        }
    }
}