Compare commits

...

3 commits

Author SHA1 Message Date
2a6087e1c7 fix: command: refs
Some checks are pending
/ build (push) Waiting to run
2025-05-08 17:39:02 +03:00
e3bfae8897 fix: command: commas 2025-05-08 17:25:45 +03:00
046be9a9e1 proc: working command, expose 2025-05-08 13:46:29 +03:00
3 changed files with 98 additions and 44 deletions

View file

@ -1,5 +1,5 @@
#![feature(str_as_str)] #![feature(str_as_str)]
#![feature(box_patterns)]
extern crate proc_macro; extern crate proc_macro;
pub(crate) use std::collections::{BTreeMap, BTreeSet}; pub(crate) use std::collections::{BTreeMap, BTreeSet};
@ -14,7 +14,8 @@ pub(crate) use syn::{
parse, parse_macro_input, parse_quote as pq, parse, parse_macro_input, parse_quote as pq,
braced, bracketed, parenthesized, Token, braced, bracketed, parenthesized, Token,
Arm, Expr, Attribute, Meta, MetaList, Path, PathSegment, PathArguments, Arm, Expr, Attribute, Meta, MetaList, Path, PathSegment, PathArguments,
ImplItem, ImplItemFn, LitStr, Type, ItemImpl, ReturnType, Signature, FnArg, PatType, ImplItem, ImplItemFn, LitStr, Type, ItemImpl, ReturnType, Signature, FnArg,
Pat, PatType, PatIdent,
parse::{Parse, ParseStream, Result}, parse::{Parse, ParseStream, Result},
token::{PathSep, Brace}, token::{PathSep, Brace},
punctuated::Punctuated, punctuated::Punctuated,

View file

@ -57,11 +57,12 @@ impl ToTokens for CommandDef {
fn to_tokens (&self, out: &mut TokenStream2) { fn to_tokens (&self, out: &mut TokenStream2) {
let Self(CommandMeta(target), CommandImpl(block, exposed)) = self; let Self(CommandMeta(target), CommandImpl(block, exposed)) = self;
let enumeration = &block.self_ty; let enumeration = &block.self_ty;
let variants = exposed.values().map(|x|CommandArm::to_enum_variant(x, true, true, false)); let variants = exposed.values().map(|x|x.to_enum_variant_def());
let matchers = exposed.values().map(CommandArm::to_matcher); let matchers = exposed.values().map(CommandArm::to_matcher);
let implementations = exposed.values().map(CommandArm::to_implementation); let implementations = exposed.values().map(CommandArm::to_implementation);
write_quote_to(out, quote! { write_quote_to(out, quote! {
/// Generated by [tengri_proc]. /// Generated by [tengri_proc].
#[derive(Clone, Debug)]
pub enum #enumeration { pub enum #enumeration {
#(#variants)* #(#variants)*
} }
@ -85,9 +86,13 @@ impl ToTokens for CommandDef {
} }
} }
}); });
if exposed.len() > 0 { //if exposed.len() > 0 {
//panic!("\n{}", quote! {#out}); //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});
//}
//}
} }
} }
@ -104,7 +109,7 @@ impl CommandArm {
fn ident_to_enum_variant (ident: &Ident) -> Arc<str> { fn ident_to_enum_variant (ident: &Ident) -> Arc<str> {
format!("{}", AsUpperCamelCase(format!("{ident}"))).into() format!("{}", AsUpperCamelCase(format!("{ident}"))).into()
} }
fn to_enum_variant (&self, with_types: bool, trailing_comma: bool, with_values: bool) -> TokenStream2 { fn to_enum_variant_def (&self) -> TokenStream2 {
let mut out = TokenStream2::new(); let mut out = TokenStream2::new();
out.append(self.to_enum_variant_ident()); out.append(self.to_enum_variant_ident());
let ident = &self.0; let ident = &self.0;
@ -112,21 +117,10 @@ impl CommandArm {
out.append(Group::new(Delimiter::Brace, { out.append(Group::new(Delimiter::Brace, {
let mut out = TokenStream2::new(); let mut out = TokenStream2::new();
for arg in self.1.iter().skip(2) { for arg in self.1.iter().skip(2) {
if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { if let FnArg::Typed(PatType {
write_quote_to(&mut out, quote! { #pat }); ty, pat: box Pat::Ident(PatIdent { ident, .. }), ..
if with_types && with_values { }) = arg {
unreachable!(); write_quote_to(&mut out, quote! { #ident : #ty , });
}
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 { } else {
unreachable!("only typed args should be present at this position") unreachable!("only typed args should be present at this position")
} }
@ -134,8 +128,55 @@ impl CommandArm {
out out
})); }));
} }
if trailing_comma { out.append(Punct::new(',', Alone));
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
}));
} }
out out
} }
@ -144,11 +185,13 @@ impl CommandArm {
let key = LitStr::new(&self.to_key(), Span::call_site()); let key = LitStr::new(&self.to_key(), Span::call_site());
let ident = &self.0; let ident = &self.0;
let take_args = self.1.iter().skip(2).map(|arg|{ let take_args = self.1.iter().skip(2).map(|arg|{
if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { if let FnArg::Typed(PatType {
ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), ..
}) = arg {
let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})",
quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site()); quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site());
write_quote(quote! { write_quote(quote! {
let #pat: #ty = Context::<#ty>::get( let #ident: #ty = Context::<#ty>::get(
state, state,
&iter.next().expect(#take_err).value &iter.next().expect(#take_err).value
); );
@ -158,7 +201,7 @@ impl CommandArm {
} }
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let variant = Self::ident_to_enum_variant(&self.0); let variant = Self::ident_to_enum_variant(&self.0);
let variant = self.to_enum_variant(false, false, true); let variant = self.to_enum_variant_bind();
write_quote(quote! { write_quote(quote! {
Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Key(#key), .. }) => { Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Key(#key), .. }) => {
let mut iter = iter.clone(); let mut iter = iter.clone();
@ -170,13 +213,15 @@ impl CommandArm {
} }
fn to_implementation (&self) -> TokenStream2 { fn to_implementation (&self) -> TokenStream2 {
let ident = &self.0; let ident = &self.0;
let variant = self.to_enum_variant(false, false, false); let variant = self.to_enum_variant_unbind();
let mut give_rest = write_quote(quote! { }); let mut give_rest = write_quote(quote! { /*TODO*/ });
let give_args = self.1.iter().skip(2).map(|arg|{ let give_args = self.1.iter().skip(2).map(|arg|{
if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { if let FnArg::Typed(PatType {
ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), ..
}) = arg {
//let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})", //let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})",
//quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site()); //quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site());
write_quote(quote! { #pat, }) write_quote(quote! { #arg, })
} else { } else {
unreachable!("only typed args should be present at this position") unreachable!("only typed args should be present at this position")
} }

View file

@ -70,23 +70,31 @@ impl ToTokens for ExposeImpl {
out.append(token); out.append(token);
} }
for (t, variants) in exposed.iter() { for (t, variants) in exposed.iter() {
let predefined = match format!("{}", quote! { #t }).as_str() { let formatted_type = format!("{}", quote! { #t });
"bool" => vec![ let predefined = match formatted_type.as_str() {
quote! { ::tengri::dsl::Value::Sym(":true") => true }, "bool" => quote! {
quote! { ::tengri::dsl::Value::Sym(":false") => false }, ::tengri::dsl::Value::Sym(":true") => true,
], ::tengri::dsl::Value::Sym(":false") => false,
},
"u8" | "u16" | "u32" | "u64" | "usize" | "u8" | "u16" | "u32" | "u64" | "usize" |
"i8" | "i16" | "i32" | "i64" | "isize" => vec![ "i8" | "i16" | "i32" | "i64" | "isize" => {
quote! { ::tengri::dsl::Value::Num(n) => *n }, let num_err = LitStr::new(
], &format!("{{n}}: failed to convert to {formatted_type}"),
_ => vec![], Span::call_site()
);
quote! {
::tengri::dsl::Value::Num(n) => TryInto::<#t>::try_into(*n)
.unwrap_or_else(|_|panic!(#num_err)),
}
},
_ => quote! {},
}; };
let values = variants.iter().map(|(k, v)|ExposeArm(k.clone(), v.clone())); let values = variants.iter().map(|(k, v)|ExposeArm(k.clone(), v.clone()));
let trait_impl = quote! { let trait_impl = quote! {
impl ::tengri::dsl::Context<#t> for #target { impl ::tengri::dsl::Context<#t> for #target {
fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> { fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> {
Some(match dsl { Some(match dsl {
#(#predefined,)* #predefined
#(#values,)* #(#values,)*
_ => return None _ => return None
}) })
@ -97,9 +105,9 @@ impl ToTokens for ExposeImpl {
out.append(token); out.append(token);
} }
} }
//if exposed.len() > 0 { if exposed.len() > 0 {
//panic!("{}", quote! {#out}); //panic!("{}", quote! {#out});
//} }
} }
} }