diff --git a/proc/src/lib.rs b/proc/src/lib.rs index 66dc0c7..82cb6c8 100644 --- a/proc/src/lib.rs +++ b/proc/src/lib.rs @@ -1,5 +1,5 @@ #![feature(str_as_str)] -#![feature(box_patterns)] + extern crate proc_macro; pub(crate) use std::collections::{BTreeMap, BTreeSet}; @@ -14,8 +14,7 @@ pub(crate) use syn::{ parse, parse_macro_input, parse_quote as pq, braced, bracketed, parenthesized, Token, Arm, Expr, Attribute, Meta, MetaList, Path, PathSegment, PathArguments, - ImplItem, ImplItemFn, LitStr, Type, ItemImpl, ReturnType, Signature, FnArg, - Pat, PatType, PatIdent, + ImplItem, ImplItemFn, LitStr, Type, ItemImpl, ReturnType, Signature, FnArg, PatType, parse::{Parse, ParseStream, Result}, token::{PathSep, Brace}, punctuated::Punctuated, diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index d3d2ec4..8ad7776 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -57,12 +57,11 @@ impl ToTokens for CommandDef { fn to_tokens (&self, out: &mut TokenStream2) { let Self(CommandMeta(target), CommandImpl(block, exposed)) = self; let enumeration = &block.self_ty; - let variants = exposed.values().map(|x|x.to_enum_variant_def()); + let variants = exposed.values().map(|x|CommandArm::to_enum_variant(x, true, true, false)); let matchers = exposed.values().map(CommandArm::to_matcher); let implementations = exposed.values().map(CommandArm::to_implementation); write_quote_to(out, quote! { /// Generated by [tengri_proc]. - #[derive(Clone, Debug)] pub enum #enumeration { #(#variants)* } @@ -86,13 +85,9 @@ impl ToTokens for CommandDef { } } }); - //if exposed.len() > 0 { - //panic!("{:#?}", block.self_ty); - //if let Type::Path(ref path) = *block.self_ty { - //if path.path.segments.get(0).unwrap().ident == "TekCommand" { - //panic!("\n{}", quote! {#out}); - //} - //} + if exposed.len() > 0 { + //panic!("\n{}", quote! {#out}); + } } } @@ -109,7 +104,7 @@ impl CommandArm { fn ident_to_enum_variant (ident: &Ident) -> Arc { format!("{}", AsUpperCamelCase(format!("{ident}"))).into() } - fn to_enum_variant_def (&self) -> TokenStream2 { + fn to_enum_variant (&self, with_types: bool, trailing_comma: bool, with_values: bool) -> TokenStream2 { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); let ident = &self.0; @@ -117,10 +112,21 @@ impl CommandArm { out.append(Group::new(Delimiter::Brace, { let mut out = TokenStream2::new(); for arg in self.1.iter().skip(2) { - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident, .. }), .. - }) = arg { - write_quote_to(&mut out, quote! { #ident : #ty , }); + if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { + write_quote_to(&mut out, quote! { #pat }); + if with_types && with_values { + unreachable!(); + } + if with_types { + write_quote_to(&mut out, quote! { : #ty }); + } + if with_values { + let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", + quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site()); + write_quote_to(&mut out, quote! { + : Context::get(state, &iter.next().expect(#take_err).value) + }); + } } else { unreachable!("only typed args should be present at this position") } @@ -128,55 +134,8 @@ impl CommandArm { out })); } - out.append(Punct::new(',', Alone)); - out - } - fn to_enum_variant_bind (&self) -> TokenStream2 { - let mut out = TokenStream2::new(); - out.append(self.to_enum_variant_ident()); - let ident = &self.0; - if self.1.len() > 2 { - out.append(Group::new(Delimiter::Brace, { - let mut out = TokenStream2::new(); - for arg in self.1.iter().skip(2) { - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { - let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", - quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); - let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})", - quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); - write_quote_to(&mut out, quote! { - #arg : Context::get(state, &iter.next().expect(#take_err).value) - .expect(#give_err) , - }); - } else { - unreachable!("only typed args should be present at this position") - } - } - out - })); - } - out - } - fn to_enum_variant_unbind (&self) -> TokenStream2 { - let mut out = TokenStream2::new(); - out.append(self.to_enum_variant_ident()); - let ident = &self.0; - if self.1.len() > 2 { - out.append(Group::new(Delimiter::Brace, { - let mut out = TokenStream2::new(); - for arg in self.1.iter().skip(2) { - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { - write_quote_to(&mut out, quote! { #arg , }); - } else { - unreachable!("only typed args should be present at this position") - } - } - out - })); + if trailing_comma { + out.append(Punct::new(',', Alone)); } out } @@ -185,13 +144,11 @@ impl CommandArm { let key = LitStr::new(&self.to_key(), Span::call_site()); let ident = &self.0; let take_args = self.1.iter().skip(2).map(|arg|{ - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { + if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", - quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); + quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site()); write_quote(quote! { - let #ident: #ty = Context::<#ty>::get( + let #pat: #ty = Context::<#ty>::get( state, &iter.next().expect(#take_err).value ); @@ -201,7 +158,7 @@ impl CommandArm { } }).collect::>(); let variant = Self::ident_to_enum_variant(&self.0); - let variant = self.to_enum_variant_bind(); + let variant = self.to_enum_variant(false, false, true); write_quote(quote! { Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Key(#key), .. }) => { let mut iter = iter.clone(); @@ -213,15 +170,13 @@ impl CommandArm { } fn to_implementation (&self) -> TokenStream2 { let ident = &self.0; - let variant = self.to_enum_variant_unbind(); - let mut give_rest = write_quote(quote! { /*TODO*/ }); + let variant = self.to_enum_variant(false, false, false); + let mut give_rest = write_quote(quote! { }); let give_args = self.1.iter().skip(2).map(|arg|{ - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { + if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { //let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})", //quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site()); - write_quote(quote! { #arg, }) + write_quote(quote! { #pat, }) } else { unreachable!("only typed args should be present at this position") } diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index 0303509..9315f2e 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -70,31 +70,23 @@ impl ToTokens for ExposeImpl { out.append(token); } for (t, variants) in exposed.iter() { - let formatted_type = format!("{}", quote! { #t }); - let predefined = match formatted_type.as_str() { - "bool" => quote! { - ::tengri::dsl::Value::Sym(":true") => true, - ::tengri::dsl::Value::Sym(":false") => false, - }, + let predefined = match format!("{}", quote! { #t }).as_str() { + "bool" => vec![ + quote! { ::tengri::dsl::Value::Sym(":true") => true }, + quote! { ::tengri::dsl::Value::Sym(":false") => false }, + ], "u8" | "u16" | "u32" | "u64" | "usize" | - "i8" | "i16" | "i32" | "i64" | "isize" => { - let num_err = LitStr::new( - &format!("{{n}}: failed to convert to {formatted_type}"), - Span::call_site() - ); - quote! { - ::tengri::dsl::Value::Num(n) => TryInto::<#t>::try_into(*n) - .unwrap_or_else(|_|panic!(#num_err)), - } - }, - _ => quote! {}, + "i8" | "i16" | "i32" | "i64" | "isize" => vec![ + quote! { ::tengri::dsl::Value::Num(n) => *n }, + ], + _ => vec![], }; let values = variants.iter().map(|(k, v)|ExposeArm(k.clone(), v.clone())); let trait_impl = quote! { impl ::tengri::dsl::Context<#t> for #target { fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> { Some(match dsl { - #predefined + #(#predefined,)* #(#values,)* _ => return None }) @@ -105,9 +97,9 @@ impl ToTokens for ExposeImpl { out.append(token); } } - if exposed.len() > 0 { + //if exposed.len() > 0 { //panic!("{}", quote! {#out}); - } + //} } }