plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


plum-checker/src/types.rs
use std::collections::BTreeMap;

#[derive(Debug, Clone, PartialEq)]
pub enum PlumType {
    TInt,
    TFloat,
    TBool,
    TStr,
    TByte,
    /// `[]Byte` — a fixed builtin, not a monomorphized generic. The checker
    /// only ever produces this for the exact source spelling `[]Byte`
    /// (see `plumTypeFromName`); there is no general `[]T` for other `T`.
    TByteSlice,
    TUnit,
    TVar(String),
    TFun(Vec<PlumType>, Box<PlumType>),
    TNamed(String),
    /// The type of a variadic parameter, e.g. `...Int` -> `TVariadic(TInt)`.
    /// Appears in exactly two places: as the trailing entry of a `TFun`'s
    /// param-types list (call-site arity/type checking), and as the type bound
    /// to the param's name inside the function body. Its only legal use inside
    /// a body is as a `for` loop's iterable — no other `unify`/`inferExpr` arm
    /// handles it, so any other use is a type error by construction.
    TVariadic(Box<PlumType>),
}

impl std::fmt::Display for PlumType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            PlumType::TInt => write!(f, "Int"),
            PlumType::TFloat => write!(f, "Float"),
            PlumType::TBool => write!(f, "Bool"),
            PlumType::TStr => write!(f, "Str"),
            PlumType::TByte => write!(f, "Byte"),
            PlumType::TByteSlice => write!(f, "[]Byte"),
            PlumType::TUnit => write!(f, "Unit"),
            PlumType::TVar(n) => write!(f, "{}", n),
            PlumType::TFun(ps, r) => {
                let ps_str: Vec<_> = ps.iter().map(|p| p.to_string()).collect();
                write!(f, "({}) -> {}", ps_str.join(", "), r)
            }
            PlumType::TNamed(n) => write!(f, "{}", n),
            PlumType::TVariadic(inner) => write!(f, "...{}", inner),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct TypeScheme {
    pub vars: Vec<String>,
    pub body: Box<PlumType>,
}

impl TypeScheme {
    pub fn mono(t: PlumType) -> Self {
        TypeScheme { vars: vec![], body: Box::new(t) }
    }
}

pub type TypeEnv = BTreeMap<String, TypeScheme>;

pub struct InferState {
    pub counter: u64,
}

impl InferState {
    pub fn new() -> Self {
        InferState { counter: 0 }
    }

    pub fn freshVar(&mut self) -> String {
        let name = format!("a{}", self.counter);
        self.counter += 1;
        name
    }

    pub fn freshType(&mut self) -> PlumType {
        PlumType::TVar(self.freshVar())
    }
}

#[derive(Debug, Clone)]
pub struct CheckError {
    pub message: String,
}

impl std::fmt::Display for CheckError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.message)
    }
}

pub type CheckResult<T> = Result<T, Vec<CheckError>>;