use crate::prelude::*;
use crate::StackAddress;
use crate::shared::meta::{Type, Trait, ImplTrait, Function, Binding};
use crate::shared::typed_ids::{BindingId, TypeId, FunctionId};
use crate::frontend::parser::types::ParsedModule;
pub struct ResolvedProgram<T> {
pub(crate) ty: PhantomData<T>,
pub modules: Vec<ParsedModule>,
pub id_mappings: IdMappings,
pub entry_fn: FunctionId,
}
pub struct IdMappings {
pub(crate) binding_map : Vec<Binding>,
pub(crate) type_map : Vec<Type>,
pub(crate) function_map: Vec<Function>,
}
impl IdMappings {
pub(crate) fn new(binding_map: Vec<Binding>, type_map: Vec<Type>, function_map: Vec<Function>) -> Self {
for info in binding_map.iter() {
info.type_id.expect("Unresolved binding type encountered.");
}
for info in function_map.iter() {
if !info.is_resolved() { panic!("Unresolved binding type encountered."); }
}
Self {
binding_map,
type_map,
function_map,
}
}
pub fn functions(self: &Self) -> impl Iterator<Item=(FunctionId, &Function)> {
self.function_map.iter().enumerate().map(|(index, info)| (FunctionId::from(index), info))
}
pub fn types(self: &Self) -> impl Iterator<Item=(TypeId, &Type)> {
self.type_map.iter().enumerate().map(|(index, info)| (TypeId::from(index), info))
}
pub fn traits(self: &Self) -> impl Iterator<Item=(TypeId, &Trait)> {
self.type_map.iter()
.enumerate()
.filter_map(|(type_id, ty)| ty.as_trait().map(|trt| (TypeId::from(type_id), trt)))
}
pub fn implementors(self: &Self) -> impl Iterator<Item=(TypeId, &Map<TypeId, ImplTrait>)> {
self.type_map.iter()
.enumerate()
.filter_map(|(type_id, ty)| ty.as_struct().map(|struct_| (TypeId::from(type_id), struct_)))
.filter_map(|i| if i.1.impl_traits.len() > 0 { Some((i.0, &i.1.impl_traits)) } else { None })
}
pub fn bindings(self: &Self) -> impl Iterator<Item=(BindingId, &Binding)> {
self.binding_map.iter().enumerate().map(|(index, info)| (BindingId::from(index), info))
}
pub fn function(self: &Self, function_id: FunctionId) -> &Function {
&self.function_map[Into::<usize>::into(function_id)]
}
pub fn binding(self: &Self, binding_id: BindingId) -> &Binding {
&self.binding_map[Into::<usize>::into(binding_id)]
}
pub fn ty(self: &Self, type_id: TypeId) -> &Type {
&self.type_map[Into::<usize>::into(type_id)]
}
pub fn function_arg_size(self: &Self, function_id: FunctionId) -> StackAddress {
let function = self.function(function_id);
let mut arg_size = 0;
for arg in &function.arg_type {
let arg_type_id = arg.expect("Function arg is not resolved");
arg_size += self.ty(arg_type_id).primitive_size() as StackAddress;
}
arg_size
}
pub fn function_ret_size(self: &Self, function_id: FunctionId) -> StackAddress {
let function = self.function(function_id);
let ret_type_id = function.ret_type.expect("Function result is not resolved");
self.ty(ret_type_id).primitive_size() as StackAddress
}
}