#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SideEffect {
Yield(Box<Type>),
}
impl std::fmt::Display for SideEffect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SideEffect::Yield(ty) => write!(f, "Yield {}", ty),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Type {
Int,
Float,
Bool,
String,
Symbol,
Channel,
Quotation(Box<Effect>),
Closure {
effect: Box<Effect>,
captures: Vec<Type>,
},
Union(String),
Var(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantFieldInfo {
pub name: String,
pub field_type: Type,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantInfo {
pub name: String,
pub fields: Vec<VariantFieldInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnionTypeInfo {
pub name: String,
pub variants: Vec<VariantInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum StackType {
Empty,
Cons {
rest: Box<StackType>,
top: Type,
},
RowVar(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Effect {
pub inputs: StackType,
pub outputs: StackType,
pub effects: Vec<SideEffect>,
}
impl StackType {
pub fn empty() -> Self {
StackType::Empty
}
pub fn singleton(ty: Type) -> Self {
StackType::Cons {
rest: Box::new(StackType::Empty),
top: ty,
}
}
pub fn push(self, ty: Type) -> Self {
StackType::Cons {
rest: Box::new(self),
top: ty,
}
}
pub fn from_vec(types: Vec<Type>) -> Self {
types
.into_iter()
.fold(StackType::Empty, |stack, ty| stack.push(ty))
}
pub fn pop(self) -> Option<(StackType, Type)> {
match self {
StackType::Cons { rest, top } => Some((*rest, top)),
_ => None,
}
}
}
impl Effect {
pub fn new(inputs: StackType, outputs: StackType) -> Self {
Effect {
inputs,
outputs,
effects: Vec::new(),
}
}
pub fn with_effects(inputs: StackType, outputs: StackType, effects: Vec<SideEffect>) -> Self {
Effect {
inputs,
outputs,
effects,
}
}
pub fn is_pure(&self) -> bool {
self.effects.is_empty()
}
pub fn has_yield(&self) -> bool {
self.effects
.iter()
.any(|e| matches!(e, SideEffect::Yield(_)))
}
}
impl std::fmt::Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Int => write!(f, "Int"),
Type::Float => write!(f, "Float"),
Type::Bool => write!(f, "Bool"),
Type::String => write!(f, "String"),
Type::Symbol => write!(f, "Symbol"),
Type::Channel => write!(f, "Channel"),
Type::Quotation(effect) => write!(f, "[{}]", effect),
Type::Closure { effect, captures } => {
let cap_str: Vec<_> = captures.iter().map(|t| format!("{}", t)).collect();
write!(f, "Closure[{}, captures=({})]", effect, cap_str.join(", "))
}
Type::Union(name) => write!(f, "{}", name),
Type::Var(name) => write!(f, "{}", name),
}
}
}
impl std::fmt::Display for StackType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StackType::Empty => write!(f, "()"),
StackType::RowVar(name) => write!(f, "..{}", name),
StackType::Cons { rest, top } => {
let mut types = vec![format!("{}", top)];
let mut current = rest.as_ref();
loop {
match current {
StackType::Empty => break,
StackType::RowVar(name) => {
types.push(format!("..{}", name));
break;
}
StackType::Cons { rest, top } => {
types.push(format!("{}", top));
current = rest;
}
}
}
types.reverse();
write!(f, "({})", types.join(" "))
}
}
}
}
impl std::fmt::Display for Effect {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.effects.is_empty() {
write!(f, "{} -- {}", self.inputs, self.outputs)
} else {
let effects_str: Vec<_> = self.effects.iter().map(|e| format!("{}", e)).collect();
write!(
f,
"{} -- {} | {}",
self.inputs,
self.outputs,
effects_str.join(" ")
)
}
}
}
#[cfg(test)]
mod tests;