mod collect;
mod members;
mod templates;
mod threads;
use std::collections::HashMap;
use crate::ast::{self, Method};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct TypeKey {
pub name: String,
pub arity: usize,
}
impl TypeKey {
pub fn new(name: impl Into<String>, arity: usize) -> Self {
TypeKey {
name: name.into(),
arity,
}
}
pub fn of_written(t: &ast::Type) -> Option<Self> {
match &t.kind {
ast::TypeKind::Path { path, args } => {
Some(TypeKey::new(path.last()?.text.clone(), args.len()))
}
_ => None,
}
}
}
impl OwnType {
pub fn shared(&self) -> bool {
self.record || (self.heap && self.readonly_all)
}
}
#[derive(Default)]
pub(crate) struct OwnType {
pub values: HashMap<String, ast::Type>,
pub methods: HashMap<String, Vec<Method>>,
pub components: Vec<String>,
pub cases: Vec<String>,
pub bases: Vec<ast::Type>,
pub interface: bool,
pub is_abstract: bool,
pub heap: bool,
pub readonly: Vec<String>,
pub readonly_all: bool,
pub record: bool,
pub content: Option<String>,
pub ctor: Vec<ast::Param>,
pub ctors: Vec<Vec<ast::Param>>,
pub generics: Vec<String>,
pub variance: Vec<Option<ast::Variance>>,
pub is_enum: bool,
pub variants: HashMap<String, Vec<ast::Param>>,
pub indexers: Vec<Indexer>,
pub delegate: Option<Method>,
pub operators: Vec<ast::Operator>,
pub threads: Option<String>,
pub stored: Vec<String>,
pub statics: Vec<String>,
pub thread_statics: Vec<String>,
pub static_methods: Vec<String>,
pub crossings: HashMap<String, Vec<Vec<(String, String)>>>,
pub wheres: Vec<ast::Where>,
pub templates: HashMap<String, Vec<Option<String>>>,
pub ctor_crossings: Vec<Vec<(String, String)>>,
pub required: Vec<String>,
pub synced: Vec<String>,
pub ctor_sets_required: Vec<bool>,
}
#[derive(Clone)]
pub(crate) struct Indexer {
pub get: Method,
pub settable: bool,
}
#[derive(Default)]
pub(crate) struct OwnTypes {
types: HashMap<TypeKey, OwnType>,
pub units: Vec<String>,
pub methods: HashMap<String, Vec<Method>>,
pub sides: HashMap<String, crate::index::Side>,
pub values: HashMap<String, ast::Type>,
pub extended: HashMap<String, OwnType>,
pub extension_methods: HashMap<String, Vec<(TypeKey, Method)>>,
pub namespaces: HashMap<String, Vec<String>>,
pub usings: HashMap<String, Vec<Vec<String>>>,
current: Vec<String>,
current_usings: Vec<Vec<String>>,
types_only: bool,
}
impl OwnTypes {
pub fn get(&self, name: &str, arity: usize) -> Option<&OwnType> {
self.types.get(&TypeKey::new(name, arity))
}
pub fn of_key(&self, key: &TypeKey) -> Option<&OwnType> {
self.types.get(key)
}
pub fn named(&self, name: &str) -> Option<(&TypeKey, &OwnType)> {
self.types
.iter()
.filter(|(k, _)| k.name == name)
.min_by_key(|(k, _)| k.arity)
}
pub fn has(&self, name: &str) -> bool {
self.named(name).is_some()
}
pub fn all(&self) -> impl Iterator<Item = (&TypeKey, &OwnType)> {
self.types.iter()
}
pub fn lineage(&self, key: &TypeKey) -> Vec<TypeKey> {
let mut out = vec![key.clone()];
let mut i = 0;
while let Some(at) = out.get(i) {
let bases: Vec<TypeKey> = self
.types
.get(at)
.map(|t| t.bases.iter().filter_map(TypeKey::of_written).collect())
.unwrap_or_default();
for b in bases {
if !out.contains(&b) {
out.push(b);
}
}
i += 1;
}
for base in self.implicit_bases(key) {
if !out.contains(&base) {
out.push(base);
}
}
out
}
pub fn implicit_bases(&self, key: &TypeKey) -> Vec<TypeKey> {
let own = self.types.get(key);
let is_enum = own.is_some_and(|t| t.is_enum);
let enum_base = is_enum.then(|| TypeKey::new(yog_script_ids::system::ENUM, 0));
let content_base = own
.and_then(|t| t.content.as_deref())
.and_then(crate::content_base)
.map(|b| TypeKey::new(b, 0));
let object = TypeKey::new(yog_script_ids::clr::OBJECT, 0);
enum_base
.into_iter()
.chain(content_base)
.chain([object])
.filter(|k| k != key && self.types.contains_key(k))
.collect()
}
pub fn lineage_named(&self, name: &str) -> Vec<TypeKey> {
self.named(name)
.map(|(k, _)| self.lineage(k))
.unwrap_or_default()
}
pub fn is_a(&self, a: &str, b: &str) -> bool {
self.lineage_named(a).iter().any(|t| t.name == b)
}
pub fn base_class(&self, name: &str) -> Option<&str> {
let (_, t) = self.named(name)?;
t.bases
.iter()
.filter_map(TypeKey::of_written)
.find(|b| self.types.get(b).is_some_and(|o| !o.interface))
.and_then(|b| self.types.get_key_value(&b))
.map(|(k, _)| k.name.as_str())
}
}