use serde::{Deserialize, Serialize};
use std::fmt;
use thiserror::Error;
pub mod inference;
pub mod value;
pub use value::Value;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Type {
Int,
Float,
Str,
Bool,
Bytes,
Unit,
List(Box<Type>),
Dict(Box<Type>, Box<Type>),
Optional(Box<Type>),
Promise(Box<Type>),
Result(Box<Type>, Box<Type>),
Function {
params: Vec<(String, Type)>,
return_type: Box<Type>,
},
TypeVar(u32),
Unknown,
}
impl Type {
pub fn is_assignable_to(&self, other: &Type) -> bool {
match (self, other) {
(t1, t2) if t1 == t2 => true,
(Type::Unknown, _) | (_, Type::Unknown) => true,
(Type::List(t1), Type::List(t2)) => t1.is_assignable_to(t2),
(Type::Optional(t1), Type::Optional(t2)) => t1.is_assignable_to(t2),
(Type::Promise(t1), Type::Promise(t2)) => t1.is_assignable_to(t2),
(Type::Result(ok1, err1), Type::Result(ok2, err2)) => {
ok1.is_assignable_to(ok2) && err1.is_assignable_to(err2)
}
(Type::Dict(k1, v1), Type::Dict(k2, v2)) => {
k1.is_assignable_to(k2) && v1.is_assignable_to(v2)
}
(
Type::Function {
params: p1,
return_type: r1,
},
Type::Function {
params: p2,
return_type: r2,
},
) => {
p1.len() == p2.len()
&& p1
.iter()
.zip(p2.iter())
.all(|((_, t1), (_, t2))| t2.is_assignable_to(t1))
&& r1.is_assignable_to(r2)
}
_ => false,
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::Int => write!(f, "int"),
Type::Float => write!(f, "float"),
Type::Str => write!(f, "str"),
Type::Bool => write!(f, "bool"),
Type::Bytes => write!(f, "bytes"),
Type::Unit => write!(f, "unit"),
Type::List(t) => write!(f, "list[{t}]"),
Type::Dict(k, v) => write!(f, "dict[{k}, {v}]"),
Type::Optional(t) => write!(f, "optional[{t}]"),
Type::Promise(t) => write!(f, "promise[{t}]"),
Type::Result(ok, err) => write!(f, "result[{ok}, {err}]"),
Type::Function {
params,
return_type,
} => {
write!(f, "(")?;
for (i, (name, typ)) in params.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{name}: {typ}")?;
}
write!(f, ") -> {return_type}")
}
Type::TypeVar(id) => write!(f, "T{id}"),
Type::Unknown => write!(f, "?"),
}
}
}
#[derive(Debug, Error)]
pub enum TypeError {
#[error("Type mismatch: expected {expected}, found {found}")]
TypeMismatch { expected: Type, found: Type },
#[error("Undefined variable: {0}")]
UndefinedVariable(String),
#[error("Cannot call non-function type: {0}")]
NotCallable(Type),
#[error("Wrong number of arguments: expected {expected}, found {found}")]
ArgumentCountMismatch { expected: usize, found: usize },
#[error("Cannot access attribute '{attr}' on type {typ}")]
AttributeError { attr: String, typ: Type },
#[error("Type inference failed: {0}")]
InferenceFailed(String),
}