t-ree 0.1.0

AST definitions for the T programming language
Documentation
/// Integer signedness.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Signedness {
    /// Signed integer.
    Signed,
    /// Unsigned integer.
    Unsigned,
}

/// Integer bit width.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IntWidth {
    /// 8-bit.
    W8,
    /// 16-bit.
    W16,
    /// 32-bit.
    W32,
    /// 64-bit.
    W64,
    /// 128-bit.
    W128,
    /// Platform-dependent (`size_t`).
    WSize,
}

impl IntWidth {
    /// Returns the size in bytes.
    pub fn byte_size(self) -> usize {
        match self {
            Self::W8 => 1,
            Self::W16 => 2,
            Self::W32 => 4,
            Self::W64 | Self::WSize => 8,
            Self::W128 => 16,
        }
    }

    /// Returns the size in bits.
    pub fn bit_size(self) -> usize {
        self.byte_size() * 8
    }
}

/// Float bit width.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FloatWidth {
    /// 32-bit (single precision).
    W32,
    /// 64-bit (double precision).
    W64,
}

impl FloatWidth {
    /// Returns the size in bytes.
    pub fn byte_size(self) -> usize {
        use FloatWidth::*;
        match self {
            W32 => 4,
            W64 => 8,
        }
    }
}

/// Pointer/reference mutability.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Mutability {
    /// Immutable/shared access.
    Shared,
    /// Mutable/exclusive access.
    Mutable,
}

/// Function type signature with parameter types and return type.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionSignature {
    /// Parameter types.
    pub parameters: Vec<Type>,
    /// Return type.
    pub return_type: Box<Type>,
}

/// A resolved type in the AST.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
    /// Diverging type (never returns).
    Never,
    /// Boolean.
    Bool,
    /// Integer with width and signedness.
    Int(IntWidth, Signedness),
    /// Floating-point with width.
    Float(FloatWidth),
    /// Pointer with mutability and pointee type.
    Pointer(Mutability, Box<Self>),
    /// Fixed-size array with element type and length.
    Array(Box<Self>, usize),
    /// SIMD vector with element type and lane count.
    Vector(Box<Self>, usize),
    /// Slice with mutability and element type.
    Slice(Mutability, Box<Self>),
    /// Tuple of types (product/AND type).
    Tuple(Vec<Self>),
    /// Enum of variant types (sum/OR type).
    Enum(Vec<Self>),
    /// Named/user-defined type.
    Named(String),
    /// Function pointer type.
    Function(FunctionSignature),
}

impl Type {
    /// Returns the unit type (empty tuple).
    pub fn unit() -> Self {
        Self::Tuple(Vec::new())
    }

    /// Returns true if this is the unit type.
    pub fn is_unit(&self) -> bool {
        matches!(self, Self::Tuple(fields) if fields.is_empty())
    }

    /// Returns true if this type matches the given primitive type name.
    pub fn matches_name(&self, name: &str) -> bool {
        match self {
            Self::Named(type_name) => type_name == name,
            Self::Bool => name == "bool",
            Self::Int(IntWidth::W8, Signedness::Signed) => name == "i8",
            Self::Int(IntWidth::W16, Signedness::Signed) => name == "i16",
            Self::Int(IntWidth::W32, Signedness::Signed) => name == "i32",
            Self::Int(IntWidth::W64, Signedness::Signed) => name == "i64",
            Self::Int(IntWidth::W128, Signedness::Signed) => name == "i128",
            Self::Int(IntWidth::W8, Signedness::Unsigned) => name == "u8",
            Self::Int(IntWidth::W16, Signedness::Unsigned) => name == "u16",
            Self::Int(IntWidth::W32, Signedness::Unsigned) => name == "u32",
            Self::Int(IntWidth::W64, Signedness::Unsigned) => name == "u64",
            Self::Int(IntWidth::W128, Signedness::Unsigned) => name == "u128",
            Self::Int(IntWidth::WSize, Signedness::Signed) => name == "isize",
            Self::Int(IntWidth::WSize, Signedness::Unsigned) => name == "usize",
            Self::Float(FloatWidth::W32) => name == "f32",
            Self::Float(FloatWidth::W64) => name == "f64",
            _ => false,
        }
    }
}

impl std::fmt::Display for Type {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Never => write!(f, "never"),
            Self::Bool => write!(f, "bool"),
            Self::Int(IntWidth::W8, Signedness::Signed) => write!(f, "i8"),
            Self::Int(IntWidth::W16, Signedness::Signed) => write!(f, "i16"),
            Self::Int(IntWidth::W32, Signedness::Signed) => write!(f, "i32"),
            Self::Int(IntWidth::W64, Signedness::Signed) => write!(f, "i64"),
            Self::Int(IntWidth::W128, Signedness::Signed) => write!(f, "i128"),
            Self::Int(IntWidth::WSize, Signedness::Signed) => write!(f, "isize"),
            Self::Int(IntWidth::W8, Signedness::Unsigned) => write!(f, "u8"),
            Self::Int(IntWidth::W16, Signedness::Unsigned) => write!(f, "u16"),
            Self::Int(IntWidth::W32, Signedness::Unsigned) => write!(f, "u32"),
            Self::Int(IntWidth::W64, Signedness::Unsigned) => write!(f, "u64"),
            Self::Int(IntWidth::W128, Signedness::Unsigned) => write!(f, "u128"),
            Self::Int(IntWidth::WSize, Signedness::Unsigned) => write!(f, "usize"),
            Self::Float(FloatWidth::W32) => write!(f, "f32"),
            Self::Float(FloatWidth::W64) => write!(f, "f64"),
            Self::Pointer(Mutability::Shared, inner) => write!(f, "&{inner}"),
            Self::Pointer(Mutability::Mutable, inner) => write!(f, "|{inner}"),
            Self::Array(inner, length) => write!(f, "[{inner}]{length}"),
            Self::Vector(inner, count) => write!(f, "{{{inner}}}{count}"),
            Self::Named(name) => write!(f, "{name}"),
            Self::Tuple(fields) => {
                for (index, field) in fields.iter().enumerate() {
                    if index > 0 {
                        write!(f, " & ")?;
                    }
                    write!(f, "{field}")?;
                }
                Ok(())
            }
            Self::Enum(variants) => {
                for (index, variant) in variants.iter().enumerate() {
                    if index > 0 {
                        write!(f, " | ")?;
                    }
                    write!(f, "{variant}")?;
                }
                Ok(())
            }
            Self::Slice(_, inner) => write!(f, "[{inner}]"),
            Self::Function(signature) => {
                write!(f, "fn(")?;
                for (index, parameter) in signature.parameters.iter().enumerate() {
                    if index > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{parameter}")?;
                }
                write!(f, ") -> {}", signature.return_type)
            }
        }
    }
}