plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
03e5a61
— Peter John
2026-07-19T19:11:09+05:30
feat(plum-checker): add type definitions
- plum-checker/src/types.rs +78 -1
- plum-checker/tests/checker_tests.rs +18 -0
plum-checker/src/types.rs
CHANGED
|
@@ -1 +1,78 @@
|
|
|
1
|
+
use std::collections::BTreeMap;
|
|
2
|
+
|
|
3
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
4
|
+
pub enum PlumType {
|
|
5
|
+
TInt,
|
|
6
|
+
TFloat,
|
|
7
|
+
TBool,
|
|
8
|
+
TStr,
|
|
9
|
+
TUnit,
|
|
10
|
+
TVar(String),
|
|
11
|
+
TFun(Vec<PlumType>, Box<PlumType>),
|
|
12
|
+
TNamed(String),
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl std::fmt::Display for PlumType {
|
|
16
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
17
|
+
match self {
|
|
18
|
+
PlumType::TInt => write!(f, "Int"),
|
|
19
|
+
PlumType::TFloat => write!(f, "Float"),
|
|
20
|
+
PlumType::TBool => write!(f, "Bool"),
|
|
21
|
+
PlumType::TStr => write!(f, "Str"),
|
|
22
|
+
PlumType::TUnit => write!(f, "Unit"),
|
|
23
|
+
PlumType::TVar(n) => write!(f, "{}", n),
|
|
24
|
+
PlumType::TFun(ps, r) => {
|
|
25
|
+
let ps_str: Vec<_> = ps.iter().map(|p| p.to_string()).collect();
|
|
26
|
+
write!(f, "({}) -> {}", ps_str.join(", "), r)
|
|
27
|
+
}
|
|
28
|
+
PlumType::TNamed(n) => write!(f, "{}", n),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
1
|
-
|
|
34
|
+
pub struct TypeScheme {
|
|
35
|
+
pub vars: Vec<String>,
|
|
36
|
+
pub body: Box<PlumType>,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
impl TypeScheme {
|
|
40
|
+
pub fn mono(t: PlumType) -> Self {
|
|
41
|
+
TypeScheme { vars: vec![], body: Box::new(t) }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub type TypeEnv = BTreeMap<String, TypeScheme>;
|
|
46
|
+
|
|
47
|
+
pub struct InferState {
|
|
48
|
+
pub counter: u64,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
impl InferState {
|
|
52
|
+
pub fn new() -> Self {
|
|
53
|
+
InferState { counter: 0 }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn fresh_var(&mut self) -> String {
|
|
57
|
+
let name = format!("a{}", self.counter);
|
|
58
|
+
self.counter += 1;
|
|
59
|
+
name
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn fresh_type(&mut self) -> PlumType {
|
|
63
|
+
PlumType::TVar(self.fresh_var())
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#[derive(Debug, Clone)]
|
|
68
|
+
pub struct CheckError {
|
|
69
|
+
pub message: String,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
impl std::fmt::Display for CheckError {
|
|
73
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
74
|
+
write!(f, "{}", self.message)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pub type CheckResult<T> = Result<T, Vec<CheckError>>;
|
plum-checker/tests/checker_tests.rs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
use plum_checker::types::*;
|
|
2
|
+
|
|
3
|
+
#[test]
|
|
4
|
+
fn fresh_vars_are_unique() {
|
|
5
|
+
let mut state = InferState::new();
|
|
6
|
+
let a = state.fresh_var();
|
|
7
|
+
let b = state.fresh_var();
|
|
8
|
+
assert_ne!(a, b);
|
|
9
|
+
assert_eq!(a, "a0");
|
|
10
|
+
assert_eq!(b, "a1");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#[test]
|
|
14
|
+
fn mono_scheme() {
|
|
15
|
+
let scheme = TypeScheme::mono(PlumType::TInt);
|
|
16
|
+
assert!(scheme.vars.is_empty());
|
|
17
|
+
assert_eq!(*scheme.body, PlumType::TInt);
|
|
18
|
+
}
|