summaryrefslogtreecommitdiff
path: root/varihappy-macros/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'varihappy-macros/src/lib.rs')
-rw-r--r--varihappy-macros/src/lib.rs283
1 files changed, 171 insertions, 112 deletions
diff --git a/varihappy-macros/src/lib.rs b/varihappy-macros/src/lib.rs
index 522d333..3931899 100644
--- a/varihappy-macros/src/lib.rs
+++ b/varihappy-macros/src/lib.rs
@@ -2,139 +2,198 @@ extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Literal, Span};
-use quote::quote;
-use syn::{Field, LitInt};
+use quote::{format_ident, quote};
+use syn::LitInt;
+use unsynn::{
+ Comma, CommaDelimitedVec, Cons, Either, GroupContaining, IParse, LiteralInteger, TokenIter,
+};
-#[proc_macro]
-pub fn concat_idents(input: TokenStream) -> TokenStream {
+fn number_to_type(mut number: u128) -> String {
let mut buffer = String::new();
- for token in input {
- buffer.push_str(&token.to_string());
+ while number > 25 {
+ buffer.push({
+ let digit = number % 26;
+ number /= 26;
+ match digit {
+ 0 => 'A',
+ 1 => 'B',
+ 2 => 'C',
+ 3 => 'D',
+ 4 => 'E',
+ 5 => 'F',
+ 6 => 'G',
+ 7 => 'H',
+ 8 => 'I',
+ 9 => 'J',
+ 10 => 'K',
+ 11 => 'L',
+ 12 => 'M',
+ 13 => 'N',
+ 14 => 'O',
+ 15 => 'P',
+ 16 => 'Q',
+ 17 => 'R',
+ 18 => 'S',
+ 19 => 'T',
+ 20 => 'U',
+ 21 => 'V',
+ 22 => 'W',
+ 23 => 'X',
+ 24 => 'Y',
+ 25 => 'Z',
+ _ => panic!("Expected a number less than 26"),
+ }
+ });
}
- let mut stream = proc_macro2::TokenStream::new();
- stream.extend([Ident::new(&buffer, Span::call_site())]);
- stream.into()
-}
-
-#[proc_macro]
-pub fn number_to_generic(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let identifier = Ident::new(
- match number {
- 0 => "A",
- 1 => "B",
- 2 => "C",
- 3 => "D",
- 4 => "E",
- 5 => "F",
- 6 => "G",
- 7 => "H",
- 8 => "I",
- 9 => "J",
- 10 => "K",
- 11 => "L",
- 12 => "M",
- 13 => "N",
- 14 => "O",
- 15 => "P",
- 16 => "Q",
- 17 => "R",
- 18 => "S",
- 19 => "T",
- 20 => "U",
- 21 => "V",
- 22 => "W",
- 23 => "X",
- 24 => "Y",
- 25 => "Z",
- _ => panic!("Expected a number less than 26"),
- },
- Span::call_site(),
- );
-
- quote! { #identifier }.into()
-}
-
-#[proc_macro]
-pub fn tuple_type_len(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = 0..number;
- quote! { (#(::varihappy_macros::number_to_generic!(#num),)*) }.into()
-}
-
-#[proc_macro]
-pub fn tuple_type_ref(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = 0..number;
- quote! { (#(&'a ::varihappy_macros::number_to_generic!(#num),)*) }.into()
+ buffer.push(match number {
+ 0 => 'A',
+ 1 => 'B',
+ 2 => 'C',
+ 3 => 'D',
+ 4 => 'E',
+ 5 => 'F',
+ 6 => 'G',
+ 7 => 'H',
+ 8 => 'I',
+ 9 => 'J',
+ 10 => 'K',
+ 11 => 'L',
+ 12 => 'M',
+ 13 => 'N',
+ 14 => 'O',
+ 15 => 'P',
+ 16 => 'Q',
+ 17 => 'R',
+ 18 => 'S',
+ 19 => 'T',
+ 20 => 'U',
+ 21 => 'V',
+ 22 => 'W',
+ 23 => 'X',
+ 24 => 'Y',
+ 25 => 'Z',
+ _ => panic!("Expected a number less than 26"),
+ });
+
+ buffer.chars().rev().collect()
}
#[proc_macro]
-pub fn tuple_type_mut(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = 0..number;
- quote! { (#(&'a mut ::varihappy_macros::number_to_generic!(#num),)*) }.into()
+pub fn tuple_new(input: TokenStream) -> TokenStream {
+ let input: proc_macro2::TokenStream = input.into();
+ let mut token_iter = TokenIter::new(input);
+ let ast: Cons<Either<LiteralInteger, GroupContaining<LiteralInteger>>, Comma, unsynn::Ident> =
+ token_iter.parse().unwrap();
+
+ let number = ast.first.fold2(|x| x, |x| x.content);
+ let number_value = number.value();
+ let number_token = number.into_inner();
+ let types =
+ (0..number_value).map(|number| Ident::new(&number_to_type(number), number_token.span()));
+ let ident = Ident::new(&ast.third.to_string(), ast.third.span());
+ quote! { #ident! { (#(#types,)*) } }.into()
}
#[proc_macro]
-pub fn reverse_tuple_type(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = (0..number).rev();
- quote! { (#(::varihappy_macros::number_to_generic!(#num),)*) }.into()
+pub fn tuple_reverse(input: TokenStream) -> TokenStream {
+ let tuple = syn::parse_macro_input!(input as syn::TypeTuple);
+ let reversed_tuple = tuple.elems.iter().rev();
+ quote! { (#(#reversed_tuple,)*) }.into()
}
#[proc_macro]
-pub fn tuple_type_len_rest(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = 1..number;
- quote! { (#(::varihappy_macros::number_to_generic!(#num),)*) }.into()
+pub fn tuple_expr_reverse(input: TokenStream) -> TokenStream {
+ let input: proc_macro2::TokenStream = input.into();
+ let mut token_iter = TokenIter::new(input);
+ let ast: Cons<
+ unsynn::Ident,
+ Comma,
+ unsynn::ParenthesisGroupContaining<CommaDelimitedVec<unsynn::Ident>>,
+ > = token_iter.parse().unwrap();
+
+ let self_id = ast.first;
+ let reversed_tuple = ast.third.content.into_iter().rev().map(|x| x.value);
+ quote! {{
+ let this = #self_id;
+ (#(::varihappy_macros::type_to_field_access!(#reversed_tuple),)*)
+ }}
+ .into()
}
#[proc_macro]
-pub fn tuple_expr_ref(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = (0..number).map(Literal::u128_unsuffixed);
- quote! { (#(&self.#num,)*) }.into()
-}
-
-#[proc_macro]
-pub fn tuple_expr_mut(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
+pub fn type_to_field_access(input: TokenStream) -> TokenStream {
+ let input: proc_macro2::TokenStream = input.into();
+ let mut token_iter = TokenIter::new(input);
+ let type_name: unsynn::Ident = token_iter.parse().unwrap();
+ let mut type_name = type_name.to_string();
+ type_name.make_ascii_lowercase();
+
+ let mut number = 0;
+ for char in type_name.chars() {
+ number *= 26;
+ number += match char {
+ 'a' => 0,
+ 'b' => 1,
+ 'c' => 2,
+ 'd' => 3,
+ 'e' => 4,
+ 'f' => 5,
+ 'g' => 6,
+ 'h' => 7,
+ 'i' => 8,
+ 'j' => 9,
+ 'k' => 10,
+ 'l' => 11,
+ 'm' => 12,
+ 'n' => 13,
+ 'o' => 14,
+ 'p' => 15,
+ 'q' => 16,
+ 'r' => 17,
+ 's' => 18,
+ 't' => 19,
+ 'u' => 20,
+ 'v' => 21,
+ 'w' => 22,
+ 'x' => 23,
+ 'y' => 24,
+ 'z' => 25,
+ _ => panic!("invalid type name"),
+ };
+ }
- let num = (0..number).map(Literal::u128_unsuffixed);
- quote! { (#(&mut self.#num,)*) }.into()
+ let number = Literal::u128_unsuffixed(number);
+ quote! { this.#number }.into()
}
#[proc_macro]
-pub fn reverse_expr_type(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = (0..number).rev().map(Literal::u128_unsuffixed);
- quote! { (#(self.#num,)*) }.into()
+pub fn repeat(input: TokenStream) -> TokenStream {
+ let input: proc_macro2::TokenStream = input.into();
+ let mut token_iter = TokenIter::new(input);
+ let ast: Cons<LiteralInteger, Comma, unsynn::Ident> = token_iter.parse().unwrap();
+
+ let numbers = (2..=ast.first.value()).map(Literal::u128_unsuffixed);
+ let macro_name = ast.third;
+ quote! { #(#macro_name!(#numbers);)* }.into()
}
#[proc_macro]
-pub fn tuple_expr_len_rest(input: TokenStream) -> TokenStream {
- let number = syn::parse_macro_input!(input as LitInt);
- let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX");
-
- let num = (1..number).map(Literal::u128_unsuffixed);
- quote! { (#(self.#num,)*) }.into()
+pub fn tuple_trait_def(input: TokenStream) -> TokenStream {
+ let input: proc_macro2::TokenStream = input.into();
+ let mut token_iter = TokenIter::new(input);
+ let ast: Cons<Either<LiteralInteger, GroupContaining<LiteralInteger>>, Comma, unsynn::Ident> =
+ token_iter.parse().unwrap();
+
+ let number = ast.first.fold2(|x| x, |x| x.content);
+ let number = number.value();
+ let minus1 = number - 1;
+
+ let trait_name = format_ident!("Tuple{number}");
+ let other_trait = format_ident!("Tuple{minus1}");
+ let item_type = format_ident!("Item{minus1}");
+ let item_fn = format_ident!("into_{minus1}");
+ let ident = ast.third;
+ quote! { #ident! { trait #trait_name for #other_trait { type #item_type; fn #item_fn; }} }
+ .into()
}