use std::{
collections::HashMap,
fmt::Display,
hash::{DefaultHasher, Hash, Hasher},
rc::Rc,
};
use crate::{
Expression,
expressions::FunctionParameter,
types::{FunctionParameterType, Type, TypeVarId},
};
mod environment;
mod heap;
pub mod module;
pub use environment::*;
pub use heap::*;
pub use module::*;
pub type HashKey = u64;
pub type HashPair = (Addr, Addr);
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Int(i64),
Char(char),
String(Rc<String>),
Float(f64),
Boolean(bool),
Type(Type),
Pointer(Addr),
Array(Vec<Addr>),
HashMap(HashMap<HashKey, HashPair>),
Null,
Function(Rc<Function>),
}
macro_rules! hash {
( $v: expr ) => {{
let mut hasher = DefaultHasher::new();
$v.hash(&mut hasher);
hasher.finish()
}};
}
impl Value {
pub const TRUE: Self = Value::Boolean(true);
pub const FALSE: Self = Value::Boolean(false);
pub const NULL: Self = Value::Null;
pub fn r#type(&self, heap: &Heap) -> Type {
use Value as O;
match self {
O::Boolean(_) => Type::Bool,
O::Char(_) => Type::Char,
O::Int(_) => Type::Int,
O::Float(_) => Type::Float,
O::Null => Type::Null,
O::String(_) => Type::String,
O::Array(items) => Type::Array(
items
.first()
.map(|i| match i.read_from(heap) {
Some(o) => o.r#type(heap),
None => Type::Unknown,
})
.unwrap_or(Type::Unknown)
.into(),
),
Value::HashMap(hm) => {
let (k, v) = hm
.values()
.next()
.map(|(k, v)| {
(
match k.read_from(heap) {
Some(ko) => ko.r#type(heap),
None => Type::Unknown,
},
match v.read_from(heap) {
Some(vo) => vo.r#type(heap),
None => Type::Unknown,
},
)
})
.unwrap_or((Type::Unknown, Type::Unknown));
Type::HashMap {
key: k.into(),
value: v.into(),
}
}
O::Type(t) => Type::AsValue(t.clone().into()),
O::Pointer(t) => match t.read_from(heap) {
Some(o) => o.r#type(heap),
None => Type::Unknown,
},
O::Function(func) => Type::Function {
parameters: func
.parameters
.iter()
.map(|param| FunctionParameterType {
is_constant: param.is_constant,
ty: param.type_def.clone(),
})
.collect(),
return_type: Box::new(func.return_type.clone()),
generics: func.generics.clone(),
},
}
}
pub fn hash_key(&self) -> Option<HashKey> {
Some(match self {
Value::Boolean(v) => hash!(v),
Value::Int(v) => hash!(v),
Value::String(v) => hash!(v),
Value::Char(v) => hash!(v),
_ => return None,
})
}
pub fn new_function(
parameters: Vec<FunctionParameter>,
return_type: Type,
body: Expression,
env: FunctionEnvironment,
generics: Vec<TypeVarId>,
) -> Rc<Function> {
Rc::new(Function {
parameters,
return_type,
body,
env,
generics,
})
}
pub fn is_true(&self) -> bool {
Value::TRUE == *self
}
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
}
#[derive(Debug, PartialEq)]
pub struct FunctionEnvironment {
pub items: EnvScope,
}
#[derive(Debug, PartialEq)]
pub struct Function {
pub parameters: Vec<FunctionParameter>,
pub return_type: Type,
pub body: Expression,
pub env: FunctionEnvironment,
pub generics: Vec<TypeVarId>,
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let return_type = &self.return_type;
let body = &self.body;
let parameters = &self
.parameters
.iter()
.map(|param| {
format!(
"{}{} {}",
if param.is_constant { "const " } else { "" },
param.type_def,
param.name
)
})
.collect::<Vec<_>>()
.join("\x1b[0m, ");
let generics = if self.generics.is_empty() {
"".to_string()
} else {
format!(
"[{}]",
self.generics
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
)
};
write!(f, "fn{generics}({parameters}) -> {return_type}: {body}")
}
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Value as O;
f.write_str(&match self {
O::Boolean(val) => val.to_string(),
O::Int(val) => val.to_string(),
O::Char(val) => val.to_string(),
O::Float(val) => val.to_string(),
O::String(val) => val.to_string(),
O::Null => "null".to_string(),
O::Type(ty) => ty.to_string(),
O::Pointer(addr) => format!("<{addr:?}>"),
O::Function(func) => func.to_string(),
O::Array(items) => format!(
"[{}]",
items
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
),
O::HashMap(hm) => format!("#{{ {} }}", {
hm.values()
.map(|(k, v)| format!("{k}: {v}"))
.collect::<Vec<_>>()
.join(", ")
}),
})
}
}
macro_rules! impl_from {
( $ty: ty, $wrapper: ident ) => {
impl From<$ty> for Value {
fn from(value: $ty) -> Self {
Value::$wrapper(value.into())
}
}
};
}
impl_from!(i64, Int);
impl_from!(f64, Float);
impl_from!(char, Char);
impl_from!(String, String);
impl From<bool> for Value {
fn from(value: bool) -> Self {
match value {
true => Value::TRUE,
false => Value::FALSE,
}
}
}