|
1 |
| -use crate::prelude::*; |
| 1 | +use std::collections::HashMap; |
| 2 | + |
| 3 | +use crate::{ |
| 4 | + function::{Args, CallType, Function, MethodReceiver}, |
| 5 | + helpers::get_docs, |
| 6 | + impl_::{Constant, FnBuilder, MethodArgs, MethodTy}, |
| 7 | + prelude::*, |
| 8 | +}; |
| 9 | +use darling::{ast::NestedMeta, FromMeta, ToTokens}; |
2 | 10 | use proc_macro2::TokenStream;
|
3 | 11 | use quote::quote;
|
4 |
| -use syn::TraitItem; |
| 12 | +use syn::{Ident, ItemTrait, Lit, TraitItem, TraitItemFn}; |
| 13 | + |
| 14 | +#[derive(Debug, Default, FromMeta)] |
| 15 | +#[darling(default)] |
| 16 | +pub struct StructArgs { |
| 17 | + /// The name of the PHP interface. Defaults to the same name as the trait. |
| 18 | + name: Option<String>, |
| 19 | +} |
| 20 | + |
| 21 | +#[derive(Debug)] |
| 22 | +struct ParsedTrait<'a> { |
| 23 | + path: &'a syn::Path, |
| 24 | + constructor: Option<Function<'a>>, |
| 25 | + functions: Vec<FnBuilder>, |
| 26 | + constants: Vec<Constant<'a>>, |
| 27 | +} |
| 28 | + |
| 29 | +impl<'a> ParsedTrait<'a> { |
| 30 | + fn parse(&mut self, items: impl Iterator<Item = &'a mut syn::TraitItem>) -> Result<()> { |
| 31 | + for item in items { |
| 32 | + match item { |
| 33 | + syn::TraitItem::Fn(method) => { |
| 34 | + let name = method.sig.ident.to_string(); |
| 35 | + let docs = get_docs(&method.attrs); |
| 36 | + let mut opts = MethodArgs::new(name); |
| 37 | + opts.parse(&mut method.attrs)?; |
| 38 | + let args = Args::parse_from_fnargs(method.sig.inputs.iter(), opts.defaults)?; |
| 39 | + let mut func = |
| 40 | + Function::new(&method.sig, Some(opts.name), args, opts.optional, docs)?; |
| 41 | + |
| 42 | + if matches!(opts.ty, MethodTy::Constructor) { |
| 43 | + if self.constructor.replace(func).is_some() { |
| 44 | + bail!(method => "Only one constructor can be provided per class."); |
| 45 | + } |
| 46 | + } else { |
| 47 | + let call_type = CallType::Method { |
| 48 | + class: self.path, |
| 49 | + receiver: if func.args.receiver.is_some() { |
| 50 | + // `&self` or `&mut self` |
| 51 | + MethodReceiver::Class |
| 52 | + } else if func |
| 53 | + .args |
| 54 | + .typed |
| 55 | + .first() |
| 56 | + .map(|arg| arg.name == "self_") |
| 57 | + .unwrap_or_default() |
| 58 | + { |
| 59 | + // `self_: &[mut] ZendClassObject<Self>` |
| 60 | + // Need to remove arg from argument list |
| 61 | + func.args.typed.pop(); |
| 62 | + MethodReceiver::ZendClassObject |
| 63 | + } else { |
| 64 | + // Static method |
| 65 | + MethodReceiver::Static |
| 66 | + }, |
| 67 | + }; |
| 68 | + let builder = func.function_builder(call_type)?; |
| 69 | + self.functions.push(FnBuilder { |
| 70 | + builder, |
| 71 | + vis: opts.vis, |
| 72 | + r#abstract: false, |
| 73 | + }); |
| 74 | + } |
| 75 | + } |
| 76 | + _ => {} |
| 77 | + } |
| 78 | + } |
| 79 | + Ok(()) |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +pub fn parser(args: TokenStream, input: ItemTrait) -> Result<TokenStream> { |
| 84 | + let meta = NestedMeta::parse_meta_list(args)?; |
| 85 | + |
| 86 | + let args = match StructArgs::from_list(&meta) { |
| 87 | + Ok(args) => args, |
| 88 | + Err(e) => bail!("Failed to parse struct arguments: {:?}", e), |
| 89 | + }; |
5 | 90 |
|
6 |
| -pub fn parser(args: TokenStream, input: TraitItem) -> Result<TokenStream> { |
7 |
| - Ok(quote! {()}) |
| 91 | + Ok(quote! {}) |
8 | 92 | }
|
0 commit comments