use thiserror::Error;

use crate::sema::types::SemaType;

#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum SemaError {
    #[error("variable `{0}` not found")]
    VariableNotFound(String),
    #[error("variable `{0}` has already been defined")]
    VariableHasBeenDefined(String),
    #[error("function `{0}` not found")]
    FunctionNotFound(String),
    #[error("function `{0}` has already been defined")]
    FunctionHasBeenDefined(String),
    #[error("incompatible operands: {0} and {1}")]
    IncompatiableOperand(SemaType, SemaType),
    #[error("invalid operand type: {0}")]
    InvalidOperand(SemaType),
    #[error("too few arguments: expected {0}, got {1}")]
    TooFewArguments(usize, usize),
    #[error("too many arguments: expected {0}, got {1}")]
    TooManyArguments(usize, usize),
    #[error("type mismatch, expected {0}, got {1}")]
    TypeMismatch(SemaType, SemaType),
    #[error("invalid assignment target")]
    InvalidAssignmentTarget,
    #[error("break statement outside of loop")]
    BreakOutsideLoop,
    #[error("continue statement outside of loop")]
    ContinueOutsideLoop,
    #[error("invalid parameter type: {0}")]
    InvalidParameterType(SemaType),
    #[error("return expression on void function")]
    ReturnExpressionOnVoidFunction,
    #[error("array dimension must be a positive integer literal")]
    InvalidArrayDimension,
    #[error("subscripted value is not an array or pointer")]
    NotSubscriptable,
    #[error("initializer element is not constant")]
    InitializerNotConstant,
}
