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(box_patterns)]
extern crate proc_macro;
pub(crate) use std::collections::{BTreeMap, BTreeSet};
@ -14,7 +14,8 @@ 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, PatType,
ImplItem, ImplItemFn, LitStr, Type, ItemImpl, ReturnType, Signature, FnArg,
Pat, PatType, PatIdent,
parse::{Parse, ParseStream, Result},
token::{PathSep, Brace},
punctuated::Punctuated,

View file

@ -57,11 +57,12 @@ 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|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 implementations = exposed.values().map(CommandArm::to_implementation);
write_quote_to(out, quote! {
/// Generated by [tengri_proc].
#[derive(Clone, Debug)]
pub enum #enumeration {
#(#variants)*
}
@ -85,9 +86,13 @@ impl ToTokens for CommandDef {
}
}
});
if exposed.len() > 0 {
//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});
}
//}
//}
}
}
@ -104,7 +109,7 @@ impl CommandArm {
fn ident_to_enum_variant (ident: &Ident) -> Arc<str> {
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();
out.append(self.to_enum_variant_ident());
let ident = &self.0;
@ -112,21 +117,10 @@ 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 { 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)
});
}
if let FnArg::Typed(PatType {
ty, pat: box Pat::Ident(PatIdent { ident, .. }), ..
}) = arg {
write_quote_to(&mut out, quote! { #ident : #ty , });
} else {
unreachable!("only typed args should be present at this position")
}
@ -134,8 +128,55 @@ impl CommandArm {
out
}));
}
if trailing_comma {
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
}
@ -144,11 +185,13 @@ 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 { 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 \"{}\" ({})",
quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site());
quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site());
write_quote(quote! {
let #pat: #ty = Context::<#ty>::get(
let #ident: #ty = Context::<#ty>::get(
state,
&iter.next().expect(#take_err).value
);
@ -158,7 +201,7 @@ impl CommandArm {
}
}).collect::<Vec<_>>();
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! {
Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Key(#key), .. }) => {
let mut iter = iter.clone();
@ -170,13 +213,15 @@ impl CommandArm {
}
fn to_implementation (&self) -> TokenStream2 {
let ident = &self.0;
let variant = self.to_enum_variant(false, false, false);
let mut give_rest = write_quote(quote! { });
let variant = self.to_enum_variant_unbind();
let mut give_rest = write_quote(quote! { /*TODO*/ });
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 \"{}\" ({})",
//quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site());
write_quote(quote! { #pat, })
write_quote(quote! { #arg, })
} else {
unreachable!("only typed args should be present at this position")
}

View file

@ -70,23 +70,31 @@ impl ToTokens for ExposeImpl {
out.append(token);
}
for (t, variants) in exposed.iter() {
let predefined = match format!("{}", quote! { #t }).as_str() {
"bool" => vec![
quote! { ::tengri::dsl::Value::Sym(":true") => true },
quote! { ::tengri::dsl::Value::Sym(":false") => false },
],
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,
},
"u8" | "u16" | "u32" | "u64" | "usize" |
"i8" | "i16" | "i32" | "i64" | "isize" => vec![
quote! { ::tengri::dsl::Value::Num(n) => *n },
],
_ => vec![],
"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! {},
};
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
})
@ -97,9 +105,9 @@ impl ToTokens for ExposeImpl {
out.append(token);
}
}
//if exposed.len() > 0 {
if exposed.len() > 0 {
//panic!("{}", quote! {#out});
//}
}
}
}