From cb3bbdbb78f0ddc02cfa0737d605b2bccd0fc87c Mon Sep 17 00:00:00 2001 From: Thelie Date: Wed, 2 Mar 2022 19:13:31 +0100 Subject: [PATCH] macro for adding traits is done. --- sing_macros/src/lib.rs | 33 ++- sing_util/Cargo.toml | 14 +- sing_util/src/lib.rs | 44 +-- sing_util/src/serde_wrapper.rs | 71 +++++ src/lib.rs | 15 + src/serde_wrapper.rs | 482 ++++----------------------------- 6 files changed, 191 insertions(+), 468 deletions(-) create mode 100644 sing_util/src/serde_wrapper.rs diff --git a/sing_macros/src/lib.rs b/sing_macros/src/lib.rs index d10de99..25021e2 100644 --- a/sing_macros/src/lib.rs +++ b/sing_macros/src/lib.rs @@ -3,13 +3,12 @@ use std::{ env, fs, error::Error, - io::{Write, Read}, fmt::format, path::Path, + io::{Write, Read}, }; -use rand::rngs::adapter::ReseedingRng; -use serde::{Serialize, Deserialize}; -use syn::{parse_macro_input, DeriveInput, AttributeArgs, ItemImpl, ImplItem}; -use quote::{quote, spanned::Spanned}; -use proc_macro2::{Span, Spacing, Delimiter, TokenStream, Literal, TokenTree, Ident, Punct, Group}; +use sing_util::TraitProfile; +use syn::{parse_macro_input, AttributeArgs, ItemImpl, ImplItem}; +use quote::{quote, spanned::Spanned, ToTokens}; + extern crate sing_util; extern crate proc_macro; @@ -51,25 +50,26 @@ fn load_trait_state() -> Result, Box proc_macro::TokenStream { +pub fn sing_add_trait(input: proc_macro::TokenStream, annotated_item: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as ItemImpl); let annotated_item = parse_macro_input!(annotated_item as AttributeArgs); let trait_name; - match input.trait_ { + match &input.trait_ { Some((_b, p, _f)) => { - trait_name = p; + trait_name = p.into_token_stream().to_string(); }, None => { syn::Error::new(input.__span(), "This attribute can only be used on trait impl blocks.") .to_compile_error(); + trait_name = String::from(""); }, }; let mut trait_functions = vec!(); - for fun in input.items { + for fun in &input.items { match fun { - ImplItem::Method(m) => trait_functions.push(m.sig), + ImplItem::Method(m) => trait_functions.push(m.sig.to_token_stream()), _ => { syn::Error::new(input.__span(), "Found unexpected item that is not a method.") .to_compile_error(); @@ -77,8 +77,17 @@ pub fn my_derive(input: proc_macro::TokenStream, annotated_item: proc_macro::To } } - let trait_state = load_trait_state().unwrap(); + let mut trait_state = load_trait_state().unwrap(); + let profile = TraitProfile::new(trait_functions); + if trait_state.contains_key(trait_name.as_str()) { + let err = format!("Trait {} is implemented twice!", trait_name); + syn::Error::new(input.__span(), err.as_str()) + .to_compile_error(); + } else { + trait_state.insert(trait_name, profile); + } + save_trait_state(trait_state).unwrap(); // Build the output, possibly using quasi-quotation diff --git a/sing_util/Cargo.toml b/sing_util/Cargo.toml index c936ca5..9568ee2 100644 --- a/sing_util/Cargo.toml +++ b/sing_util/Cargo.toml @@ -2,11 +2,17 @@ name = "sing_util" version = "0.1.0" edition = "2021" + +[lib] +bench = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - +# build = "build.rs" +# +# [build-dependencies] +# lalrpop = "0.19" +# [dependencies] -ron = "0.7" -rand = "0.7" serde = { version = "1.0", features = ["derive"] } - +syn = { version = "1.0", features = ["full"] } +proc-macro2 = "1.0" diff --git a/sing_util/src/lib.rs b/sing_util/src/lib.rs index c9b2daa..914ed90 100644 --- a/sing_util/src/lib.rs +++ b/sing_util/src/lib.rs @@ -1,37 +1,37 @@ -use std::{ - collections::HashMap, - env, - fs, - error::Error, - io::{Write, Read}, fmt::format, -}; -use rand::rngs::adapter::ReseedingRng; -use serde::{Serialize, Deserialize}; +use core::fmt::Debug; -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct FunctionProfile{ - inputs: String, - outputs: String, -} +use proc_macro2::TokenStream; +use serde::{Serialize, Deserialize}; +use serde_wrapper::TokenStreamWrapper; + +mod serde_wrapper; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TraitProfile{ - functions: HashMap, -} + //functions: HashMap, + functions: Vec, +} -impl TraitProfile { - pub fn get_fun_profile(&self, query: &String) -> Option<&FunctionProfile> { - self.functions.get(query) +impl TraitProfile{ + pub fn new(streams: Vec) -> Self { + let mut inner = vec!(); + + for stream in streams { + inner.push(TokenStreamWrapper::new(stream)); + } + + Self{ + functions: inner + } } } #[derive(Debug, Clone)] enum DeduplicatedFunctionProfile { - Single(String, FunctionProfile), - Multiple(Vec, FunctionProfile), + Single(String, TokenStreamWrapper), + Multiple(Vec, TokenStreamWrapper), } - /*impl Evaluator { fn deduplicate_functions(&self) -> Self { let mut self = self.clone(); diff --git a/sing_util/src/serde_wrapper.rs b/sing_util/src/serde_wrapper.rs new file mode 100644 index 0000000..3075c97 --- /dev/null +++ b/sing_util/src/serde_wrapper.rs @@ -0,0 +1,71 @@ +use std::{str::FromStr, fmt::{self, format}}; + +use proc_macro2::TokenStream; +use serde::{Serialize, Serializer, Deserialize, Deserializer, de::{Visitor, self}}; + +#[derive(Debug, Clone)] +pub struct TokenStreamWrapper(TokenStream); + +impl TokenStreamWrapper { + pub fn new(stream: TokenStream) -> Self { + Self(stream) + } +} + +impl Serialize for TokenStreamWrapper { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer + { + let inner = &self.0; + serializer.serialize_newtype_struct("Lifetime", &inner.to_string()) + } +} + +impl<'de> Deserialize<'de> for TokenStreamWrapper { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> + { + let tok_str = deserializer.deserialize_string(TokenStreamVisitor)?; + + match TokenStream::from_str(&tok_str.as_str()) { + Ok(t) => Ok(Self(t)), + Err(e) => Err(de::Error::custom( + format!("string does not represent a valid TokenStream: {}", e) + )) + } + } +} + +struct TokenStreamVisitor; + +impl<'de> Visitor<'de> for TokenStreamVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("A string representing a TokenStream") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(value.to_string()) + } + + fn visit_borrowed_str(self, value: &'de str) -> Result + where + E: de::Error, + { + Ok(value.to_string()) + } + + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + Ok(value) + } + +} diff --git a/src/lib.rs b/src/lib.rs index 27b151e..66c12b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ use core::fmt::Debug; +use proc_macro2::TokenStream; use serde::{Serialize, Deserialize}; use serde_wrapper::TokenStreamWrapper; @@ -11,6 +12,20 @@ struct TraitProfile{ functions: Vec, } +impl TraitProfile{ + pub fn new(streams: Vec) -> Self { + let mut inner = vec!(); + + for stream in streams { + inner.push(TokenStreamWrapper::new(stream)); + } + + Self{ + functions: inner + } + } +} + #[derive(Debug, Clone)] enum DeduplicatedFunctionProfile { Single(String, TokenStreamWrapper), diff --git a/src/serde_wrapper.rs b/src/serde_wrapper.rs index df4b0a1..3075c97 100644 --- a/src/serde_wrapper.rs +++ b/src/serde_wrapper.rs @@ -1,370 +1,17 @@ +use std::{str::FromStr, fmt::{self, format}}; + use proc_macro2::TokenStream; -use serde::{Serialize, Deserialize, Serializer, Deserializer, ser::{SerializeStruct, SerializeTupleVariant, SerializeStructVariant}}; -use syn::{ImplItemMethod, Visibility, Signature, Pat, FnArg, Type, PatIdent, Ident, __private::{Span, ToTokens}, Receiver, ReturnType, Generics, GenericParam, QSelf, Path, Lifetime, TraitBound, TypeParamBound}; -use core::fmt::{Debug, Formatter}; -use std::error::Error; - - -#[derive(Clone)] -pub (crate) struct ImplItemMethodWrapper(ImplItemMethod); - -impl Debug for ImplItemMethodWrapper { - fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - todo!() - } -} - -impl Serialize for ImplItemMethodWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - let inner = &self.0; - let mut state = serializer.serialize_struct("Color", 4)?; - - // Attribute macros are not important in our case. - state.serialize_field("vis", &VisibilityWrapper(&inner.vis)); - // Defaultness are also not important here. - state.serialize_field("sig", &SignatureWrapper(&inner.sig)); - // We can throw away the block too. - - state.end() - } -} - -impl<'de> Deserialize<'de> for ImplItemMethodWrapper { - fn deserialize(_: D) -> Result>::Error> where D: Deserializer<'de> { - todo!() - } -} - -struct VisibilityWrapper<'a>(&'a Visibility); - -impl Serialize for VisibilityWrapper<'_> { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - match &self.0 { - Visibility::Public(_) => serializer.serialize_unit_variant("Visibility", 0, "Pub"), - Visibility::Crate(_) => serializer.serialize_unit_variant("Visibility", 1, "Crate"), - Visibility::Restricted(r) => serializer.serialize_newtype_variant( - "Visibility", - 2, - "Restricted", - &PathWrapper(*r.path), - ), - Visibility::Inherited => serializer.serialize_unit_variant("Visibility", 3, "Inherited"), - } - } -} - -struct SignatureWrapper<'a>(&'a Signature); - -impl Serialize for SignatureWrapper<'_> { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - let inner = &self.0; - let mut state = serializer.serialize_struct("Signature", 7)?; - - let mut prefixes = vec!(); - if inner.constness.is_some() { - prefixes.push("const") - } - if inner.asyncness.is_some() { - prefixes.push("async") - } - if inner.unsafety.is_some() { - prefixes.push("unsafe") - } - state.serialize_field("prefixes", &prefixes)?; - - match &inner.abi { - Some(a) => state.serialize_field( - "abi", - &Some( - format!( - "extern {}", - match &a.name { - Some(n) => n.value(), - None => String::from(""), - } - ).as_str() - ) - ), - None => state.serialize_field("abi", &None::), - }?; - - // No need to serialize the Fn token - state.serialize_field("ident", &inner.ident.to_string())?; - - state.serialize_field("generics", &GenericsWrapper(inner.generics))?; - - // Parentheses do not need to be serialized either - - serialize_iterator_struct( - &mut state, - Box::new(inner - .inputs - .clone() - .into_iter() - ), - "inputs", - | inp: &FnArg | -> Result<(PatWrapper, Option), Box> { - match inp { - FnArg::Receiver(r) => Ok(patopt_from_receiver(r.clone())), - FnArg::Typed(t) => Ok((PatWrapper(*t.pat.clone()), Some(TypeWrapper(*t.ty.clone())))), - } - } - ); - - state.serialize_field("variadic", match inner.variadic{ - Some(_) => "...", - None => "", - })?; - - match &inner.output{ - ReturnType::Default => {state.serialize_field("output", "()")?;}, - ReturnType::Type(_, t) => {(state.serialize_field("output", &TypeWrapper(*t.clone())))?;} - }; - - state.end() - } -} - -struct GenericsWrapper(Generics); - -impl Serialize for GenericsWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - todo!() - /*let inner = &self.0; - let mut state = serializer.serialize_struct("Signature", 7)?; - - serialize_iterator( - &mut state, - Box::new(inner - .params - .clone() - .into_iter() - ), - "params", - | inp: &GenericParam | -> Result<(PatWrapper, Option), Box> { - match inp { - GenericParam::Type(t) => t, - GenericParam::Lifetime() => {}, - GenericParam::Const() => {}, - } - } - ); - - state.end()*/ - } -} - -struct PatWrapper(Pat); - -impl Serialize for PatWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - let inner = &self.0; - - match inner { - Pat::Box(b) => serializer.serialize_newtype_variant("Pat", 0, "Box", &PatWrapper(*b.pat.clone())), - Pat::Ident(i) => { - let mut state = serializer.serialize_struct_variant("Pat", 1, "Ident", 4)?; - - if i.by_ref.is_some() { - state.serialize_field("by_ref", &Some(String::from("ref"))); - } else { - state.serialize_field("by_ref", &None::); - } - - if i.mutability.is_some() { - state.serialize_field("mutability", &Some(String::from("mut"))); - } else { - state.serialize_field("mutability", &None::); - } - - state.serialize_field("ident", &i.ident.to_string()); - - if let Some((_, s)) = &i.subpat { - state.serialize_field("subpat", &PatWrapper(*s.clone())); - } else { - state.serialize_field("subpat", &None::); - } - - state.end() - } - Pat::Path(p) => { - let mut state = serializer.serialize_struct_variant("Pat", 5, "Path", 2)?; - - if let Some(q) = &p.qself { - state.serialize_field("QSelf", &Some(QSelfWrapper(q.clone()))); - } else { - state.serialize_field("QSelf", &None::); - } - - state.serialize_field("Path", &PathWrapper(p.path.clone())); - - state.end() - } - Pat::Reference(r) => { - let mut state = serializer.serialize_struct_variant("Pat", 7, "Reference", 2)?; - - if r.mutability.is_some() { - state.serialize_field("mutability", &Some(String::from("mut"))); - } else { - state.serialize_field("mutability", &None::); - } - - state.serialize_field("pat", &PatWrapper(*r.pat.clone())); - - state.end() - } - Pat::Slice(s) => { - let mut state = serializer.serialize_struct_variant("Pat", 9, "Slice", 1)?; - - serialize_iterator_struct_variant( - &mut state, - Box::new( - s.elems - .clone() - .into_iter() - ), - "elems", - |p: &Pat| -> Result> {Ok(PatWrapper(p.clone()))} - ); - - state.end() - } - Pat::Tuple(t) => { - let mut state = serializer.serialize_struct_variant("Pat", 11, "Tuple", 1)?; - - serialize_iterator_struct_variant( - &mut state, - Box::new( - t.elems - .clone() - .into_iter() - ), - "elems", - |p: &Pat| -> Result> {Ok(PatWrapper(p.clone()))} - ); - - state.end() - } - Pat::Type(t) => { - let mut state = serializer.serialize_struct_variant("Pat", 13, "Type", 2)?; - - state.serialize_field("pat", &PatWrapper(*t.pat.clone())); - state.serialize_field("ty", &TypeWrapper(*t.ty.clone())); - - state.end() - } - Pat::Verbatim(t) => serializer.serialize_newtype_variant("Pat", 14, "Verbatim", &t.to_string()), - Pat::Wild(_) => serializer.serialize_unit_variant("Pat", 15, "Wild"), - // The rest can't be used in function arguments. - _ => unimplemented!() - } - } -} - -struct TypeWrapper( Type); - -impl Serialize for TypeWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - let inner = &self.0; - - match inner { - Type::Array(a) => { - let mut state = serializer.serialize_struct_variant("Pat", 0, "Type", 2)?; - - state.serialize_field("elem", &TypeWrapper(*a.elem.clone())); - // TODO: this is somewhat inelegant: - state.serialize_field("len", &a.len.to_token_stream().to_string()); - - state.end() - } - Type::Group(g) => serializer.serialize_newtype_variant("Type", 2, "Group", &TypeWrapper(*g.elem.clone())), - Type::ImplTrait(t) => { - let mut state = serializer.serialize_struct_variant("Pat", 11, "Tuple", 1)?; - - serialize_iterator_struct_variant( - &mut state, - Box::new( - t.bounds - .clone() - .into_iter() - ), - "elems", - |p: &TypeParamBound| -> Result> {Ok(PatWrapper(p.clone()))} - ); - - state.end() - } - // The rest can't be used in function arguments. - _ => unimplemented!() - } - } -} - -struct PathWrapper(Path); - -impl Serialize for PathWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - /*let mut path_str = String::from(""); - - for seg in &r.path.segments { - // There should be no arguments in the paths passed here. - path_str.push_str(seg.ident.to_string().as_str()); - path_str.push_str("::"); - } - - serializer.serialize_str( - format!("pub ({})", path_str).as_str() - )*/ - todo!() - } -} - -struct QSelfWrapper(QSelf); - -impl Serialize for QSelfWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - todo!() - } -} - -struct LifetimeWrapper(Lifetime); - -impl Serialize for LifetimeWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer - { - let inner = &self.0; - serializer.serialize_newtype_struct("Lifetime", &inner.ident.to_string()) - } -} +use serde::{Serialize, Serializer, Deserialize, Deserializer, de::{Visitor, self}}; +#[derive(Debug, Clone)] pub struct TokenStreamWrapper(TokenStream); +impl TokenStreamWrapper { + pub fn new(stream: TokenStream) -> Self { + Self(stream) + } +} + impl Serialize for TokenStreamWrapper { fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where @@ -375,75 +22,50 @@ impl Serialize for TokenStreamWrapper { } } - -struct TraitBoundWrapper(TraitBound); - -impl Serialize for TraitBoundWrapper { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> - where - S: Serializer +impl<'de> Deserialize<'de> for TokenStreamWrapper { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de> { - let inner = &self.0; - todo!(); - } -} + let tok_str = deserializer.deserialize_string(TokenStreamVisitor)?; -fn patopt_from_receiver(r: Receiver) -> (PatWrapper, Option) { - let mut ident = String::from(""); - - if let Some((_, lt)) = &r.reference { - ident.push('&'); - - match lt { - Some(l) => ident.push_str( - l.ident - .to_string() - .as_str() - ), - None => {}, - } - - ident.push(' '); + match TokenStream::from_str(&tok_str.as_str()) { + Ok(t) => Ok(Self(t)), + Err(e) => Err(de::Error::custom( + format!("string does not represent a valid TokenStream: {}", e) + )) } + } +} + +struct TokenStreamVisitor; + +impl<'de> Visitor<'de> for TokenStreamVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("A string representing a TokenStream") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(value.to_string()) + } + + fn visit_borrowed_str(self, value: &'de str) -> Result + where + E: de::Error, + { + Ok(value.to_string()) + } + + fn visit_string(self, value: String) -> Result + where + E: de::Error, + { + Ok(value) + } - (PatWrapper(Pat::Ident(PatIdent{ - attrs: vec!(), - by_ref: None, - mutability: r.mutability, - ident: Ident::new(&ident, Span::call_site()), - subpat: None, - })), None) } - -fn serialize_iterator_struct (serializer: &mut S, iterator: Box>, field_name: &'static str, item_fun: F) - -> Result<(), Box> -where - F: Fn(&T) -> Result>, - S: SerializeStruct , - U: Serialize, -{ - let mut p_vec = vec!(); - for item in iterator { - p_vec.push(item_fun(&item)?); - } - serializer.serialize_field(field_name, &p_vec); - Ok(()) -} - -// Thanks to weird traits in Serde we need to duplicate code hereā€¦ -// TODO: Maybe to this as a macro -fn serialize_iterator_struct_variant (serializer: &mut S, iterator: Box>, field_name: &'static str, item_fun: F) - -> Result<(), Box> -where - F: Fn(&T) -> Result>, - S: SerializeStructVariant , - U: Serialize, -{ - let mut p_vec = vec!(); - for item in iterator { - p_vec.push(item_fun(&item)?); - } - serializer.serialize_field(field_name, &p_vec); - Ok(()) -} -