chore: fmt

This commit is contained in:
Felipe g 2022-10-13 08:25:29 -03:00
parent e2a4df9577
commit 912b9fccde
9 changed files with 306 additions and 155 deletions

View File

@ -1,37 +1,94 @@
use proc_macro::{self, TokenStream};
use proc_macro2::Span;
use proc_macro2::TokenStream as TknStream;
use quote::quote;
use syn::parse_quote;
use syn::spanned::Spanned;
use syn::Error;
use syn::Ident;
use syn::ItemTrait;
use syn::{parse_macro_input, PatIdent, Receiver};
use syn::{Error};
#[derive(Debug)]
struct Method {
name: syn::Ident,
args: Vec<syn::FnArg>,
memoizable: bool,
meta_info: bool,
ret: syn::ReturnType,
meta_ret: syn::ReturnType,
}
#[derive(Debug)]
struct TraitPat {
methods: Vec<(syn::Ident, Vec<syn::FnArg>, syn::ReturnType)>,
methods: Vec<Method>,
}
fn methods_to_pat(trait_item: &ItemTrait) -> syn::Result<TraitPat> {
fn method_args(method: &syn::TraitItemMethod) -> syn::Result<Vec<syn::FnArg>> {
if method.sig.inputs.is_empty() {
return Err(Error::new(method.sig.ident.span(), "expected `&self`"));
}
match &method.sig.inputs[0] {
syn::FnArg::Receiver(Receiver {
mutability: None,
self_token: _,
reference: Some(_),
..
}) => {}
id => return Err(Error::new(id.span(), "expected `&self`")),
}
let mut iter = method.sig.inputs.iter();
iter.next();
Ok(iter.cloned().collect())
}
fn methods_to_pat(trait_item: &mut ItemTrait) -> syn::Result<TraitPat> {
let mut pat = TraitPat { methods: Vec::new() };
for item in &trait_item.items {
for item in &mut trait_item.items {
match item {
syn::TraitItem::Method(method) => {
if method.sig.inputs.is_empty() {
return Err(Error::new(method.sig.ident.span(), "expected `&self`"));
}
match method.sig.inputs[0] {
syn::FnArg::Receiver(Receiver {
mutability: None,
self_token: _,
reference: Some(_),
..
}) => {}
_ => return Err(Error::new(method.sig.ident.span(), "expected `&self`")),
}
let mut method_args = Vec::new();
for i in 1..method.sig.inputs.len() {
method_args.push(method.sig.inputs[i].clone())
let mut memoizable = false;
let mut meta_info = false;
for attr in &method.attrs {
let span = attr.path.span();
match attr.path.get_ident() {
Some(path) => {
if path == &Ident::new("memoize", Span::call_site()) {
memoizable = true;
} else if path == &Ident::new("memoize_info", Span::call_site()) {
meta_info = true;
memoizable = true;
} else {
return Err(Error::new(span, "unrecognized query attribute"));
}
}
_ => return Err(Error::new(span, "invalid query attribute")),
}
}
method.attrs = Vec::new();
let args = method_args(method)?;
let name = method.sig.ident.clone();
pat.methods.push((name, method_args, method.sig.output.clone()))
let old = method.sig.output.clone();
if meta_info {
match &mut method.sig.output {
syn::ReturnType::Default => method.sig.output = parse_quote!(quote! { -> ((), bool) }),
syn::ReturnType::Type(_, ty) => *ty = Box::new(parse_quote!((#ty, bool))),
}
}
pat.methods.push(Method {
name,
args,
memoizable,
ret: old,
meta_info,
meta_ret: method.sig.output.clone(),
})
}
_ => return Err(Error::new(trait_item.ident.span(), "can only process methods")),
}
@ -39,119 +96,103 @@ fn methods_to_pat(trait_item: &ItemTrait) -> syn::Result<TraitPat> {
Ok(pat)
}
#[proc_macro_attribute]
pub fn make_provider(_attr: TokenStream, input: TokenStream) -> TokenStream {
let mut ast: ItemTrait = parse_macro_input!(input);
fn append_ident(ident: &syn::Ident, str: &str) -> syn::Ident {
syn::Ident::new(&format!("{}{}", ident, str), ident.span())
}
let cache = syn::Ident::new(&format!("{}Cache", ast.ident), ast.ident.span());
let provider = syn::Ident::new(&format!("{}Provider", ast.ident), ast.ident.span());
let store = syn::Ident::new(&format!("{}Database", ast.ident), ast.ident.span());
let ident = ast.ident.clone();
let pat = match methods_to_pat(&ast) {
Ok(res) => res,
Err(err) => return err.to_compile_error().into(),
};
fn mk_ident(ident: &str) -> syn::Ident {
syn::Ident::new(ident, Span::call_site())
}
fn make_cache_struct(pat: &TraitPat, ident_cache: &syn::Ident) -> syn::Result<TknStream> {
let mut defs = Vec::new();
for (ident, _, ret) in &pat.methods {
match ret {
syn::ReturnType::Type(_, ty) => {
defs.push(quote! {
pub #ident: std::sync::Arc<dashmap::DashMap<u64, #ty>>,
});
}
_ => (),
}
}
let mut fields = Vec::new();
for (ident, args, ret) in &pat.methods {
fields.push(quote! {
pub #ident: fn(&#store, #(#args),*) #ret,
});
}
let mut impls = Vec::new();
for i in 0..pat.methods.len() {
let mut new_args: Vec<PatIdent> = Vec::new();
let (ident, args, ret) = &pat.methods[i];
for arg in args {
match arg {
syn::FnArg::Typed(syn::PatType { pat, .. }) => match *pat.clone() {
syn::Pat::Ident(id) => new_args.push(id),
_ => return quote! {compile_error!("pattern type not supported yet"); }.into(),
},
_ => return quote! {compile_error!("cannot use &self in the middle of parameters yet"); }.into(),
for Method { ret, memoizable, name, .. } in &pat.methods {
if let syn::ReturnType::Type(_, ty) = ret {
if *memoizable {
defs.push(quote! {
pub #name: std::sync::Arc<dashmap::DashMap<u64, #ty>>,
});
}
}
impls.push(quote! {
fn #ident(&self, #(#args),*) #ret {
self.run_query((#(#new_args)* as u64), self.cache.#ident.clone(), #i as u8, |db| {
(db.provider.#ident)(db, #(#new_args),*)
})
}
});
}
for entry in &mut ast.items {
match entry {
syn::TraitItem::Method(met) => {
met.attrs = Vec::new();
}
_ => (),
}
}
let mut match_fields = Vec::new();
for i in 0..pat.methods.len() {
let (ident, _, _) = &pat.methods[i];
let u = i as u8;
match_fields.push(quote! {
#u => {self.cache.#ident.remove(&hash);},
});
}
quote! {
#ast
let struct_quoted = quote! {
#[derive(Default)]
pub struct #cache {
pub struct #ident_cache {
#(#defs)*
}
};
pub struct #provider {
Ok(struct_quoted)
}
fn make_provider_struct(pat: &TraitPat, ident_provider: &syn::Ident, ident_store: &syn::Ident) -> syn::Result<TknStream> {
let mut fields = Vec::new();
for Method { name, args, ret, .. } in &pat.methods {
fields.push(quote! {
pub #name: fn(&#ident_store, #(#args),*) #ret,
});
}
let quoted = quote! {
pub struct #ident_provider {
#(#fields)*
}
};
Ok(quoted)
}
fn make_storage_struct(pat: &TraitPat, ident_provider: &syn::Ident, ident_cache: &syn::Ident, ident_storage: &syn::Ident, conf: Option<syn::Path>) -> syn::Result<TknStream> {
let mut match_fields = Vec::new();
for i in 0..pat.methods.iter().filter(|e| e.memoizable).count() {
let Method { name, .. } = &pat.methods[i];
let u = i as u8;
match_fields.push(quote! {
#u => {self.cache.#name.remove(&hash);},
});
}
let config = match &conf {
Some(res) => quote! { config: #res },
None => quote! {},
};
let conf_def = match conf {
Some(_) => quote! { config },
None => quote! {},
};
let res = quote! {
#[derive(Clone)]
pub struct #store {
provider: std::sync::Arc<#provider>,
cache: std::sync::Arc<#cache>,
dep_graph: crate::graph::DepGraph,
pub struct #ident_storage {
provider: std::sync::Arc<#ident_provider>,
cache: std::sync::Arc<#ident_cache>,
dep_graph: crate::core::graph::DepGraph,
input_hash: u64,
parent: Option<u64>
parent: Option<u64>,
#config
}
impl #store {
pub fn new(provider: std::sync::Arc<#provider>) -> #store {
#store {
impl #ident_storage {
pub fn new(provider: std::sync::Arc<#ident_provider>, #config) -> #ident_storage {
#ident_storage {
provider,
cache: Default::default(),
dep_graph: Default::default(),
input_hash: Default::default(),
parent: None,
#conf_def
}
}
}
impl crate::store::Session for #store {
use crate::core::store::Session;
impl crate::core::store::Session for #ident_storage {
fn delete_from_cache(&self, hash: u64, db_idx: u8) {
match db_idx {
#(#match_fields)*
@ -167,14 +208,128 @@ pub fn make_provider(_attr: TokenStream, input: TokenStream) -> TokenStream {
self.parent = Some(hash);
}
fn dependency_graph(&self) -> crate::graph::DepGraph {
fn dependency_graph(&self) -> crate::core::graph::DepGraph {
self.dep_graph.clone()
}
}
};
impl #ident for #store {
#(#impls)*
Ok(res)
}
fn make_impl(pat: &TraitPat, ident: &syn::Ident, ident_storage: &syn::Ident) -> syn::Result<TknStream> {
let mut impls = Vec::new();
let mut counter = 0;
for i in 0..pat.methods.len() {
let mut new_args: Vec<PatIdent> = Vec::new();
let Method {
name,
args,
memoizable,
ret,
meta_info,
meta_ret,
..
} = &pat.methods[i];
for arg in args {
match arg {
syn::FnArg::Typed(syn::PatType { pat, .. }) => match *pat.clone() {
syn::Pat::Ident(id) => new_args.push(id),
pat => return Err(Error::new(pat.span(), "pattern matching not supported yet")),
},
pat => return Err(Error::new(pat.span(), "cannot use self in this position")),
}
}
let run_memoized = mk_ident("run_query_memoized");
let run_flat = mk_ident("run_query_flat");
let meta = if *meta_info {
quote! {}
} else {
quote! { .0 }
};
if *memoizable {
impls.push(quote! {
fn #name(&self, #(#args),*) #meta_ret {
self.#run_memoized(fxhash::hash64(&(#i+1, #(&#new_args),*)), self.cache.#name.clone(), #counter as u8, |db| {
(db.provider.#name)(db, #(#new_args),*)
})#meta
}
});
counter += 1;
} else {
impls.push(quote! {
fn #name(&self, #(#args),*) #ret {
self.#run_flat(fxhash::hash64(&(#i+1, #(&#new_args),*)), |db| {
(db.provider.#name)(db, #(#new_args),*)
})
}
});
}
}
.into()
Ok(quote! {
impl #ident for #ident_storage {
#(#impls)*
}
})
}
fn make_provider_strutures(ast: &mut ItemTrait, ident: &syn::Ident, attr_vec: Vec<syn::NestedMeta>) -> syn::Result<TknStream> {
let cache = append_ident(ident, "Cache");
let provider = append_ident(ident, "Provider");
let storage = append_ident(ident, "Database");
let trait_pat = methods_to_pat(ast)?;
let attr = parse_config(attr_vec)?;
let cache_struct = make_cache_struct(&trait_pat, &cache)?;
let provider_struct = make_provider_struct(&trait_pat, &provider, &storage)?;
let storage_struct = make_storage_struct(&trait_pat, &provider, &cache, &storage, attr)?;
let impl_for_struct = make_impl(&trait_pat, ident, &storage)?;
let res = quote! {
#ast
#cache_struct
#provider_struct
#storage_struct
#impl_for_struct
};
Ok(res)
}
fn parse_config(ast: Vec<syn::NestedMeta>) -> syn::Result<Option<syn::Path>> {
if ast.len() == 1 {
let ast = &ast[0];
match ast {
syn::NestedMeta::Meta(meta) => match meta {
syn::Meta::Path(path) => Ok(Some(path.clone())),
_ => Err(Error::new(ast.span(), "cannot use type")),
},
syn::NestedMeta::Lit(_) => Err(Error::new(ast.span(), "cannot parse type")),
}
} else if ast.is_empty() {
Ok(None)
} else {
Err(Error::new(Span::call_site(), "too many arguments for the attribute"))
}
}
#[proc_macro_attribute]
pub fn make_provider(attr_inp: TokenStream, input: TokenStream) -> TokenStream {
let mut ast: ItemTrait = parse_macro_input!(input);
for attr in &ast.attrs {
println!("{:?}", attr);
}
let ident = ast.ident.clone();
make_provider_strutures(&mut ast, &ident, parse_macro_input!(attr_inp))
.map_or_else(|x| x.into_compile_error(), |x| x)
.into()
}

View File

@ -1,4 +1,4 @@
use kind_report::data::{DiagnosticFrame, Marking, Severity, Color};
use kind_report::data::{Color, DiagnosticFrame, Marking, Severity};
use kind_span::Range;
use crate::lexer::tokens::Token;
@ -49,12 +49,12 @@ impl From<Box<SyntaxError>> for DiagnosticFrame {
SyntaxError::LowerCasedDefinition(name, range) => DiagnosticFrame {
code: 0,
severity: Severity::Error,
title: "The definition name should be upper cased.".to_string(),
title: "The definition name must be capitalized.".to_string(),
subtitles: vec![],
hints: vec![{
let mut c = name.chars();
let fst = c.next().unwrap().to_uppercase();
format!("Change it to '{}{}'", fst, c.as_str()).to_string()
format!("Change it to '{}{}'", fst, c.as_str())
}],
positions: vec![Marking {
position: range,
@ -74,20 +74,18 @@ impl From<Box<SyntaxError>> for DiagnosticFrame {
text: "The comment starts in this position!".to_string(),
}],
},
SyntaxError::InvalidEscapeSequence(kind, range) => {
DiagnosticFrame {
code: 0,
severity: Severity::Error,
title: format!("The {} character sequence is invalid!", encode_name(kind)),
subtitles: vec![],
hints: vec![],
positions: vec![Marking {
position: range,
color: Color::Fst,
text: "Here!".to_string(),
}],
}
}
SyntaxError::InvalidEscapeSequence(kind, range) => DiagnosticFrame {
code: 0,
severity: Severity::Error,
title: format!("The {} character sequence is invalid!", encode_name(kind)),
subtitles: vec![],
hints: vec![],
positions: vec![Marking {
position: range,
color: Color::Fst,
text: "Here!".to_string(),
}],
},
SyntaxError::InvalidNumberRepresentation(repr, range) => DiagnosticFrame {
code: 0,
severity: Severity::Error,
@ -132,4 +130,4 @@ impl From<&Box<SyntaxError>> for DiagnosticFrame {
fn from(err: &Box<SyntaxError>) -> Self {
(err.clone()).into()
}
}
}

View File

@ -97,7 +97,6 @@ impl<'a> Parser<'a> {
Ok(ident)
}
fn parse_lambda(&mut self) -> Result<Box<Expr>, SyntaxError> {
let name_span = self.range();

View File

@ -1,4 +1,4 @@
use kind_span::{Range};
use kind_span::Range;
use crate::errors::{EncodeSequence, SyntaxError};
use crate::lexer::tokens::Token;

View File

@ -45,12 +45,12 @@ impl<'a> Lexer<'a> {
"open" => Token::Open,
"return" => Token::Return,
_ => {
if data.bytes().next().map(|x| x.is_ascii_uppercase()).unwrap_or(false) {
Token::UpperId(data.to_string())
}else {
Token::LowerId(data.to_string())
}
},
if data.bytes().next().map(|x| x.is_ascii_uppercase()).unwrap_or(false) {
Token::UpperId(data.to_string())
} else {
Token::LowerId(data.to_string())
}
}
}
}

View File

@ -2,7 +2,7 @@ use std::{iter::Peekable, str::Chars};
use kind_span::{Pos, Range, SyntaxCtxIndex};
use crate::{lexer::tokens::Token};
use crate::lexer::tokens::Token;
/// The lexer state.
pub struct Lexer<'a> {

View File

@ -1,4 +1,4 @@
use kind_tree::concrete::pat::{Pat, PatKind};
use kind_tree::concrete::pat::{Pat, PatKind, PatIdent};
use crate::errors::SyntaxError;
use crate::lexer::tokens::Token;
@ -56,7 +56,7 @@ impl<'a> Parser<'a> {
let id = self.parse_id()?;
Ok(Box::new(Pat {
range: id.range,
data: PatKind::Var(id),
data: PatKind::Var(PatIdent(id)),
}))
}
@ -68,7 +68,6 @@ impl<'a> Parser<'a> {
}))
}
fn parse_pat_list(&mut self) -> Result<Box<Pat>, SyntaxError> {
let range = self.range();
self.bump(); // '['

View File

@ -1,6 +1,6 @@
use std::collections::VecDeque;
use kind_span::{Range};
use kind_span::Range;
use crate::{errors::SyntaxError, lexer::tokens::Token, Lexer};

View File

@ -1,6 +1,6 @@
/// Parses all of the top level structures
/// like Book, Entry, Rule and Argument.
use std::collections::HashMap;
use std::collections::{HashMap};
use kind_tree::concrete::{Argument, Book, Entry, Rule};
@ -13,16 +13,17 @@ fn is_hidden_arg(token: &Token) -> bool {
}
impl<'a> Parser<'a> {
pub fn is_top_level_entry(&self) -> bool {
self.get().is_upper_id() && (
self.peek(1).same_variant(Token::Colon) // ':'
pub fn is_top_level_entry_continuation(&self) -> bool {
self.peek(1).same_variant(Token::Colon) // ':'
| self.peek(1).same_variant(Token::LPar) // '('
| self.peek(1).same_variant(Token::Less) // '<'
| self.peek(1).same_variant(Token::Minus) // '-'
| self.peek(1).same_variant(Token::Plus) // '+'
)
}
pub fn is_top_level_entry(&self) -> bool {
self.get().is_upper_id() && self.is_top_level_entry_continuation()
}
pub fn complement_binding_op(&self) -> Option<Token> {
match self.get() {
@ -88,17 +89,16 @@ impl<'a> Parser<'a> {
}))
}
pub fn parse_entry(&mut self) -> Result<Box<Entry>, SyntaxError> {
pub fn parse_entry(&mut self) -> Result<Entry, SyntaxError> {
let start = self.range();
if self.get().is_lower_id() {
if self.get().is_lower_id() && self.is_top_level_entry_continuation() {
let ident = self.parse_id()?;
return Err(SyntaxError::LowerCasedDefinition(ident.data.0, ident.range));
}
// Just to make errors more localized
if !self.is_top_level_entry() {
println!("{:?} {:?}", self.get(), self.peek(1));
self.fail(vec![])?
}
@ -122,7 +122,7 @@ impl<'a> Parser<'a> {
}
}
let end = rules.last().as_ref().map(|x| x.range).unwrap_or(tipo.range);
Ok(Box::new(Entry {
Ok(Entry {
name: ident,
docs,
args,
@ -130,18 +130,18 @@ impl<'a> Parser<'a> {
rules,
attrs: Vec::new(),
range: start.mix(end),
}))
})
}
pub fn parse_book(&mut self) -> Book {
let mut entrs = HashMap::new();
let mut entries = HashMap::new();
let mut names = Vec::new();
while !self.get().same_variant(Token::Eof) {
match self.parse_entry() {
Ok(entry) => {
if entrs.get(&entry.name.data.0).is_none() {
if entries.get(&entry.name.data.0).is_none() {
names.push(entry.name.clone());
entrs.insert(entry.name.data.0.clone(), entry);
entries.insert(entry.name.data.0.clone(), entry);
}
}
Err(err) => {
@ -156,9 +156,9 @@ impl<'a> Parser<'a> {
match res {
Ok(_) => (),
Err(err) => self.errs.push(Box::new(err))
Err(err) => self.errs.push(Box::new(err)),
}
Book { names, entrs }
Book { entries, names }
}
}