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
03e5a61 1
use std::collections::BTreeMap;
03e5a61 2
03e5a61 3
#[derive(Debug, Clone, PartialEq)]
03e5a61 4
pub enum PlumType {
03e5a61 5
    TInt,
03e5a61 6
    TFloat,
03e5a61 7
    TBool,
03e5a61 8
    TStr,
0000000 9
    TByte,
0000000 10
    /// `[]Byte` — a fixed builtin, not a monomorphized generic. The checker
0000000 11
    /// only ever produces this for the exact source spelling `[]Byte`
0000000 12
    /// (see `plumTypeFromName`); there is no general `[]T` for other `T`.
0000000 13
    TByteSlice,
03e5a61 14
    TUnit,
03e5a61 15
    TVar(String),
03e5a61 16
    TFun(Vec<PlumType>, Box<PlumType>),
03e5a61 17
    TNamed(String),
d0981fb 18
    /// The type of a variadic parameter, e.g. `...Int` -> `TVariadic(TInt)`.
d0981fb 19
    /// Appears in exactly two places: as the trailing entry of a `TFun`'s
d0981fb 20
    /// param-types list (call-site arity/type checking), and as the type bound
d0981fb 21
    /// to the param's name inside the function body. Its only legal use inside
3d6f280 22
    /// a body is as a `for` loop's iterable — no other `unify`/`inferExpr` arm
d0981fb 23
    /// handles it, so any other use is a type error by construction.
d0981fb 24
    TVariadic(Box<PlumType>),
03e5a61 25
}
03e5a61 26
03e5a61 27
impl std::fmt::Display for PlumType {
03e5a61 28
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
03e5a61 29
        match self {
03e5a61 30
            PlumType::TInt => write!(f, "Int"),
03e5a61 31
            PlumType::TFloat => write!(f, "Float"),
03e5a61 32
            PlumType::TBool => write!(f, "Bool"),
03e5a61 33
            PlumType::TStr => write!(f, "Str"),
0000000 34
            PlumType::TByte => write!(f, "Byte"),
0000000 35
            PlumType::TByteSlice => write!(f, "[]Byte"),
03e5a61 36
            PlumType::TUnit => write!(f, "Unit"),
03e5a61 37
            PlumType::TVar(n) => write!(f, "{}", n),
03e5a61 38
            PlumType::TFun(ps, r) => {
03e5a61 39
                let ps_str: Vec<_> = ps.iter().map(|p| p.to_string()).collect();
03e5a61 40
                write!(f, "({}) -> {}", ps_str.join(", "), r)
03e5a61 41
            }
03e5a61 42
            PlumType::TNamed(n) => write!(f, "{}", n),
d0981fb 43
            PlumType::TVariadic(inner) => write!(f, "...{}", inner),
03e5a61 44
        }
03e5a61 45
    }
03e5a61 46
}
03e5a61 47
03e5a61 48
#[derive(Debug, Clone, PartialEq)]
03e5a61 49
pub struct TypeScheme {
03e5a61 50
    pub vars: Vec<String>,
03e5a61 51
    pub body: Box<PlumType>,
03e5a61 52
}
03e5a61 53
03e5a61 54
impl TypeScheme {
03e5a61 55
    pub fn mono(t: PlumType) -> Self {
03e5a61 56
        TypeScheme { vars: vec![], body: Box::new(t) }
03e5a61 57
    }
03e5a61 58
}
03e5a61 59
03e5a61 60
pub type TypeEnv = BTreeMap<String, TypeScheme>;
03e5a61 61
03e5a61 62
pub struct InferState {
03e5a61 63
    pub counter: u64,
03e5a61 64
}
03e5a61 65
03e5a61 66
impl InferState {
03e5a61 67
    pub fn new() -> Self {
03e5a61 68
        InferState { counter: 0 }
03e5a61 69
    }
03e5a61 70
3d6f280 71
    pub fn freshVar(&mut self) -> String {
03e5a61 72
        let name = format!("a{}", self.counter);
03e5a61 73
        self.counter += 1;
03e5a61 74
        name
03e5a61 75
    }
03e5a61 76
3d6f280 77
    pub fn freshType(&mut self) -> PlumType {
3d6f280 78
        PlumType::TVar(self.freshVar())
03e5a61 79
    }
03e5a61 80
}
03e5a61 81
03e5a61 82
#[derive(Debug, Clone)]
03e5a61 83
pub struct CheckError {
03e5a61 84
    pub message: String,
03e5a61 85
}
03e5a61 86
03e5a61 87
impl std::fmt::Display for CheckError {
03e5a61 88
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
03e5a61 89
        write!(f, "{}", self.message)
03e5a61 90
    }
03e5a61 91
}
03e5a61 92
03e5a61 93
pub type CheckResult<T> = Result<T, Vec<CheckError>>;