Bulk of the code is in place, no debugging done yet.
This commit is contained in:
parent
cb3bbdbb78
commit
616ab17008
4 changed files with 552 additions and 91 deletions
4
sing_macros/src/keyword.rs
Normal file
4
sing_macros/src/keyword.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
use syn::custom_keyword;
|
||||
|
||||
custom_keyword!(ioe);
|
||||
custom_keyword!(msg);
|
|
@ -5,14 +5,454 @@ use std::{
|
|||
error::Error,
|
||||
io::{Write, Read},
|
||||
};
|
||||
use sing_util::TraitProfile;
|
||||
use syn::{parse_macro_input, AttributeArgs, ItemImpl, ImplItem};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{TokenStream as TokenStream2, Span};
|
||||
use sing_util::{DeduplicatedFunctionProfile, TraitProfile};
|
||||
use syn::{
|
||||
parse_macro_input,
|
||||
AttributeArgs,
|
||||
Ident,
|
||||
ItemImpl,
|
||||
ImplItem,
|
||||
NestedMeta,
|
||||
parse::{Parse, ParseStream},
|
||||
Token,
|
||||
parenthesized,
|
||||
Arm,
|
||||
parse2,
|
||||
LitStr,
|
||||
Signature,
|
||||
FnArg,
|
||||
Path,
|
||||
Stmt,
|
||||
};
|
||||
use quote::{quote, spanned::Spanned, ToTokens};
|
||||
|
||||
|
||||
extern crate sing_util;
|
||||
extern crate proc_macro;
|
||||
|
||||
mod keyword;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn sing_add_trait(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as ItemImpl);
|
||||
let annotated_item = parse_macro_input!(annotated_item as AttributeArgs);
|
||||
|
||||
let output = add_trait_inner(input, annotated_item);
|
||||
|
||||
TokenStream::from(output)
|
||||
}
|
||||
|
||||
fn add_trait_inner(input: ItemImpl, annotated_item: Vec<NestedMeta>) -> TokenStream2 {
|
||||
let trait_name;
|
||||
match &input.trait_ {
|
||||
Some((_b, p, _f)) => {
|
||||
trait_name = p.into_token_stream().to_string();
|
||||
},
|
||||
None => {
|
||||
compile_error_panic(input.__span(), "This attribute can only be used on trait impl blocks.");
|
||||
trait_name = String::from("");
|
||||
},
|
||||
};
|
||||
|
||||
let mut trait_functions = HashMap::new();
|
||||
for fun in &input.items {
|
||||
match fun {
|
||||
ImplItem::Method(m) => {trait_functions.insert(
|
||||
m.sig.ident.to_string(),
|
||||
m.sig.to_token_stream()
|
||||
);},
|
||||
_ => {
|
||||
compile_error_panic(input.__span(), "Found unexpected item that is not a method.");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// TODO: add gobble
|
||||
quote! {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn sing_loop(input: TokenStream) -> TokenStream {
|
||||
let span = TokenStream2::from(input.clone()).__span();
|
||||
let input = parse_macro_input!(input as LoopParams);
|
||||
|
||||
let output = match loop_inner(input, span) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
compile_error_panic(span, &e.to_string());
|
||||
TokenStream2::new()
|
||||
},
|
||||
};
|
||||
|
||||
TokenStream::from(output)
|
||||
}
|
||||
|
||||
fn loop_inner(input: LoopParams, span: Span) -> Result<TokenStream2, Box<dyn Error>> {
|
||||
let LoopParams {
|
||||
trait_obj,
|
||||
ser_fun,
|
||||
de_fun,
|
||||
reader,
|
||||
writer,
|
||||
err_writer,
|
||||
message_type
|
||||
} = input;
|
||||
|
||||
let mut ioe_initializers = vec!();
|
||||
|
||||
let reader = match reader {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
ioe_initializers.push(parse2::<Stmt>(quote!{
|
||||
let reader = std::io::stdin().lock();
|
||||
})?);
|
||||
|
||||
parse2::<Ident>(quote!{
|
||||
reader
|
||||
})?},
|
||||
};
|
||||
|
||||
let writer = match writer {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
ioe_initializers.push(parse2::<Stmt>(quote!{
|
||||
let writer = std::io::stdout().lock();
|
||||
})?);
|
||||
|
||||
parse2::<Ident>(quote!{
|
||||
writer
|
||||
})?},
|
||||
};
|
||||
|
||||
let err_writer = match err_writer {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
ioe_initializers.push(parse2::<Stmt>(quote!{
|
||||
let err_writer = std::io::stdin().lock();
|
||||
})?);
|
||||
|
||||
parse2::<Ident>(quote!{
|
||||
err_writer
|
||||
})?},
|
||||
};
|
||||
|
||||
let ioe_initializers = ioe_initializers;
|
||||
|
||||
let message_type = match message_type {
|
||||
Some(r) => r,
|
||||
None => parse2::<Path>(quote!{
|
||||
todo!();
|
||||
})?,
|
||||
};
|
||||
|
||||
let traits = load_trait_state().unwrap();
|
||||
|
||||
let mut funs = HashMap::new();
|
||||
for (t_name, t_funs) in &traits {
|
||||
for (f_name, fun) in t_funs.get_funs()? {
|
||||
if funs.contains_key(&f_name) {
|
||||
funs.insert(f_name.clone(), match &funs[&f_name] {
|
||||
DeduplicatedFunctionProfile::Single(t, _) => DeduplicatedFunctionProfile::Multiple(vec!(t_name.clone(), t.clone())),
|
||||
DeduplicatedFunctionProfile::Multiple(v) => {
|
||||
let mut v = v.clone();
|
||||
v.push(t_name.clone());
|
||||
DeduplicatedFunctionProfile::Multiple(v)
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut fun_arms = vec!();
|
||||
for (f_name, f_profile) in funs {
|
||||
let fn_lit = LitStr::new(&f_name, span);
|
||||
let fn_ident = Ident::new(&f_name, span);
|
||||
let arm;
|
||||
|
||||
match f_profile {
|
||||
DeduplicatedFunctionProfile::Multiple(v) => {
|
||||
arm = quote!{
|
||||
#fn_lit => {
|
||||
let traits = vec!( #( #v ),* );
|
||||
let message = format!("The function {} is found in the following traits: {}.
|
||||
Plese specify which traits function you want to use.",
|
||||
#f_name,
|
||||
traits,
|
||||
);
|
||||
<#err_writer as Write>.write_all(message.as_bytes())?;
|
||||
},
|
||||
};
|
||||
},
|
||||
DeduplicatedFunctionProfile::Single(tr, s) => {
|
||||
let tr = Ident::new(&tr, span);
|
||||
arm = get_fun_arm(
|
||||
fn_lit,
|
||||
fn_ident,
|
||||
ser_fun.clone(),
|
||||
de_fun.clone(),
|
||||
writer.clone(),
|
||||
trait_obj.clone(),
|
||||
tr,
|
||||
s.get_inner()?
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
let arm = parse2::<Arm>(arm)?;
|
||||
fun_arms.push(arm);
|
||||
}
|
||||
|
||||
fun_arms.push(
|
||||
parse2::<Arm>(quote! {
|
||||
"" => {
|
||||
let message = String::from("No function name was given! Aborting.");
|
||||
<#err_writer as Write>.write_all(message.as_bytes())?;
|
||||
},
|
||||
})?
|
||||
);
|
||||
|
||||
fun_arms.push(
|
||||
parse2::<Arm>(quote! {
|
||||
s => {
|
||||
let message = format!("The function {} is not known! Aborting.", s);
|
||||
<#err_writer as Write>.write_all(message.as_bytes())?;
|
||||
},
|
||||
})?
|
||||
);
|
||||
|
||||
let mut trait_arms = vec!();
|
||||
|
||||
for (t_name, t_profile) in traits.clone() {
|
||||
let t_lit = LitStr::new(&t_name, span);
|
||||
let t_ident = Ident::new(&t_name, span);
|
||||
|
||||
let mut f_arms = vec!();
|
||||
for (f_name, f_profile) in t_profile.get_funs()? {
|
||||
let fn_lit = LitStr::new(&f_name, span);
|
||||
let fn_ident = Ident::new(&f_name, span);
|
||||
|
||||
let f_arm = get_fun_arm(
|
||||
fn_lit,
|
||||
fn_ident,
|
||||
ser_fun.clone(),
|
||||
de_fun.clone(),
|
||||
writer.clone(),
|
||||
trait_obj.clone(),
|
||||
t_ident.clone(),
|
||||
f_profile
|
||||
)?;
|
||||
|
||||
f_arms.push(parse2::<Arm>(f_arm)?);
|
||||
}
|
||||
|
||||
f_arms.push(
|
||||
parse2::<Arm>(quote! {
|
||||
"" => {
|
||||
let message = String::from("No function name was given! Aborting.");
|
||||
<#err_writer as Write>.write_all(message.as_bytes())?;
|
||||
},
|
||||
})?
|
||||
);
|
||||
|
||||
f_arms.push(
|
||||
parse2::<Arm>(quote! {
|
||||
s => {
|
||||
let message = format!("The function {} was not found in the trait {}! Aborting.", s, #t_lit );
|
||||
<#err_writer as Write>.write_all(message.as_bytes())?;
|
||||
}
|
||||
})?
|
||||
);
|
||||
|
||||
let t_arm = quote! {
|
||||
#t_lit => {
|
||||
match <message as TraitCallMessage>.get_fun_name().as_str() {
|
||||
#( #f_arms )*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
trait_arms.push(parse2::<Arm>(t_arm)?);
|
||||
}
|
||||
|
||||
Ok(quote!{
|
||||
#( #ioe_initializers )*
|
||||
'main: loop {
|
||||
let mut buf = String::new();
|
||||
<#reader as BufRead>.read_line(buf);
|
||||
|
||||
match #de_fun ::< #message_type >(buf) {
|
||||
Ok(message) => {
|
||||
let mut message = message;
|
||||
|
||||
match <message as TraitCallMessage>.get_trait_name().as_str() {
|
||||
#( #trait_arms )*
|
||||
}
|
||||
|
||||
match #ser_fun(message) {
|
||||
Ok(s) => <#writer as Write>.write_all(s),
|
||||
Err(e) => <#err_writer as Write>.write_all("Could not encode call result: {}", e),
|
||||
}
|
||||
},
|
||||
Err(e) => <#err_writer as Write>.write_all("Could not decode {} as trait message: {}", buf, e),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
struct LoopParams {
|
||||
trait_obj: Ident,
|
||||
ser_fun: Path,
|
||||
de_fun: Path,
|
||||
reader: Option<Ident>,
|
||||
writer: Option<Ident>,
|
||||
err_writer: Option<Ident>,
|
||||
message_type: Option<Path>,
|
||||
}
|
||||
|
||||
impl Parse for LoopParams {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let trait_obj = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
|
||||
let ser_fun = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
|
||||
let de_fun = input.parse()?;
|
||||
let lookahead = input.lookahead1();
|
||||
|
||||
let mut reader = None;
|
||||
let mut writer = None;
|
||||
let mut err_writer = None;
|
||||
let mut message_type = None;
|
||||
|
||||
'parse: loop {
|
||||
input.parse::<Token![,]>()?;
|
||||
if input.is_empty() {break 'parse}
|
||||
if lookahead.peek(keyword::msg) {
|
||||
input.parse::<keyword::msg>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
let ty = input.parse()?;
|
||||
message_type = Some(ty);
|
||||
|
||||
} else if lookahead.peek(keyword::ioe) {
|
||||
input.parse::<keyword::ioe>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let lh_inner = content.lookahead1();
|
||||
let ioe_err_generic = "The ioe keyword expects three variables in the following order: (Input, Output, Error),";
|
||||
|
||||
if lh_inner.peek(Ident) {
|
||||
let r = content.parse()?;
|
||||
reader = Some(r);
|
||||
} else {
|
||||
compile_error_panic(
|
||||
content.span(),
|
||||
format!("{}, but the Input variable was not supplied.", ioe_err_generic).as_str()
|
||||
);
|
||||
}
|
||||
|
||||
if lh_inner.peek(Ident) {
|
||||
let w = content.parse()?;
|
||||
writer = Some(w);
|
||||
} else {
|
||||
compile_error_panic(
|
||||
content.span(),
|
||||
format!("{}, but the Output variable was not supplied.", ioe_err_generic).as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
if lh_inner.peek(Ident) {
|
||||
let e = content.parse()?;
|
||||
err_writer = Some(e);
|
||||
} else {
|
||||
compile_error_panic(
|
||||
content.span(),
|
||||
format!("{}, but the Error variable was not supplied.", ioe_err_generic).as_str(),
|
||||
);
|
||||
}
|
||||
}
|
||||
if input.is_empty() {break 'parse}
|
||||
}
|
||||
Ok(Self {
|
||||
trait_obj,
|
||||
ser_fun,
|
||||
de_fun,
|
||||
reader,
|
||||
writer,
|
||||
err_writer,
|
||||
message_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fun_arm(
|
||||
fn_lit: LitStr,
|
||||
fn_ident: Ident,
|
||||
ser_fun: Path,
|
||||
de_fun: Path,
|
||||
writer: Ident,
|
||||
trait_obj: Ident,
|
||||
tr: Ident,
|
||||
s: TokenStream2,
|
||||
) -> Result<TokenStream2, Box<dyn Error>> {
|
||||
let sig = parse2::<Signature>(s)?;
|
||||
let mut args = vec!();
|
||||
let mut parse_lets = vec!();
|
||||
|
||||
for a in sig.inputs {
|
||||
match a {
|
||||
// This is just a "self" value which does not need to be in the call
|
||||
FnArg::Receiver(_) => (),
|
||||
FnArg::Typed(t) => {
|
||||
let pat = *t.pat;
|
||||
let ty = t.ty;
|
||||
|
||||
args.push(pat.clone());
|
||||
|
||||
parse_lets.push(parse2::<Stmt>(quote!{
|
||||
let #pat : #ty = #de_fun ( #pat );
|
||||
})?);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(quote!{
|
||||
#fn_lit => {
|
||||
let params = <message as TraitCallMessage>.get_params();
|
||||
|
||||
let ( #( #args ),* ) = params;
|
||||
#( #parse_lets )*
|
||||
|
||||
let result = <#trait_obj as #tr>. #fn_ident ( #( #args ),* );
|
||||
<message as TraitCallMessage>.new_params(
|
||||
vec!(<#ser_fun as Serializer>.serialize(result))
|
||||
);
|
||||
|
||||
<#writer as Write>.write_all(message.as_bytes())?;
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn get_run_id () -> Result<usize, Box<dyn Error>> {
|
||||
// Get a random uid for this compiler run and save it as an environment variable.
|
||||
// Load it if it's already there.
|
||||
|
@ -30,6 +470,7 @@ fn get_run_id () -> Result<usize, Box<dyn Error>> {
|
|||
fn get_state_file_path() -> Result<String, Box<dyn Error>> {
|
||||
let compilation_run_identifier = get_run_id()?;
|
||||
Ok(format!("/tmp/sing-trait-store-{}", compilation_run_identifier))
|
||||
|
||||
}
|
||||
|
||||
fn save_trait_state(map: HashMap<String, sing_util::TraitProfile>) -> Result<usize, Box<dyn Error>> {
|
||||
|
@ -49,62 +490,82 @@ fn load_trait_state() -> Result<HashMap<String, sing_util::TraitProfile>, Box<dy
|
|||
Ok(ron::from_str(&state_string)?)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
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_ {
|
||||
Some((_b, p, _f)) => {
|
||||
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 {
|
||||
match fun {
|
||||
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();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
let output = quote! {
|
||||
// ...
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from(output)
|
||||
fn compile_error_panic(span: Span, msg: &str) {
|
||||
syn::Error::new(span, msg)
|
||||
.to_compile_error();
|
||||
panic!("{}", msg)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{str::FromStr, collections::HashMap};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use sing_util::TraitProfile;
|
||||
|
||||
use crate::{save_trait_state, load_trait_state, add_trait_inner};
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
fn save_tokenstream() {
|
||||
let mut orig = HashMap::new();
|
||||
|
||||
orig.insert(String::from("test"), TokenStream::from_str("
|
||||
fn test(a: Astruct, b: [Box<dyn Error>, String]) -> String {}
|
||||
").unwrap());
|
||||
orig.insert(String::from("other_test"), TokenStream::from_str("
|
||||
fn other_test(a: Trait1 + Trait2) -> Result<String, Box<dyn Error>> {}
|
||||
").unwrap(),
|
||||
);
|
||||
|
||||
let orig_name = String::from("Test");
|
||||
let mut orig_state = HashMap::new();
|
||||
orig_state.insert(orig_name.clone(), TraitProfile::new(orig));
|
||||
|
||||
save_trait_state(orig_state.clone()).unwrap();
|
||||
|
||||
let new_state = load_trait_state().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
orig_state[&orig_name].get_funs().unwrap()["test"].to_string(),
|
||||
new_state[&orig_name].get_funs().unwrap()["test"].to_string()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trait_call() {
|
||||
let call = TokenStream::from_str("
|
||||
impl FruitTree for BananaTree {
|
||||
fn shake(&self) -> Box<dyn Fruit> {
|
||||
Box::new(self.bananas.pop())
|
||||
}
|
||||
}
|
||||
").unwrap();
|
||||
let call = syn::parse2(call).unwrap();
|
||||
|
||||
add_trait_inner(call, vec!());
|
||||
|
||||
let new_state = load_trait_state().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
TokenStream::from_str("
|
||||
fn shake(&self) -> Box<dyn Fruit>
|
||||
").unwrap().to_string(),
|
||||
new_state["FruitTree"].get_funs().unwrap()["shake"].to_string()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn non_trait_call() {
|
||||
let call = TokenStream::from_str("
|
||||
impl Banana {
|
||||
pub fn peel(&self) -> Food {
|
||||
self.inner.clone()
|
||||
}
|
||||
}
|
||||
").unwrap();
|
||||
let call = syn::parse2(call).unwrap();
|
||||
|
||||
add_trait_inner(call, vec!());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use core::fmt::Debug;
|
||||
use std::{error::Error, collections::HashMap};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
@ -8,55 +9,46 @@ mod serde_wrapper;
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TraitProfile{
|
||||
//functions: HashMap<String, FunctionProfile>,
|
||||
functions: Vec<TokenStreamWrapper>,
|
||||
functions: HashMap<String, TokenStreamWrapper>,
|
||||
}
|
||||
|
||||
impl TraitProfile{
|
||||
pub fn new(streams: Vec<TokenStream>) -> Self {
|
||||
let mut inner = vec!();
|
||||
pub fn new(funs: HashMap<String, TokenStream>) -> Self {
|
||||
let mut inner = HashMap::new();
|
||||
|
||||
for stream in streams {
|
||||
inner.push(TokenStreamWrapper::new(stream));
|
||||
for (name, stream) in funs {
|
||||
inner.insert(name, TokenStreamWrapper::new(stream));
|
||||
}
|
||||
|
||||
Self{
|
||||
functions: inner
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_funs(&self) -> Result<HashMap<String, TokenStream>, Box<dyn Error>> {
|
||||
let wrappers = self.functions.clone();
|
||||
let mut funs = HashMap::new();
|
||||
|
||||
for (name, wrapper) in wrappers {
|
||||
funs.insert(name, wrapper.get_inner()?);
|
||||
}
|
||||
|
||||
Ok(funs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum DeduplicatedFunctionProfile {
|
||||
pub enum DeduplicatedFunctionProfile {
|
||||
Single(String, TokenStreamWrapper),
|
||||
Multiple(Vec<String>, TokenStreamWrapper),
|
||||
Multiple(Vec<String>),
|
||||
}
|
||||
|
||||
/*impl<T> Evaluator<T> {
|
||||
fn deduplicate_functions(&self) -> Self<T> {
|
||||
let mut self = self.clone();
|
||||
let mut functions: HashMap<String, DeduplicatedFunctionProfile>;
|
||||
|
||||
for (t_name, t_profile) in self.traits {
|
||||
for (fun_name, fun_profile) in t_profile.functions {
|
||||
if !functions.contains_key(fun_name) {
|
||||
self.functions.insert(fun_name, DeduplicatedFunctionProfile::Single(t_name, fun_profile))
|
||||
} else {
|
||||
let other = self.functions.remove(fun_name).unwrap();
|
||||
|
||||
let traits: Vec<String>;
|
||||
match other {
|
||||
DeduplicatedFunctionProfile::Single(t, _) => traits = vec!(t),
|
||||
DeduplicatedFunctionProfile::Multiple(ts, _) => traits = ts,
|
||||
}
|
||||
|
||||
self.functions.insert(fun_name, DeduplicatedFunctionProfile::Multiple(traits, fun_profile))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub trait TraitCallMessage {
|
||||
fn get_fun_name() -> String;
|
||||
fn get_trait_name() -> String;
|
||||
fn get_params() -> Vec<String>;
|
||||
fn new_params(p: Vec<String>);
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
use std::{str::FromStr, fmt::{self, format}};
|
||||
use std::{str::FromStr, fmt::{self, format}, error::Error};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer, de::{Visitor, self}};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TokenStreamWrapper(TokenStream);
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TokenStreamWrapper(String);
|
||||
|
||||
impl TokenStreamWrapper {
|
||||
pub fn new(stream: TokenStream) -> Self {
|
||||
Self(stream)
|
||||
Self(stream.to_string())
|
||||
}
|
||||
pub fn get_inner(&self) -> Result<TokenStream, Box<dyn Error>> {
|
||||
Ok(TokenStream::from_str(&self.0.clone())?)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl Serialize for TokenStreamWrapper {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||
where
|
||||
|
@ -29,7 +32,7 @@ impl<'de> Deserialize<'de> for TokenStreamWrapper {
|
|||
{
|
||||
let tok_str = deserializer.deserialize_string(TokenStreamVisitor)?;
|
||||
|
||||
match TokenStream::from_str(&tok_str.as_str()) {
|
||||
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)
|
||||
|
@ -69,3 +72,4 @@ impl<'de> Visitor<'de> for TokenStreamVisitor {
|
|||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue