use std::collections::HashMap;
use unsynn::*;
use crate::{Generics, HasGenerics, ItemKind, MaybeRefType, Typed, kw, mutate_delimited_vec};
unsynn! {
pub(super) struct Arguments(ParenthesisGroupContaining<CommaDelimitedVec<FunctionArg>>);
pub struct FunctionArg {
mut_: Option<kw::Mut>,
ident: Ident,
colon: Colon,
type_: MaybeRefType,
}
pub(super) struct Returns {
colon: Colon,
type_: ReturnType,
}
pub(super) enum ReturnType {
One(MaybeRefType),
Many(ParenthesisGroupContaining<CommaDelimitedVec<MaybeRefType>>),
}
}
impl crate::Module {
pub fn fully_qualify_fun_signature_types(&mut self) -> &mut Self {
let imports: HashMap<_, _> = self
.items()
.filter_map(|item| match &item.kind {
ItemKind::Import(import) => Some(import),
_ => None,
})
.flat_map(|import| import.flatten())
.collect();
for item in &mut self.contents.content {
match &mut item.kind {
ItemKind::Function(fun) => {
let generics = &fun.type_param_idents();
fun.map_types(|ty| ty.resolve(&imports, generics));
}
ItemKind::NativeFun(native) => {
let generics = &native.type_param_idents();
native.map_types(|ty| ty.resolve(&imports, generics));
}
_ => (),
}
}
self
}
}
impl HasGenerics for super::Function {
fn generics(&self) -> Option<&Generics> {
self.generics.as_ref()
}
}
impl HasGenerics for super::NativeFun {
fn generics(&self) -> Option<&Generics> {
self.generics.as_ref()
}
}
impl Typed for super::Function {
fn map_types(&mut self, mut f: impl FnMut(&mut crate::Type)) {
mutate_delimited_vec(&mut self.args.0.content, |arg| f(&mut arg.type_.r#type));
if let Some(ret) = self.ret.as_mut() {
ret.map_types(f);
}
}
}
impl Typed for super::NativeFun {
fn map_types(&mut self, mut f: impl FnMut(&mut crate::Type)) {
mutate_delimited_vec(&mut self.args.0.content, |arg| f(&mut arg.type_.r#type));
if let Some(ret) = self.ret.as_mut() {
ret.map_types(f);
}
}
}
impl Typed for Returns {
fn map_types(&mut self, mut f: impl FnMut(&mut crate::Type)) {
match &mut self.type_ {
ReturnType::One(maybe_ref_type) => f(&mut maybe_ref_type.r#type),
ReturnType::Many(parenthesis_group) => {
mutate_delimited_vec(&mut parenthesis_group.content, |maybe_ref_type| {
f(&mut maybe_ref_type.r#type)
})
}
}
}
}
impl super::Function {
pub fn arguments(&self) -> impl ExactSizeIterator<Item = &FunctionArg> {
self.args.0.content.iter().map(|d| &d.value)
}
pub fn returns(&self) -> impl ExactSizeIterator<Item = &MaybeRefType> {
MaybeRefTypeIter::new(self.ret.as_ref())
}
}
impl super::NativeFun {
pub fn arguments(&self) -> impl ExactSizeIterator<Item = &FunctionArg> {
self.args.0.content.iter().map(|d| &d.value)
}
pub fn returns(&self) -> impl ExactSizeIterator<Item = &MaybeRefType> {
MaybeRefTypeIter::new(self.ret.as_ref())
}
}
impl FunctionArg {
pub const fn ident(&self) -> &Ident {
&self.ident
}
pub const fn type_(&self) -> &MaybeRefType {
&self.type_
}
}
struct MaybeRefTypeIter<'a> {
inner: Option<&'a Returns>,
idx: usize,
}
impl<'a> MaybeRefTypeIter<'a> {
const fn new(inner: Option<&'a Returns>) -> Self {
Self { inner, idx: 0 }
}
}
impl<'a> Iterator for MaybeRefTypeIter<'a> {
type Item = &'a MaybeRefType;
fn next(&mut self) -> Option<Self::Item> {
match &self.inner {
None => None,
Some(Returns {
type_: ReturnType::One(maybe_ref_type),
..
}) if self.idx == 0 => {
self.idx += 1;
Some(maybe_ref_type)
}
Some(Returns {
type_: ReturnType::One(_),
..
}) => None,
Some(Returns {
type_: ReturnType::Many(parenthesis_group),
..
}) if self.idx < parenthesis_group.content.len() => {
let item = &parenthesis_group.content[self.idx].value;
self.idx += 1;
Some(item)
}
Some(Returns {
type_: ReturnType::Many(_),
..
}) => None,
}
}
}
impl<'a> ExactSizeIterator for MaybeRefTypeIter<'a> {
fn len(&self) -> usize {
match &self.inner {
None => 0,
Some(Returns {
type_: ReturnType::One(_),
..
}) => 1,
Some(Returns {
type_: ReturnType::Many(parenthesis_group),
..
}) => parenthesis_group.content.len(),
}
}
}