use crate::typing::{BinaryOperator, Identifier, ModulePath, Type, TypingContext}; use super::UnaryOperator; #[derive(Debug)] pub struct TypeError { file: Option, module: ModulePath, function: Option, kind: TypeErrorKind, } impl std::fmt::Display for TypeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("Error\n")?; if let Some(path) = &self.file { f.write_fmt(format_args!(" in file {}\n", path.display()))?; } f.write_fmt(format_args!(" in module {}\n", self.module))?; if let Some(name) = &self.function { f.write_fmt(format_args!(" in function {}\n", name))?; } f.write_fmt(format_args!("{:#?}", self.kind))?; Ok(()) } } #[derive(Default)] pub struct TypeErrorBuilder { file: Option, module: Option, function: Option, kind: Option, } impl TypeError { pub fn builder() -> TypeErrorBuilder { TypeErrorBuilder::default() } } impl TypeErrorBuilder { pub fn context(mut self, ctx: &TypingContext) -> Self { self.file = ctx.file.clone(); self.module = Some(ctx.module.clone()); self.function = ctx.function.clone(); self } pub fn kind(mut self, kind: TypeErrorKind) -> Self { self.kind = Some(kind); self } pub fn build(self) -> TypeError { TypeError { file: self.file, module: self.module.expect("TypeError builder is missing module"), function: self.function, kind: self.kind.expect("TypeError builder is missing kind"), } } } #[derive(Debug)] pub enum TypeErrorKind { InvalidBinaryOperator { operator: BinaryOperator, lht: Type, rht: Type, }, BlockTypeDoesNotMatchFunctionType { block_type: Type, function_type: Type, }, ReturnTypeDoesNotMatchFunctionType { function_type: Type, return_type: Type, }, UnknownIdentifier { identifier: String, }, AssignmentMismatch { lht: Type, rht: Type, }, AssignUndeclared, VariableRedeclaration, ReturnStatementsMismatch, UnknownFunctionCalled(Identifier), WrongFunctionArguments, ConditionIsNotBool, IfElseMismatch, InvalidUnaryOperator { operator: UnaryOperator, inner: Type, }, }