mod repository;
use crate::prelude::*;
use crate::shared::Progress;
use crate::frontend::resolver::resolved::IdMappings;
use crate::shared::typed_ids::{TypeId, ScopeId, BindingId, FunctionId};
use crate::shared::meta::{Type, Function, FunctionKind, Binding};
use repository::Repository;
pub(crate) struct Scopes {
types : Repository<String, TypeId, Type>,
bindings : Repository<String, BindingId, Binding>,
functions : Repository<(String, TypeId), FunctionId, Function>,
scopefunction : UnorderedMap<ScopeId, Option<FunctionId>>,
parent_map : Vec<ScopeId>, }
impl Into<IdMappings> for Scopes {
fn into(self: Self) -> IdMappings {
let binding_map = self.bindings.into();
let type_map = self.types.into();
let function_map = self.functions.into();
IdMappings::new(binding_map, type_map, function_map)
}
}
impl Scopes {
pub fn new() -> Self {
let root_id = Self::root_id();
Scopes {
types : Repository::new(),
bindings : Repository::new(),
functions : Repository::new(),
scopefunction : UnorderedMap::new(),
parent_map : vec![ root_id ], }
}
pub fn resolved(self: &Self) -> Progress {
Progress::new(
self.bindings.values().fold(0, |acc, b| acc + b.type_id.is_some() as usize)
+ self.types.values().fold(0, |acc, t| acc + match t {
Type::Array(array) => if array.type_id.is_some() { 1 } else { 0 },
_ => 1,
})
+ self.functions.values().fold(0, |acc, f| acc + f.is_resolved() as usize),
self.bindings.len()
+ self.types.len()
+ self.functions.len(),
)
}
pub fn root_id() -> ScopeId {
(0).into()
}
pub fn parent_id(self: &Self, scope_id: ScopeId) -> Option<ScopeId> {
let parent_scope_id = self.parent_map[Into::<usize>::into(scope_id)];
if parent_scope_id == scope_id { None } else { Some(parent_scope_id) }
}
pub fn create_scope(self: &mut Self, parent: ScopeId) -> ScopeId {
let index = self.parent_map.len();
self.parent_map.push(parent);
index.into()
}
}
impl Scopes {
pub fn set_scopefunction_id(self: &mut Self, scope_id: ScopeId, function_id: FunctionId) {
self.scopefunction.insert(scope_id, Some(function_id));
}
pub fn scopefunction_id(self: &Self, scope_id: ScopeId) -> Option<FunctionId> {
*self.scopefunction.get(&scope_id).unwrap_or(&None)
}
pub fn lookup_scopefunction_id(self: &Self, mut scope_id: ScopeId) -> Option<FunctionId> {
loop {
if let Some(function_id) = self.scopefunction_id(scope_id) {
return Some(function_id);
} else if let Some(parent_scope_id) = self.parent_id(scope_id) {
scope_id = parent_scope_id;
} else {
return None;
}
}
}
}
impl Scopes {
pub fn insert_function(self: &mut Self, scope_id: ScopeId, name: &str, result_type_id: Option<TypeId>, arg_type_ids: Vec<Option<TypeId>>, kind: Option<FunctionKind>) -> FunctionId {
let type_id = match kind {
Some(FunctionKind::Method(type_id)) => type_id,
Some(FunctionKind::Builtin(type_id, _)) => type_id,
_ => TypeId::void(),
};
self.functions.insert(scope_id, Some((name.into(), type_id)), Function { ret_type: result_type_id, arg_type: arg_type_ids, kind: kind })
}
pub fn alias_function(self: &mut Self, scope_id: ScopeId, name: &str, function_id: FunctionId) -> FunctionId {
self.functions.alias(scope_id, (name.into(), TypeId::void()), function_id)
}
pub fn function_id(self: &Self, scope_id: ScopeId, name: (&str, TypeId)) -> Option<FunctionId> {
self.functions.id_by_name(scope_id, (name.0.to_string(), name.1))
}
pub fn lookup_function_id(self: &Self, mut scope_id: ScopeId, name: (&str, TypeId)) -> Option<FunctionId> {
loop {
if let Some(index) = self.function_id(scope_id, name) {
return Some(index);
} else if let Some(parent_scope_id) = self.parent_id(scope_id) {
scope_id = parent_scope_id;
} else {
return None;
}
}
}
pub fn trait_function_id(self: &Self, _scope_id: ScopeId, name: &str, type_id: TypeId) -> Option<FunctionId> {
let ty = self.types.value_by_id(type_id);
if let Some(trait_type_ids) = ty.impl_trait_ids() {
for &trait_type_id in trait_type_ids {
let trt = self.types.value_by_id(trait_type_id).as_trait().expect("Implemented type expected to be a trait, got something else");
if let Some(&function_id) = trt.provided.get(name) {
return function_id;
}
}
}
None
}
pub fn function_ref(self: &Self, function_id: FunctionId) -> &Function {
self.functions.value_by_id(function_id)
}
}
impl Scopes {
pub fn insert_binding(self: &mut Self, scope_id: ScopeId, name: Option<&str>, mutable: bool, type_id: Option<TypeId>) -> BindingId {
self.bindings.insert(scope_id, name.map(|n| n.into()), Binding { mutable, type_id })
}
pub fn binding_id(self: &Self, scope_id: ScopeId, name: &str) -> Option<BindingId> {
self.bindings.id_by_name(scope_id, name.to_string())
}
pub fn lookup_binding_id(self: &Self, mut scope_id: ScopeId, name: &str) -> Option<BindingId> {
loop {
if let Some(index) = self.binding_id(scope_id, name) {
return Some(index);
} else if let Some(parent_scope_id) = self.parent_id(scope_id) {
scope_id = parent_scope_id;
} else {
return None;
}
}
}
pub fn binding_mut(self: &mut Self, binding_id: BindingId) -> &mut Binding {
self.bindings.value_by_id_mut(binding_id)
}
pub fn binding_ref(self: &Self, binding_id: BindingId) -> &Binding {
self.bindings.value_by_id(binding_id)
}
}
impl Scopes {
pub fn insert_type(self: &mut Self, scope_id: ScopeId, name: Option<&str>, ty: Type) -> TypeId {
self.types.insert(scope_id, name.map(|n| n.into()), ty)
}
pub fn alias_type(self: &mut Self, scope_id: ScopeId, name: &str, type_id: TypeId) -> TypeId {
self.types.alias(scope_id, name.into(), type_id)
}
pub fn type_id(self: &Self, scope_id: ScopeId, name: &str) -> Option<TypeId> {
self.types.id_by_name(scope_id, name.to_string())
}
pub fn lookup_type_id(self: &Self, mut scope_id: ScopeId, name: &str) -> Option<TypeId> {
loop {
if let Some(index) = self.type_id(scope_id, name) {
return Some(index);
} else if let Some(parent_scope_id) = self.parent_id(scope_id) {
scope_id = parent_scope_id;
} else {
return None;
}
}
}
pub fn type_name(self: &Self, type_id: TypeId) -> Option<&String> {
self.types.name_by_id(type_id, "Self".to_string())
}
pub fn type_mut(self: &mut Self, type_id: TypeId) -> &mut Type {
self.types.value_by_id_mut(type_id)
}
pub fn type_ref(self: &Self, type_id: TypeId) -> &Type {
self.types.value_by_id(type_id)
}
}