add support for different types of mutability

main
annieversary 2022-01-21 10:50:14 +00:00
parent 15678fe80f
commit 49dae204b8
6 changed files with 130 additions and 122 deletions

View File

@ -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<Path>,
pub letters: Vec<Ident>,
pub generics: TokenStream,
}
impl IntermediateStruct {
pub fn new(
tokens: TokenStream,
id: Ident,
traits: Vec<Path>,
letters: Vec<Ident>,
generics: TokenStream,
) -> Self {
Self {
tokens,
id,
traits,
letters,
generics,
}
}
}
pub fn intermediate_structs(args: &Args, prog_name: &Ident) -> Vec<IntermediateStruct> {
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::<TokenStream>();
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::<TokenStream>();
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::<Vec<_>>(),
generics,
));
(structs, name, traits)
},
)
.0
}

View File

@ -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<Self::Item> {
for _ in 0..100 {
self.idx += 1;
if let Some(c) = char::from_u32(self.idx) {
return Some(c);
}
}
None
}
}

View File

@ -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<Self::Item> {
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<Path>,
letters: Vec<Ident>,
generics: TokenStream,
}
impl IntermediateStruct {
fn new(
tokens: TokenStream,
id: Ident,
traits: Vec<Path>,
letters: Vec<Ident>,
generics: TokenStream,
) -> Self {
Self {
tokens,
id,
traits,
letters,
generics,
}
}
}
fn intermediate_structs(args: &Args, prog_name: &Ident) -> Vec<IntermediateStruct> {
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::<TokenStream>();
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::<TokenStream>();
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::<Vec<_>>(),
generics,
));
(structs, name, traits)
},
)
.0
}
fn impls(prog_name: &Ident, intermediate_structs: &Vec<IntermediateStruct>) -> 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);
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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;