diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index 40f8140..ac1e2a9 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -4,133 +4,72 @@ use crate::*; pub(crate) struct CommandDef(pub(crate) CommandMeta, pub(crate) CommandImpl); #[derive(Debug, Clone)] -pub(crate) struct CommandMeta(Ident); +pub(crate) struct CommandMeta { + target: Ident, +} #[derive(Debug, Clone)] pub(crate) struct CommandImpl(ItemImpl, BTreeMap, CommandArm>); #[derive(Debug, Clone)] -struct CommandArm(Ident, Vec, ReturnType); +struct CommandVariant(Ident, Vec); #[derive(Debug, Clone)] -struct CommandVariant(Ident, Vec); +struct CommandArm(Arc, Ident, Vec, ReturnType); impl Parse for CommandMeta { fn parse (input: ParseStream) -> Result { - Ok(Self(input.parse::()?)) + Ok(Self { + target: input.parse::()?, + }) } } impl Parse for CommandImpl { fn parse (input: ParseStream) -> Result { - let block = input.parse::()?; - let exposed = Self::collect(&block.items).map_err(|e|input.error(e))?; - Ok(Self(block, exposed)) - } -} - -impl CommandImpl { - fn collect (items: &Vec) - -> std::result::Result, CommandArm>, String> - { + let block = input.parse::()?; let mut exposed: BTreeMap, CommandArm> = Default::default(); - for item in items.iter() { - if let ImplItem::Fn( - ImplItemFn { sig: Signature { ident, inputs, output, .. }, .. } - ) = item { - let key = CommandArm::ident_to_key(&ident); + for item in block.items.iter() { + if let ImplItem::Fn(ImplItemFn { + sig: Signature { ident, inputs, output, .. }, .. + }) = item { + let key: Arc = + format!("{}", AsKebabCase(format!("{}", &ident))).into(); + let variant: Arc = + format!("{}", AsUpperCamelCase(format!("{}", &ident))).into(); if exposed.contains_key(&key) { - return Err(format!("already defined: {ident}")); + 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(exposed) - } -} - -impl CommandArm { - fn to_key (&self) -> Arc { - Self::ident_to_key(&self.0) - } - fn to_enum_variant (&self) -> CommandVariant { - CommandVariant(self.to_enum_variant_ident(), self.1.clone()) - } - fn to_enum_variant_ident (&self) -> Ident { - Ident::new(&Self::ident_to_enum_variant(&self.0), Span::call_site()) - } - fn ident_to_key (ident: &Ident) -> Arc { - format!("{}", AsKebabCase(format!("{ident}"))).into() - } - fn ident_to_enum_variant (ident: &Ident) -> Arc { - format!("{}", AsUpperCamelCase(format!("{ident}"))).into() - } - fn to_matcher (&self) -> TokenStream2 { - let mut out = TokenStream2::new(); - let key = LitStr::new(&self.to_key(), Span::call_site()); - let ident = &self.0; - let mut take_args = vec![TokenStream2::new();0]; - let mut take_rest = TokenStream2::new(); - for token in quote! { - Some(::tengri::dsl::Token { value: Value::Key(#key), .. }) => { - let mut iter = iter.clone(); - #(#take_args)* - #(#take_rest)? - self.#ident() - }, - } { - out.append(token); - } - out - //$(Some(Token { value: Value::Key($key), .. }) => { - //let mut iter = iter.clone(); - //$( - //let next = iter.next(); - //if next.is_none() { panic!("no argument: {}", stringify!($arg)); } - //let $arg = next.unwrap(); - //$(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? - //)* - //$(let $rest = iter.clone();)? - //return $command - //}),* - } - fn to_implementation (&self) -> TokenStream2 { - let mut out = TokenStream2::new(); - let mut variant = TokenStream2::new(); - let mut call = TokenStream2::new(); - for token in quote! { - #variant => #call, - } { - out.append(token); - } - out + 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 variants = exposed.values().map(CommandArm::to_enum_variant); - let matchers = exposed.values().map(CommandArm::to_matcher); - let implementations = exposed.values().map(CommandArm::to_implementation); + 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 { - #(#variants)* - } - impl<'a> TryFromDsl<'a, #target> for #enumeration { - fn try_from_expr (state: &#target, iter: TokenIter) -> Option { - let mut iter = iter.clone(); - match iter.next() { - #(#matchers)* - _ => None - } - } + #(#definitions)* } impl Command<#target> for #enumeration { fn execute (self, state: &mut #target) -> Perhaps { @@ -142,9 +81,6 @@ impl ToTokens for CommandDef { } { out.append(token) } - if exposed.len() > 0 { - panic!("{}", quote! {#out}); - } } } @@ -172,30 +108,34 @@ impl ToTokens for CommandVariant { impl ToTokens for CommandArm { fn to_tokens (&self, out: &mut TokenStream2) { - let Self(ident, args, returnType) = self; - for ident in ["tengri", "dsl", "Value", "Sym"].iter() { - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new(ident, Span::call_site())); - } + 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(); - out.append(self.to_enum_variant_ident()); 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(Ident::new("self", Span::call_site())); - out.append(Punct::new('.', Alone)); - out.append(ident.clone()); + 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(&self.to_key(), Span::call_site()).token()); - out.append(Punct::new(',', Alone)); + //out.append(LitStr::new(&symbol, Span::call_site()).token()); } out })); diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index 9315f2e..bf7ae58 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -81,7 +81,7 @@ impl ToTokens for ExposeImpl { ], _ => vec![], }; - let values = variants.iter().map(|(k, v)|ExposeArm(k.clone(), v.clone())); + let values = variants.values(); let trait_impl = quote! { impl ::tengri::dsl::Context<#t> for #target { fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> { @@ -97,9 +97,6 @@ impl ToTokens for ExposeImpl { out.append(token); } } - //if exposed.len() > 0 { - //panic!("{}", quote! {#out}); - //} } } @@ -125,12 +122,9 @@ impl ToTokens for ExposeArm { })); out.append(Punct::new('=', Joint)); out.append(Punct::new('>', Alone)); - out.append(Ident::new("self", Span::call_site())); - out.append(Punct::new('.', Alone)); for token in quote! { #value } { out.append(token); } - out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new())); } }