diff --git a/effers-derive/src/intermediate_structs.rs b/effers-derive/src/intermediate_structs.rs new file mode 100644 index 0000000..162658a --- /dev/null +++ b/effers-derive/src/intermediate_structs.rs @@ -0,0 +1,81 @@ +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::{Ident, Path}; + +use crate::{lette::LettersIter, Args}; + +pub struct IntermediateStruct { + pub tokens: TokenStream, + pub id: Ident, + pub traits: Vec, + pub letters: Vec, + pub generics: TokenStream, +} + +impl IntermediateStruct { + pub fn new( + tokens: TokenStream, + id: Ident, + traits: Vec, + letters: Vec, + generics: TokenStream, + ) -> Self { + Self { + tokens, + id, + traits, + letters, + generics, + } + } +} + +pub fn intermediate_structs(args: &Args, prog_name: &Ident) -> Vec { + let struct_with = format!("{}With", prog_name); + args.effects + .iter() + .fold( + (vec![], struct_with, vec![]), + |(mut structs, name, mut traits), eff| { + let name = format!("{}{}", &name, &eff.name); + + traits.push(eff.path.clone()); + + // kinda messy + let letters = LettersIter::new() + .take(traits.len()) + .map(|c| Ident::new(&c.to_string(), Span::call_site())); + let generics = traits + .iter() + .zip(letters.clone()) + .map(|(t, c)| quote!(#c: #t,)) + .collect::(); + + let id = Ident::new(&name, Span::call_site()); + let last = if let Some(&IntermediateStruct { + ref id, + ref letters, + .. + }) = &structs.last() + { + let gen = letters.iter().map(|l| quote!(#l,)).collect::(); + quote!(#id<#gen>) + } else { + quote!(#prog_name) + }; + let last_letter = letters.clone().last(); + structs.push(IntermediateStruct::new( + quote! { + struct #id<#generics>(#last, #last_letter); + }, + id, + traits.clone(), + letters.collect::>(), + generics, + )); + + (structs, name, traits) + }, + ) + .0 +} diff --git a/effers-derive/src/lette.rs b/effers-derive/src/lette.rs new file mode 100644 index 0000000..7970a0d --- /dev/null +++ b/effers-derive/src/lette.rs @@ -0,0 +1,26 @@ +#[derive(Clone, Copy)] +pub struct LettersIter { + idx: u32, +} + +impl LettersIter { + pub fn new() -> Self { + Self { + idx: 'A' as u32 - 1, + } + } +} +impl Iterator for LettersIter { + type Item = char; + + fn next(&mut self) -> Option { + for _ in 0..100 { + self.idx += 1; + if let Some(c) = char::from_u32(self.idx) { + return Some(c); + } + } + + None + } +} diff --git a/effers-derive/src/lib.rs b/effers-derive/src/lib.rs index fdaa407..63aae2f 100644 --- a/effers-derive/src/lib.rs +++ b/effers-derive/src/lib.rs @@ -3,10 +3,13 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::token::{Mut, SelfValue}; use syn::visit_mut::VisitMut; -use syn::{parse_macro_input, Expr, ExprCall, FnArg, Ident, ItemFn, Path, PathSegment, Receiver}; +use syn::{parse_macro_input, Expr, ExprCall, FnArg, Ident, ItemFn, PathSegment, Receiver}; mod parse; use parse::Args; +mod intermediate_structs; +mod lette; +use intermediate_structs::*; #[proc_macro_attribute] pub fn program( @@ -30,33 +33,6 @@ pub fn program( proc_macro::TokenStream::from(out) } -#[derive(Clone, Copy)] -struct LettersIter { - idx: u32, -} - -impl LettersIter { - fn new() -> Self { - Self { - idx: 'A' as u32 - 1, - } - } -} -impl Iterator for LettersIter { - type Item = char; - - fn next(&mut self) -> Option { - for _ in 0..100 { - self.idx += 1; - if let Some(c) = char::from_u32(self.idx) { - return Some(c); - } - } - - None - } -} - /// takes in the function contents, and returns the structs n stuff fn rewrite_item_into_struct(func: ItemFn, args: Args) -> TokenStream { let prog_name = (&args.name).clone().unwrap(); @@ -87,82 +63,6 @@ fn rewrite_item_into_struct(func: ItemFn, args: Args) -> TokenStream { TokenStream::from(out) } -struct IntermediateStruct { - tokens: TokenStream, - id: Ident, - traits: Vec, - letters: Vec, - generics: TokenStream, -} - -impl IntermediateStruct { - fn new( - tokens: TokenStream, - id: Ident, - traits: Vec, - letters: Vec, - generics: TokenStream, - ) -> Self { - Self { - tokens, - id, - traits, - letters, - generics, - } - } -} - -fn intermediate_structs(args: &Args, prog_name: &Ident) -> Vec { - let struct_with = format!("{}With", prog_name); - args.effects - .iter() - .fold( - (vec![], struct_with, vec![]), - |(mut structs, name, mut traits), eff| { - let name = format!("{}{}", &name, &eff.name); - - traits.push(eff.path.clone()); - - // kinda messy - let letters = LettersIter::new() - .take(traits.len()) - .map(|c| Ident::new(&c.to_string(), Span::call_site())); - let generics = traits - .iter() - .zip(letters.clone()) - .map(|(t, c)| quote!(#c: #t,)) - .collect::(); - - let id = Ident::new(&name, Span::call_site()); - let last = if let Some(&IntermediateStruct { - ref id, - ref letters, - .. - }) = &structs.last() - { - let gen = letters.iter().map(|l| quote!(#l,)).collect::(); - quote!(#id<#gen>) - } else { - quote!(#prog_name) - }; - let last_letter = letters.clone().last(); - structs.push(IntermediateStruct::new( - quote! { - struct #id<#generics>(#last, #last_letter); - }, - id, - traits.clone(), - letters.collect::>(), - generics, - )); - - (structs, name, traits) - }, - ) - .0 -} - fn impls(prog_name: &Ident, intermediate_structs: &Vec) -> TokenStream { let mut impls = vec![]; let mut id = quote!(#prog_name); @@ -268,7 +168,8 @@ impl<'a> syn::visit_mut::VisitMut for FuncRewriter<'a> { // then change the parameters so the handler is the first // get the effect's index, and add the inverse num of `.0`s let idx = eff_len - (i + 1); - let s = format!("&mut self{}.1", ".0".repeat(idx)); + let m = if func.mut_token.is_some() { "mut " } else { "" }; + let s = format!("&{}self{}.1", m, ".0".repeat(idx)); let expr: Expr = syn::parse_str(&s).unwrap(); node.args.insert(0, expr); } diff --git a/examples/main.rs b/examples/main.rs index 35b11fe..24cda27 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -1,6 +1,6 @@ use effers::program; -#[program(Smth => Printer(print as p), Logger(debug, info))] +#[program(Smth => Printer(print as p), Logger(mut debug, mut info))] fn smth(val: u8) -> u8 { p("hey hi hello"); @@ -10,7 +10,7 @@ fn smth(val: u8) -> u8 { val + 3 } -#[program(Printer(print as p))] +#[program(Printer(mut print as p))] fn other_program() { p("hey hi hello"); } @@ -32,7 +32,7 @@ fn main() { } trait Printer { - fn print(&mut self, s: &str); + fn print(&self, s: &str); } trait Logger { fn debug(&mut self, s: &str); @@ -41,7 +41,7 @@ trait Logger { struct IoPrinter; impl Printer for IoPrinter { - fn print(&mut self, s: &str) { + fn print(&self, s: &str) { println!("{}", s) } } diff --git a/examples/path.rs b/examples/path.rs index a9815b3..23afb9b 100644 --- a/examples/path.rs +++ b/examples/path.rs @@ -10,12 +10,12 @@ fn prog(val: u8) -> u8 { mod inc { pub trait Incrementer { - fn increment(&mut self, v: u8) -> u8; + fn increment(&self, v: u8) -> u8; } pub struct TestInc; impl Incrementer for TestInc { - fn increment(&mut self, v: u8) -> u8 { + fn increment(&self, v: u8) -> u8 { v + 3 } } diff --git a/src/lib.rs b/src/lib.rs index 211d6fb..ca2854a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,21 +4,21 @@ pub use effers_derive::program; mod test { use super::*; - // #[program(Smth => Printer(print as p), Logger(debug, info), inc::Incrementer(increment))] - // fn smth(val: u8) -> u8 { - // let s = p("hey hi hello"); + #[program(Smth => Printer(print as p), Logger(mut debug, mut info), inc::Incrementer(mut increment))] + fn smth(val: u8) -> u8 { + let s = p("hey hi hello"); - // debug("this is a debug-level log"); - // info("this is a info-level log"); + debug("this is a debug-level log"); + info("this is a info-level log"); - // let _s = p("hey hi hello"); + let _s = p("hey hi hello"); - // dbg!(s); + dbg!(s); - // let x = increment(val); - // let y = increment(x); - // x + y - // } + let x = increment(val); + let y = increment(x); + x + y + } trait Printer { fn print(&self, s: &str) -> &str;