use std::ops::Deref;
use arcstr::{literal, ArcStr};
use imbl::Vector;
use serde::{Deserialize, Serialize};
use crate::{model::{Graph, NodeRef, SId, PROTOTYPE_TYPE_ATTR, SELF_STR_KEYWORD, SUPER_STR_KEYWORD}, parser::types::parse_type_complete, runtime::{Units, Val}};
const NULL: ArcStr = literal!("null");
const VOID: ArcStr = literal!("void");
const UNKNOWN: ArcStr = literal!("unknown");
const MAP: ArcStr = literal!("map");
const SET: ArcStr = literal!("set");
const LIST: ArcStr = literal!("list");
const BOOL: ArcStr = literal!("bool");
const BLOB: ArcStr = literal!("blob");
const FUNC: ArcStr = literal!("fn");
pub(super) const DATA: ArcStr = literal!("data");
pub(super) const OBJ: ArcStr = literal!("obj");
const VER: ArcStr = literal!("ver");
const STR: ArcStr = literal!("str");
const PROMPT: ArcStr = literal!("prompt");
const INT: ArcStr = literal!("int");
const FLOAT: ArcStr = literal!("float");
#[derive(Debug, Clone, Deserialize, Serialize, Default, Hash)]
pub enum Type {
#[default]
Void,
Null,
NotNull(Box<Self>),
Promise(Box<Self>),
Bool,
Num(NumT),
Str,
Ver,
Prompt,
Obj(SId), Fn,
Data(ArcStr),
Blob,
List,
Tup(Vector<Self>),
Map,
Set,
Unknown,
Union(Vector<Self>),
}
impl PartialEq for Type {
fn eq(&self, other: &Self) -> bool {
match other {
Self::Null => return !self.exp_not_null(),
Self::Unknown => return true,
Self::Union(types) => {
match self {
Self::Union(otypes) => {
for ty in types {
for oty in otypes {
if ty.eq(oty) {
return true;
}
}
}
return false;
},
sf => {
for ty in types {
if ty.eq(sf) {
return true;
}
}
return false;
}
}
},
Self::Promise(ty) => {
match self {
Self::Promise(oty) => return ty == oty,
_ => return **ty == *self,
}
},
_ => {}
}
match self {
Self::Union(types) => {
match other {
Self::Union(otypes) => {
for ty in types {
for oty in otypes {
if ty.eq(oty) {
return true;
}
}
}
return false;
},
other => {
for ty in types {
if ty.eq(other) {
return true;
}
}
return false;
}
}
},
Self::Void => {
match other {
Self::Void => true,
_ => false,
}
},
Self::Bool => {
match other {
Self::Bool => true,
_ => false,
}
},
Self::Num(t) => {
match other {
Self::Num(ot) => t.eq(ot),
_ => false,
}
},
Self::Prompt => {
match other {
Self::Prompt => true,
_ => false,
}
},
Self::Str => {
match other {
Self::Str => true,
_ => false,
}
},
Self::Ver => {
match other {
Self::Ver => true,
_ => false,
}
},
Self::Obj(t) => {
match other {
Self::Obj(ot) => t.eq(ot),
_ => false,
}
},
Self::Fn => {
match other {
Self::Fn => true,
_ => false,
}
},
Self::Data(t) => {
match other {
Self::Data(ot) => t.eq(ot),
_ => false, }
},
Self::List => {
match other {
Self::List => true,
_ => false,
}
},
Self::Map => {
match other {
Self::Map => true,
_ => false,
}
},
Self::Set => {
match other {
Self::Set => true,
_ => false,
}
},
Self::Tup(types) => {
match other {
Self::Tup(otypes) => types.eq(otypes),
_ => false,
}
},
Self::Blob => {
match other {
Self::Blob => true,
_ => false,
}
},
Self::Promise(ty) => {
match other {
Self::Promise(oty) => ty == oty,
_ => **ty == *other,
}
},
Self::Null => !other.exp_not_null(),
Self::NotNull(t) => t.deref().eq(other),
Self::Unknown => true,
}
}
}
impl Eq for Type {}
impl Type {
#[inline]
pub fn empty(&self) -> bool {
match self {
Self::Null |
Self::Void => true,
_ => false,
}
}
#[inline]
pub fn null(&self) -> bool {
match self {
Self::Null => true,
_ => false,
}
}
#[inline]
pub fn exp_not_null(&self) -> bool {
match self {
Self::NotNull(_) => true,
_ => false,
}
}
pub fn obj_to_proto(&mut self, graph: &Graph, mut context: Option<NodeRef>) {
match &mut *self {
Self::Union(types) => {
for ty in types { ty.obj_to_proto(graph, context.clone()); }
},
Self::Promise(ctype) => {
ctype.obj_to_proto(graph, context);
},
Self::NotNull(ctype) => {
ctype.obj_to_proto(graph, context);
},
Self::Tup(types) => {
for ty in types { ty.obj_to_proto(graph, context.clone()); }
},
Self::Obj(name_or_id) => {
if !name_or_id.node_exists(graph) { let mut path = name_or_id.as_ref().to_string();
if path.contains('.') {
if !path.starts_with(SELF_STR_KEYWORD.as_str()) && !path.starts_with(SUPER_STR_KEYWORD.as_str()) {
context = None;
}
let mut split = path.split('.').collect::<Vec<_>>();
let typename = split.pop().unwrap();
if let Some(node) = graph.find_node_named(&split.join("."), context.clone()) {
context = Some(node);
path = typename.to_string();
}
}
if context.is_none() { context = graph.main_root(); }
if let Some(proto_id) = graph.find_type(&path, context) {
*name_or_id = proto_id;
}
}
},
_ => {}
}
}
pub fn type_of(&self) -> ArcStr {
match self {
Self::Union(types) => {
let mut geo = String::default();
for ty in types {
if geo.len() < 1 {
geo.push_str(&ty.type_of());
} else {
geo.push_str(&format!(" | {}", ty.type_of()));
}
}
geo.into()
},
Self::Unknown => UNKNOWN,
Self::Map => MAP,
Self::Set => SET,
Self::List => LIST,
Self::Bool => BOOL,
Self::Blob => BLOB,
Self::Fn => FUNC,
Self::Data(tname) => {
let dta = DATA;
if tname == &dta {
return dta;
}
format!("Data<{}>", tname).into()
},
Self::Null => NULL,
Self::NotNull(t) => t.type_of(),
Self::Num(num) => num.type_of(),
Self::Ver => VER,
Self::Str => STR,
Self::Prompt => PROMPT,
Self::Tup(vals) => {
let mut res = "(".to_string();
for i in 0..vals.len() {
let v = &vals[i];
let type_of = v.type_of();
if i < vals.len() - 1 {
res.push_str(&format!("{}, ", type_of));
} else {
res.push_str(&type_of);
}
}
res.push_str(")");
res.into()
},
Self::Void => VOID,
Self::Obj(ctype) => ctype.as_ref().into(),
Self::Promise(ty) => format!("Promise<{}>", ty.type_of()).into(),
}
}
pub fn rt_type_of(&self, graph: &Graph) -> ArcStr {
match self {
Self::Union(types) => {
let mut geo = String::default();
for ty in types {
if geo.len() < 1 {
geo.push_str(&ty.rt_type_of(graph));
} else {
geo.push_str(&format!(" | {}", ty.rt_type_of(graph)));
}
}
geo.into()
},
Self::Unknown => UNKNOWN,
Self::Map => MAP,
Self::Set => SET,
Self::List => LIST,
Self::Bool => BOOL,
Self::Blob => BLOB,
Self::Fn => FUNC,
Self::Data(tname) => {
let dta = DATA;
if tname == &dta {
return dta;
}
format!("Data<{}>", tname).into()
},
Self::Null => NULL,
Self::NotNull(t) => t.rt_type_of(graph),
Self::Num(num) => num.type_of(),
Self::Ver => VER,
Self::Str => STR,
Self::Prompt => PROMPT,
Self::Tup(vals) => {
let mut res = "(".to_string();
for i in 0..vals.len() {
let v = &vals[i];
let type_of = v.rt_type_of(graph);
if i < vals.len() - 1 {
res.push_str(&format!("{}, ", type_of));
} else {
res.push_str(&type_of);
}
}
res.push_str(")");
res.into()
},
Self::Void => VOID,
Self::Obj(ctype) => {
if let Some(node) = ctype.node(graph) {
if let Some(type_attr) = node.attributes.get(PROTOTYPE_TYPE_ATTR.as_str()) {
match type_attr {
Val::Str(name) => {
return name.clone();
},
_ => {
return node.name.as_ref().into();
}
}
}
}
ctype.as_ref().into()
},
Self::Promise(ty) => format!("Promise<{}>", ty.rt_type_of(graph)).into(),
}
}
pub fn md_type_of(&self, graph: &Graph) -> String {
self.rt_type_of(graph).replace("<", "\\<")
}
pub fn gen_lib_name(&self) -> ArcStr {
match self {
Self::Unknown |
Self::Null |
Self::Union(_) |
Self::Void => literal!("Empty"),
Self::List => literal!("List"),
Self::Map => literal!("Map"),
Self::Set => literal!("Set"),
Self::Blob => literal!("Blob"),
Self::Bool => literal!("Bool"),
Self::Fn => literal!("Fn"),
Self::Num(_) => literal!("Num"),
Self::Data(_) => literal!("Data"),
Self::Str => literal!("Str"),
Self::Prompt => literal!("Prompt"),
Self::Obj(_) => literal!("Obj"),
Self::Promise(_) => literal!("Promise"),
Self::Ver => literal!("Ver"),
Self::Tup(_) => literal!("Tup"),
Self::NotNull(t) => t.gen_lib_name(),
}
}
}
impl<T: AsRef<str>> From<T> for Type {
fn from(value: T) -> Self {
parse_type_complete(value.as_ref()).expect(&format!("failed to parse stof type string '{}' into a valid Type", value.as_ref()))
}
}
impl ToString for Type {
fn to_string(&self) -> String {
self.type_of().to_string()
}
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, Hash)]
pub enum NumT {
Int,
Float,
Units(Units),
}
impl PartialEq for NumT {
fn eq(&self, other: &Self) -> bool {
match self {
Self::Int => {
match other {
Self::Int => true,
_ => false,
}
},
Self::Float => {
match other {
Self::Float => true,
_ => false,
}
},
Self::Units(units) => {
match other {
Self::Float => true,
Self::Units(ounits) => {
units == ounits
},
_ => false,
}
},
}
}
}
impl Eq for NumT {}
impl NumT {
pub fn type_of(&self) -> ArcStr {
match self {
Self::Float => FLOAT,
Self::Int => INT,
Self::Units(units) => units.to_string(),
}
}
}