mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 19:56:44 +01:00
This commit is contained in:
parent
7570aefcc2
commit
7df7cb839c
2 changed files with 157 additions and 2 deletions
|
|
@ -2,6 +2,7 @@ extern crate proc_macro;
|
||||||
|
|
||||||
pub(crate) use std::collections::{BTreeMap, BTreeSet};
|
pub(crate) use std::collections::{BTreeMap, BTreeSet};
|
||||||
pub(crate) use std::cmp::Ordering;
|
pub(crate) use std::cmp::Ordering;
|
||||||
|
pub(crate) use std::sync::Arc;
|
||||||
pub(crate) use proc_macro::TokenStream;
|
pub(crate) use proc_macro::TokenStream;
|
||||||
pub(crate) use proc_macro2::{
|
pub(crate) use proc_macro2::{
|
||||||
TokenStream as TokenStream2, TokenTree,
|
TokenStream as TokenStream2, TokenTree,
|
||||||
|
|
@ -11,16 +12,17 @@ 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,
|
ImplItem, ImplItemFn, LitStr, Type, ItemImpl, ReturnType, Signature, FnArg, PatType,
|
||||||
parse::{Parse, ParseStream, Result},
|
parse::{Parse, ParseStream, Result},
|
||||||
token::{PathSep, Brace},
|
token::{PathSep, Brace},
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
};
|
};
|
||||||
pub(crate) use quote::{quote, TokenStreamExt, ToTokens};
|
pub(crate) use quote::{quote, TokenStreamExt, ToTokens};
|
||||||
pub(crate) use heck::AsKebabCase;
|
pub(crate) use heck::{AsKebabCase, AsUpperCamelCase};
|
||||||
|
|
||||||
mod proc_view;
|
mod proc_view;
|
||||||
mod proc_expose;
|
mod proc_expose;
|
||||||
|
mod proc_command;
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn view (meta: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn view (meta: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
|
@ -40,6 +42,15 @@ pub fn expose (meta: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn command (meta: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
use self::proc_command::{CommandDef, CommandMeta, CommandImpl};
|
||||||
|
write_macro(CommandDef(
|
||||||
|
parse_macro_input!(meta as CommandMeta),
|
||||||
|
parse_macro_input!(item as CommandImpl),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn write_macro <T: ToTokens> (t: T) -> TokenStream {
|
fn write_macro <T: ToTokens> (t: T) -> TokenStream {
|
||||||
let mut out = TokenStream2::new();
|
let mut out = TokenStream2::new();
|
||||||
t.to_tokens(&mut out);
|
t.to_tokens(&mut out);
|
||||||
|
|
|
||||||
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