add support for different types of mutability
parent
15678fe80f
commit
49dae204b8
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,13 @@ use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::token::{Mut, SelfValue};
|
use syn::token::{Mut, SelfValue};
|
||||||
use syn::visit_mut::VisitMut;
|
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;
|
mod parse;
|
||||||
use parse::Args;
|
use parse::Args;
|
||||||
|
mod intermediate_structs;
|
||||||
|
mod lette;
|
||||||
|
use intermediate_structs::*;
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn program(
|
pub fn program(
|
||||||
|
@ -30,33 +33,6 @@ pub fn program(
|
||||||
proc_macro::TokenStream::from(out)
|
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
|
/// takes in the function contents, and returns the structs n stuff
|
||||||
fn rewrite_item_into_struct(func: ItemFn, args: Args) -> TokenStream {
|
fn rewrite_item_into_struct(func: ItemFn, args: Args) -> TokenStream {
|
||||||
let prog_name = (&args.name).clone().unwrap();
|
let prog_name = (&args.name).clone().unwrap();
|
||||||
|
@ -87,82 +63,6 @@ fn rewrite_item_into_struct(func: ItemFn, args: Args) -> TokenStream {
|
||||||
TokenStream::from(out)
|
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 {
|
fn impls(prog_name: &Ident, intermediate_structs: &Vec<IntermediateStruct>) -> TokenStream {
|
||||||
let mut impls = vec![];
|
let mut impls = vec![];
|
||||||
let mut id = quote!(#prog_name);
|
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
|
// then change the parameters so the handler is the first
|
||||||
// get the effect's index, and add the inverse num of `.0`s
|
// get the effect's index, and add the inverse num of `.0`s
|
||||||
let idx = eff_len - (i + 1);
|
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();
|
let expr: Expr = syn::parse_str(&s).unwrap();
|
||||||
node.args.insert(0, expr);
|
node.args.insert(0, expr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use effers::program;
|
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 {
|
fn smth(val: u8) -> u8 {
|
||||||
p("hey hi hello");
|
p("hey hi hello");
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ fn smth(val: u8) -> u8 {
|
||||||
val + 3
|
val + 3
|
||||||
}
|
}
|
||||||
|
|
||||||
#[program(Printer(print as p))]
|
#[program(Printer(mut print as p))]
|
||||||
fn other_program() {
|
fn other_program() {
|
||||||
p("hey hi hello");
|
p("hey hi hello");
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Printer {
|
trait Printer {
|
||||||
fn print(&mut self, s: &str);
|
fn print(&self, s: &str);
|
||||||
}
|
}
|
||||||
trait Logger {
|
trait Logger {
|
||||||
fn debug(&mut self, s: &str);
|
fn debug(&mut self, s: &str);
|
||||||
|
@ -41,7 +41,7 @@ trait Logger {
|
||||||
|
|
||||||
struct IoPrinter;
|
struct IoPrinter;
|
||||||
impl Printer for IoPrinter {
|
impl Printer for IoPrinter {
|
||||||
fn print(&mut self, s: &str) {
|
fn print(&self, s: &str) {
|
||||||
println!("{}", s)
|
println!("{}", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,12 @@ fn prog(val: u8) -> u8 {
|
||||||
|
|
||||||
mod inc {
|
mod inc {
|
||||||
pub trait Incrementer {
|
pub trait Incrementer {
|
||||||
fn increment(&mut self, v: u8) -> u8;
|
fn increment(&self, v: u8) -> u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestInc;
|
pub struct TestInc;
|
||||||
impl Incrementer for TestInc {
|
impl Incrementer for TestInc {
|
||||||
fn increment(&mut self, v: u8) -> u8 {
|
fn increment(&self, v: u8) -> u8 {
|
||||||
v + 3
|
v + 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -4,21 +4,21 @@ pub use effers_derive::program;
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// #[program(Smth => Printer(print as p), Logger(debug, info), inc::Incrementer(increment))]
|
#[program(Smth => Printer(print as p), Logger(mut debug, mut info), inc::Incrementer(mut increment))]
|
||||||
// fn smth(val: u8) -> u8 {
|
fn smth(val: u8) -> u8 {
|
||||||
// let s = p("hey hi hello");
|
let s = p("hey hi hello");
|
||||||
|
|
||||||
// debug("this is a debug-level log");
|
debug("this is a debug-level log");
|
||||||
// info("this is a info-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 x = increment(val);
|
||||||
// let y = increment(x);
|
let y = increment(x);
|
||||||
// x + y
|
x + y
|
||||||
// }
|
}
|
||||||
|
|
||||||
trait Printer {
|
trait Printer {
|
||||||
fn print(&self, s: &str) -> &str;
|
fn print(&self, s: &str) -> &str;
|
||||||
|
|
Loading…
Reference in New Issue