mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-08-28 04:46:58 +02:00
wip support for expressions in #[commands] procmacro
Some checks are pending
/ build (push) Waiting to run
Some checks are pending
/ build (push) Waiting to run
This commit is contained in:
parent
62f30daac6
commit
a4931d8e4f
1 changed files with 50 additions and 29 deletions
|
|
@ -3,8 +3,8 @@ use proc_macro2::{TokenStream as TokenStream2, Span};
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use std::collections::{HashMap, BTreeMap};
|
use std::collections::{HashMap, BTreeMap};
|
||||||
use syn::{
|
use syn::{
|
||||||
Error, Path, Lit, Ident, Variant, Fields, BinOp,
|
Error, Path, Ident, Variant, Fields, BinOp,
|
||||||
Expr, ExprPath, ExprBinary, ExprAssign, ExprLit,
|
Expr, ExprPath, ExprBinary, ExprAssign, ExprLit, Lit, LitStr,
|
||||||
ItemEnum, ItemImpl, ImplItem, ImplItemFn, Signature,
|
ItemEnum, ItemImpl, ImplItem, ImplItemFn, Signature,
|
||||||
MetaList, Type, TypePath, FnArg, PatType,
|
MetaList, Type, TypePath, FnArg, PatType,
|
||||||
parse::{ParseStream, Parse, Result},
|
parse::{ParseStream, Parse, Result},
|
||||||
|
|
@ -28,9 +28,9 @@ macro_rules! attribute {
|
||||||
|
|
||||||
attribute!(commands {
|
attribute!(commands {
|
||||||
#[derive(Debug, Clone)] pub struct Def(pub Meta, pub Item);
|
#[derive(Debug, Clone)] pub struct Def(pub Meta, pub Item);
|
||||||
#[derive(Debug, Clone)] pub struct Meta(pub Path, pub Lit);
|
#[derive(Debug, Clone)] pub struct Meta(pub Path, pub LitStr);
|
||||||
#[derive(Debug, Clone)] pub struct Item(
|
#[derive(Debug, Clone)] pub struct Item(
|
||||||
pub Path, pub ItemImpl, pub HashMap<Ident, (Ident, Vec<FnArg>, Lit)>
|
pub Path, pub ItemImpl, pub HashMap<Ident, (Ident, Vec<FnArg>, LitStr)>
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Parse for Meta {
|
impl Parse for Meta {
|
||||||
|
|
@ -38,7 +38,7 @@ attribute!(commands {
|
||||||
let meta = input.parse()?;
|
let meta = input.parse()?;
|
||||||
if let Expr::Assign(ExprAssign { ref left, ref right, .. }) = meta
|
if let Expr::Assign(ExprAssign { ref left, ref right, .. }) = meta
|
||||||
&& let Expr::Path(ExprPath { path, .. }) = &**left
|
&& let Expr::Path(ExprPath { path, .. }) = &**left
|
||||||
&& let Expr::Lit(ExprLit { lit, .. }) = &**right
|
&& let Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) = &**right
|
||||||
{
|
{
|
||||||
Ok(Self(path.clone(), lit.clone()))
|
Ok(Self(path.clone(), lit.clone()))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -57,7 +57,7 @@ attribute!(commands {
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::new(item.self_ty.span(), format!("must be path to struct")))
|
return Err(Error::new(item.self_ty.span(), format!("must be path to struct")))
|
||||||
};
|
};
|
||||||
let mut dispatch: HashMap<Ident, (Ident, Vec<FnArg>, Lit)> = Default::default();
|
let mut dispatch: HashMap<Ident, (Ident, Vec<FnArg>, LitStr)> = Default::default();
|
||||||
for item in item.items.iter_mut() {
|
for item in item.items.iter_mut() {
|
||||||
if let ImplItem::Fn(ImplItemFn {
|
if let ImplItem::Fn(ImplItemFn {
|
||||||
attrs, sig: Signature { ident, inputs, .. }, ..
|
attrs, sig: Signature { ident, inputs, .. }, ..
|
||||||
|
|
@ -67,7 +67,7 @@ attribute!(commands {
|
||||||
&& path == &Path::from(Ident::new("command", Span::call_site()))
|
&& path == &Path::from(Ident::new("command", Span::call_site()))
|
||||||
&& let Ok(handler) = syn::parse2::<Expr>(tokens.clone())
|
&& let Ok(handler) = syn::parse2::<Expr>(tokens.clone())
|
||||||
&& let Expr::Assign(ExprAssign { ref left, ref right, .. }) = handler
|
&& let Expr::Assign(ExprAssign { ref left, ref right, .. }) = handler
|
||||||
&& let Expr::Lit(ExprLit { lit, .. }) = &**right
|
&& let Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) = &**right
|
||||||
&& let Expr::Path(ExprPath { path, .. }) = &**left
|
&& let Expr::Path(ExprPath { path, .. }) = &**left
|
||||||
&& path.segments.len() == 1 {
|
&& path.segments.len() == 1 {
|
||||||
dispatch.insert(ident.clone(), (
|
dispatch.insert(ident.clone(), (
|
||||||
|
|
@ -90,41 +90,62 @@ attribute!(commands {
|
||||||
|
|
||||||
impl ToTokens for Def {
|
impl ToTokens for Def {
|
||||||
fn to_tokens (&self, out: &mut TokenStream2) {
|
fn to_tokens (&self, out: &mut TokenStream2) {
|
||||||
let Self(Meta(command, namespace), Item(ident, item, items)) = self;
|
let Self(Meta(command, namespace), Item(state, item, items)) = self;
|
||||||
let mut variants = quote! {};
|
let mut variants = quote! {};
|
||||||
let mut dispatch = quote! {};
|
let mut dispatch = quote! {};
|
||||||
|
let mut keywords = quote! {};
|
||||||
|
let mut expressions = quote! {};
|
||||||
for (ident, (variant, inputs, keyword)) in items.iter() {
|
for (ident, (variant, inputs, keyword)) in items.iter() {
|
||||||
|
let mut typed = quote! {};
|
||||||
let mut params = quote! {};
|
let mut params = quote! {};
|
||||||
let mut args = quote! {};
|
|
||||||
let mut has_args = false;
|
let mut has_args = false;
|
||||||
for arg in inputs.iter() {
|
for arg in inputs.iter() {
|
||||||
match arg {
|
if let FnArg::Typed(PatType { pat, ty, .. }) = arg {
|
||||||
FnArg::Receiver(_) => {},
|
has_args = true;
|
||||||
FnArg::Typed(PatType { pat, ty, .. }) => {
|
append(&mut typed, quote! { #pat: #ty, });
|
||||||
has_args = true;
|
append(&mut params, quote! { #pat, });
|
||||||
append(&mut params, quote! { #pat: #ty, });
|
|
||||||
append(&mut args, quote! { #pat, })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
append(&mut variants, if has_args {
|
||||||
|
quote! { #variant { #typed }, }
|
||||||
|
} else {
|
||||||
|
quote! { #variant, }
|
||||||
|
});
|
||||||
|
append(&mut dispatch, if has_args {
|
||||||
|
quote! { #command::#variant { #params } => state.#ident(#params), }
|
||||||
|
} else {
|
||||||
|
quote! { #command::#variant => state.#ident(), }
|
||||||
|
});
|
||||||
|
let keyword = format!("{}/{}", namespace.value(), keyword.value());
|
||||||
if has_args {
|
if has_args {
|
||||||
params = quote! { { #params } };
|
append(&mut expressions, quote! {
|
||||||
args = quote! { { #args } };
|
#keyword (#typed) => { #command::#variant { #params } },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
append(&mut keywords, quote! {
|
||||||
|
#keyword => #command::#variant,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
append(&mut variants, quote! { #variant #params, });
|
|
||||||
append(&mut dispatch, quote! { #command::#variant #args => { todo!() }, });
|
|
||||||
}
|
}
|
||||||
append(out, quote! {
|
append(out, quote! {
|
||||||
#item
|
#[derive(Debug, Clone)] pub enum #command { #variants }
|
||||||
pub enum #command { #variants }
|
|
||||||
impl dizzle::Act<#ident> for #command {
|
impl<'a> dizzle::Namespace<'a, #command> for #state {
|
||||||
fn act (&self, state: &mut #ident) -> Perhaps<Self> {
|
symbols!('a |state| -> #command {
|
||||||
match self {
|
#keywords
|
||||||
#dispatch
|
});
|
||||||
_ => unreachable!()
|
expressions!('a |state| -> #command {
|
||||||
}
|
#expressions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #command {
|
||||||
|
pub fn act (self, state: &mut #state) -> Perhaps<Self> {
|
||||||
|
match self { #dispatch _ => unreachable!() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#item
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +290,7 @@ attribute!(keyword {
|
||||||
#item
|
#item
|
||||||
|
|
||||||
impl<'a> Namespace<'a, #ident> for #state {
|
impl<'a> Namespace<'a, #ident> for #state {
|
||||||
symbols!('a |stte| -> #ident {
|
symbols!('a |_state| -> #ident {
|
||||||
#body,
|
#body,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue