mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
This commit is contained in:
parent
7570aefcc2
commit
7df7cb839c
2 changed files with 157 additions and 2 deletions
144
proc/src/proc_command.rs
Normal file
144
proc/src/proc_command.rs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct CommandDef(pub(crate) CommandMeta, pub(crate) CommandImpl);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct CommandMeta {
|
||||
target: Ident,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct CommandImpl(ItemImpl, BTreeMap<Arc<str>, CommandArm>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CommandVariant(Ident, Vec<FnArg>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CommandArm(Arc<str>, Ident, Vec<FnArg>, ReturnType);
|
||||
|
||||
impl Parse for CommandMeta {
|
||||
fn parse (input: ParseStream) -> Result<Self> {
|
||||
Ok(Self {
|
||||
target: input.parse::<Ident>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for CommandImpl {
|
||||
fn parse (input: ParseStream) -> Result<Self> {
|
||||
let block = input.parse::<ItemImpl>()?;
|
||||
let mut exposed: BTreeMap<Arc<str>, CommandArm> = Default::default();
|
||||
for item in block.items.iter() {
|
||||
if let ImplItem::Fn(ImplItemFn {
|
||||
sig: Signature { ident, inputs, output, .. }, ..
|
||||
}) = item {
|
||||
let key: Arc<str> =
|
||||
format!("{}", AsKebabCase(format!("{}", &ident))).into();
|
||||
let variant: Arc<str> =
|
||||
format!("{}", AsUpperCamelCase(format!("{}", &ident))).into();
|
||||
if exposed.contains_key(&key) {
|
||||
return Err(input.error(format!("already defined: {ident}")));
|
||||
}
|
||||
exposed.insert(key, CommandArm(
|
||||
variant,
|
||||
ident.clone(),
|
||||
inputs.iter().map(|x|x.clone()).collect(),
|
||||
output.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(Self(block, exposed))
|
||||
}
|
||||
}
|
||||
|
||||
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 definitions = exposed.values().map(|x|CommandVariant(
|
||||
x.1.clone(),
|
||||
x.2.clone(),
|
||||
));
|
||||
let implementations = exposed.values().map(|x|CommandArm(
|
||||
x.0.clone(),
|
||||
x.1.clone(),
|
||||
x.2.clone(),
|
||||
x.3.clone(),
|
||||
));
|
||||
for token in quote! {
|
||||
#block
|
||||
enum #enumeration {
|
||||
#(#definitions)*
|
||||
}
|
||||
impl Command<#target> for #enumeration {
|
||||
fn execute (self, state: &mut #target) -> Perhaps<Self> {
|
||||
match self {
|
||||
#(#implementations)*
|
||||
}
|
||||
}
|
||||
}
|
||||
} {
|
||||
out.append(token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for CommandVariant {
|
||||
fn to_tokens (&self, out: &mut TokenStream2) {
|
||||
let Self(ident, args) = self;
|
||||
out.append(LitStr::new(&format!("{}", ident), Span::call_site())
|
||||
.token());
|
||||
out.append(Group::new(Delimiter::Parenthesis, {
|
||||
let mut out = TokenStream2::new();
|
||||
for arg in args.iter() {
|
||||
if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg {
|
||||
out.append(LitStr::new(
|
||||
&format!("{}", quote! { #ty }),
|
||||
Span::call_site()
|
||||
).token());
|
||||
out.append(Punct::new(',', Alone));
|
||||
}
|
||||
}
|
||||
out
|
||||
}));
|
||||
out.append(Punct::new(',', Alone));
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for CommandArm {
|
||||
fn to_tokens (&self, out: &mut TokenStream2) {
|
||||
let Self(symbol, ident, args, returnType) = self;
|
||||
out.append(Punct::new(':', Joint));
|
||||
out.append(Punct::new(':', Alone));
|
||||
out.append(Ident::new("tengri", Span::call_site()));
|
||||
out.append(Punct::new(':', Joint));
|
||||
out.append(Punct::new(':', Alone));
|
||||
out.append(Ident::new("dsl", Span::call_site()));
|
||||
out.append(Punct::new(':', Joint));
|
||||
out.append(Punct::new(':', Alone));
|
||||
out.append(Ident::new("Value", Span::call_site()));
|
||||
out.append(Punct::new(':', Joint));
|
||||
out.append(Punct::new(':', Alone));
|
||||
out.append(Ident::new("Sym", Span::call_site()));
|
||||
out.append(Group::new(Delimiter::Parenthesis, {
|
||||
let mut out = TokenStream2::new();
|
||||
for arg in args.iter() {
|
||||
out.append(LitStr::new(&symbol, Span::call_site()).token());
|
||||
}
|
||||
out
|
||||
}));
|
||||
out.append(Punct::new('=', Joint));
|
||||
out.append(Punct::new('>', Alone));
|
||||
out.append(LitStr::new(&format!("{}", ident), Span::call_site()).token());
|
||||
out.append(Group::new(Delimiter::Parenthesis, {
|
||||
let mut out = TokenStream2::new();
|
||||
for arg in args.iter() {
|
||||
// TODO
|
||||
//out.append(LitStr::new(&symbol, Span::call_site()).token());
|
||||
}
|
||||
out
|
||||
}));
|
||||
out.append(Punct::new(',', Alone));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue