plum
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>>; |