mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-07 04:06:48 +01:00
231 lines
7.7 KiB
Rust
231 lines
7.7 KiB
Rust
use crate::*;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct ExposeDef(pub(crate) ExposeMeta, pub(crate) ExposeImpl);
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct ExposeMeta;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct ExposeImpl(ItemImpl, BTreeMap<ExposeType, BTreeMap<String, Ident>>);
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct ExposeSym(LitStr);
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct ExposeType(Box<Type>);
|
|
|
|
impl Parse for ExposeMeta {
|
|
fn parse (_input: ParseStream) -> Result<Self> {
|
|
Ok(Self)
|
|
}
|
|
}
|
|
|
|
impl Parse for ExposeImpl {
|
|
fn parse (input: ParseStream) -> Result<Self> {
|
|
let block = input.parse::<ItemImpl>()?;
|
|
let mut exposed: BTreeMap<ExposeType, BTreeMap<String, Ident>> = Default::default();
|
|
for item in block.items.iter() {
|
|
if let ImplItem::Fn(ImplItemFn { sig: Signature { ident, output, .. }, .. }) = item {
|
|
if let ReturnType::Type(_, return_type) = output {
|
|
let return_type = ExposeType(return_type.clone());
|
|
if !exposed.contains_key(&return_type) {
|
|
exposed.insert(return_type.clone(), Default::default());
|
|
}
|
|
let values = exposed.get_mut(&return_type).unwrap();
|
|
let key = format!(":{}", AsKebabCase(format!("{}", &ident)));
|
|
if values.contains_key(&key) {
|
|
return Err(input.error(format!("already defined: {key}")))
|
|
}
|
|
values.insert(key, ident.clone());
|
|
} else {
|
|
return Err(input.error("output type must be specified"))
|
|
}
|
|
}
|
|
}
|
|
Ok(Self(block, exposed))
|
|
}
|
|
}
|
|
|
|
impl ToTokens for ExposeDef {
|
|
fn to_tokens (&self, out: &mut TokenStream2) {
|
|
let Self(_meta, data) = self;
|
|
write_quote_to(out, quote! { #data });
|
|
}
|
|
}
|
|
|
|
impl ToTokens for ExposeImpl {
|
|
fn to_tokens (&self, out: &mut TokenStream2) {
|
|
let Self(block, exposed) = self;
|
|
write_quote_to(out, quote! { #block });
|
|
for (t, variants) in exposed.iter() {
|
|
self.expose_variants(out, t, variants);
|
|
}
|
|
if exposed.len() > 0 {
|
|
//panic!("{}", quote! {#out});
|
|
}
|
|
}
|
|
}
|
|
|
|
fn is_num (t: &impl AsRef<str>) -> bool {
|
|
return matches!(t.as_ref(),
|
|
| "u8" | "u16" | "u32" | "u64" | "usize"
|
|
| "i8" | "i16" | "i32" | "i64" | "isize") }
|
|
|
|
impl ExposeImpl {
|
|
fn expose_variants (
|
|
&self, out: &mut TokenStream2, t: &ExposeType, variants: &BTreeMap<String, Ident>
|
|
) {
|
|
let Self(ItemImpl { self_ty: state, .. }, ..) = self;
|
|
let type_is = format!("{}", quote! { #t });
|
|
let variants = variants.iter().map(|(key, value)|{
|
|
let key = LitStr::new(&key, Span::call_site());
|
|
quote! { Some(#key) => Ok(Some(state.#value())), }
|
|
});
|
|
write_quote_to(out, if &type_is == "bool" {
|
|
quote! {
|
|
/// Generated by [tengri_proc::expose].
|
|
impl ::tengri::dsl::FromDsl<#state> for #t {
|
|
fn from_dsl (state: &#state, dsl: &impl Dsl) -> Perhaps<Self> {
|
|
match dsl.key()? {
|
|
Some("true") => Ok(Some(true)),
|
|
Some("false") => Ok(Some(false)),
|
|
_ => match dsl.sym()? { #(#variants)* _ => Ok(None) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if is_num(&type_is) {
|
|
quote! {
|
|
/// Generated by [tengri_proc::expose].
|
|
impl ::tengri::dsl::FromDsl<#state> for #t {
|
|
fn from_dsl (state: &#state, dsl: &impl Dsl) -> Perhaps<Self> {
|
|
match dsl.num()? {
|
|
Some(n) => Ok(Some(n.parse::<#t>()?)),
|
|
_ => match dsl.sym()? { #(#variants)* _ => Ok(None) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
quote! {
|
|
/// Generated by [tengri_proc::expose].
|
|
impl ::tengri::dsl::FromDsl<#state> for #t {
|
|
fn from_dsl (state: &#state, dsl: &impl Dsl) -> Perhaps<Self> {
|
|
match dsl.sym()? { #(#variants)* _ => Ok(None) }
|
|
}
|
|
}
|
|
}
|
|
})
|
|
//let arms = variants.iter().map(|(key, value)|{
|
|
//let key = LitStr::new(&key, Span::call_site());
|
|
//quote! { #key => state.#value(), }
|
|
//});
|
|
//if &type_is == "bool" {
|
|
//return quote! {
|
|
//::tengri::dsl::Val::Sym(s) => match s.as_ref() {
|
|
//":true" => true,
|
|
//":false" => false,
|
|
//#variants
|
|
//_ => { return Ok(None) }
|
|
//},
|
|
//}
|
|
//}
|
|
//if matches!(type_is.as_str(),
|
|
//"u8" | "u16" | "u32" | "u64" | "usize" |
|
|
//"i8" | "i16" | "i32" | "i64" | "isize")
|
|
//{
|
|
//let num_err = LitStr::new(
|
|
//&format!("{{n}}: failed to convert to {type_is}"),
|
|
//Span::call_site()
|
|
//);
|
|
//return quote! {
|
|
//::tengri::dsl::Val::Num(n) => TryInto::<#t>::try_into(n)
|
|
//.unwrap_or_else(|_|panic!(#num_err)),
|
|
//::tengri::dsl::Val::Sym(s) => match s.as_ref() {
|
|
//#variants
|
|
//_ => { return Ok(None) }
|
|
//},
|
|
//}
|
|
//}
|
|
//let arms = quote! {
|
|
//::tengri::dsl::Val::Sym(s) => match s.as_ref() {
|
|
//#variants
|
|
//_ => { return Ok(None) }
|
|
//},
|
|
//};
|
|
//let builtins =
|
|
//write_quote_to(out, quote! {
|
|
///// Generated by [tengri_proc::expose].
|
|
//impl ::tengri::dsl::FromDsl<#state> for #t {
|
|
//fn from_dsl (state: &#state, dsl: &impl Dsl) -> Perhaps<Self> {
|
|
//$builtins
|
|
//$defined
|
|
//Ok(None)
|
|
//}
|
|
//}
|
|
//});
|
|
}
|
|
}
|
|
|
|
impl From<LitStr> for ExposeSym { fn from (this: LitStr) -> Self { Self(this) } }
|
|
|
|
impl PartialOrd for ExposeSym {
|
|
fn partial_cmp (&self, other: &Self) -> Option<Ordering> {
|
|
let this = &self.0;
|
|
let that = &other.0;
|
|
Some(format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that })))
|
|
}
|
|
}
|
|
|
|
impl Ord for ExposeSym {
|
|
fn cmp (&self, other: &Self) -> Ordering {
|
|
let this = &self.0;
|
|
let that = &other.0;
|
|
format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that }))
|
|
}
|
|
}
|
|
|
|
impl PartialEq for ExposeSym {
|
|
fn eq (&self, other: &Self) -> bool {
|
|
let this = &self.0;
|
|
let that = &other.0;
|
|
format!("{}", quote! { #this }) == format!("{}", quote! { #that })
|
|
}
|
|
}
|
|
|
|
impl Eq for ExposeSym {}
|
|
|
|
impl From<Type> for ExposeType { fn from (this: Type) -> Self { Self(Box::new(this)) } }
|
|
|
|
impl PartialOrd for ExposeType {
|
|
fn partial_cmp (&self, other: &Self) -> Option<Ordering> {
|
|
let this = &self.0;
|
|
let that = &other.0;
|
|
Some(format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that })))
|
|
}
|
|
}
|
|
|
|
impl Ord for ExposeType {
|
|
fn cmp (&self, other: &Self) -> Ordering {
|
|
let this = &self.0;
|
|
let that = &other.0;
|
|
format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that }))
|
|
}
|
|
}
|
|
|
|
impl PartialEq for ExposeType {
|
|
fn eq (&self, other: &Self) -> bool {
|
|
let this = &self.0;
|
|
let that = &other.0;
|
|
format!("{}", quote! { #this }) == format!("{}", quote! { #that })
|
|
}
|
|
}
|
|
|
|
impl Eq for ExposeType {}
|
|
|
|
impl ToTokens for ExposeType {
|
|
fn to_tokens (&self, out: &mut TokenStream2) {
|
|
self.0.to_tokens(out)
|
|
}
|
|
}
|