use crate::api_def::statement::ExpressionContext;
use proc_macro2::TokenStream;
use quote::ToTokens;
use quote::quote;
use syn::GenericArgument;
use syn::Path;
use syn::PathArguments;
use syn::PathSegment;
pub(crate) fn parse_path(path: &Path, _context: ExpressionContext) -> TokenStream {
let mut iter = path.segments.iter();
let first = iter.next().expect("path should have at least one segment");
let first_segment = parse_path_segment(first, quote! { None });
iter.fold(first_segment, |path, segment| {
parse_path_segment(segment, quote! { Some(&#path) })
})
}
fn parse_path_segment(path: &PathSegment, parent: TokenStream) -> TokenStream {
let ident = &path.ident;
let generics = match &path.arguments {
PathArguments::AngleBracketed(args) => {
args.args
.iter()
.filter_map(|ga| {
match ga {
GenericArgument::Type(ty) => {
Some(quote! { <#ty as ::agdb::api_def::TypeDefinition>::type_def })
}
_ => None,
}
})
.collect::<Vec<_>>()
}
PathArguments::Parenthesized(args) => args
.inputs
.iter()
.map(|ty| quote! { <#ty as ::agdb::api_def::TypeDefinition>::type_def })
.collect::<Vec<_>>(),
PathArguments::None => Vec::new(),
};
quote! {
::agdb::api_def::Expression::Path {
ident: stringify!(#ident),
parent: #parent,
generics: &[#(#generics),*],
}
}
}
pub(crate) fn parse_identifier_to_string(path: &Path) -> String {
path.segments
.last()
.expect("path should not be empty")
.to_token_stream()
.to_string()
}