Preprocess query modifiers
This commit is contained in:
parent
4f49fff019
commit
198dfceb80
1 changed files with 82 additions and 31 deletions
|
@ -1,5 +1,4 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
|
||||||
use syn::{
|
use syn::{
|
||||||
Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error,
|
Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error,
|
||||||
braced, parenthesized, parse_macro_input,
|
braced, parenthesized, parse_macro_input,
|
||||||
|
@ -21,8 +20,8 @@ struct IdentOrWild(Ident);
|
||||||
impl Parse for IdentOrWild {
|
impl Parse for IdentOrWild {
|
||||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||||
Ok(if input.peek(Token![_]) {
|
Ok(if input.peek(Token![_]) {
|
||||||
input.parse::<Token![_]>()?;
|
let underscore = input.parse::<Token![_]>()?;
|
||||||
IdentOrWild(Ident::new("_", Span::call_site()))
|
IdentOrWild(Ident::new("_", underscore.span()))
|
||||||
} else {
|
} else {
|
||||||
IdentOrWild(input.parse()?)
|
IdentOrWild(input.parse()?)
|
||||||
})
|
})
|
||||||
|
@ -31,7 +30,7 @@ impl Parse for IdentOrWild {
|
||||||
|
|
||||||
/// A modifier for a query
|
/// A modifier for a query
|
||||||
enum QueryModifier {
|
enum QueryModifier {
|
||||||
/// The description of the query
|
/// The description of the query.
|
||||||
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
|
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
|
||||||
|
|
||||||
/// Cache the query to disk if the `Expr` returns true.
|
/// Cache the query to disk if the `Expr` returns true.
|
||||||
|
@ -107,7 +106,7 @@ fn check_attributes(attrs: Vec<Attribute>) -> Result<()> {
|
||||||
|
|
||||||
/// A compiler query. `query ... { ... }`
|
/// A compiler query. `query ... { ... }`
|
||||||
struct Query {
|
struct Query {
|
||||||
attrs: List<QueryModifier>,
|
modifiers: List<QueryModifier>,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
key: IdentOrWild,
|
key: IdentOrWild,
|
||||||
arg: Type,
|
arg: Type,
|
||||||
|
@ -131,10 +130,10 @@ impl Parse for Query {
|
||||||
// Parse the query modifiers
|
// Parse the query modifiers
|
||||||
let content;
|
let content;
|
||||||
braced!(content in input);
|
braced!(content in input);
|
||||||
let attrs = content.parse()?;
|
let modifiers = content.parse()?;
|
||||||
|
|
||||||
Ok(Query {
|
Ok(Query {
|
||||||
attrs,
|
modifiers,
|
||||||
name,
|
name,
|
||||||
key,
|
key,
|
||||||
arg,
|
arg,
|
||||||
|
@ -174,24 +173,76 @@ impl Parse for Group {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct QueryModifiers {
|
||||||
|
/// The description of the query.
|
||||||
|
desc: Option<(Option<Ident>, Punctuated<Expr, Token![,]>)>,
|
||||||
|
|
||||||
|
/// Cache the query to disk if the `Expr` returns true.
|
||||||
|
cache: Option<(Option<Ident>, Expr)>,
|
||||||
|
|
||||||
|
/// Custom code to load the query from disk.
|
||||||
|
load_cached: Option<(Ident, Ident, Block)>,
|
||||||
|
|
||||||
|
/// A cycle error for this query aborting the compilation with a fatal error.
|
||||||
|
fatal_cycle: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process query modifiers into a struct, erroring on duplicates
|
||||||
|
fn process_modifiers(query: &mut Query) -> QueryModifiers {
|
||||||
|
let mut load_cached = None;
|
||||||
|
let mut cache = None;
|
||||||
|
let mut desc = None;
|
||||||
|
let mut fatal_cycle = false;
|
||||||
|
for modifier in query.modifiers.0.drain(..) {
|
||||||
|
match modifier {
|
||||||
|
QueryModifier::LoadCached(tcx, id, block) => {
|
||||||
|
if load_cached.is_some() {
|
||||||
|
panic!("duplicate modifier `load_cached` for query `{}`", query.name);
|
||||||
|
}
|
||||||
|
load_cached = Some((tcx, id, block));
|
||||||
|
}
|
||||||
|
QueryModifier::Cache(tcx, expr) => {
|
||||||
|
if cache.is_some() {
|
||||||
|
panic!("duplicate modifier `cache` for query `{}`", query.name);
|
||||||
|
}
|
||||||
|
cache = Some((tcx, expr));
|
||||||
|
}
|
||||||
|
QueryModifier::Desc(tcx, list) => {
|
||||||
|
if desc.is_some() {
|
||||||
|
panic!("duplicate modifier `desc` for query `{}`", query.name);
|
||||||
|
}
|
||||||
|
desc = Some((tcx, list));
|
||||||
|
}
|
||||||
|
QueryModifier::FatalCycle => {
|
||||||
|
if fatal_cycle {
|
||||||
|
panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
|
||||||
|
}
|
||||||
|
fatal_cycle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QueryModifiers {
|
||||||
|
load_cached,
|
||||||
|
cache,
|
||||||
|
desc,
|
||||||
|
fatal_cycle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Add the impl of QueryDescription for the query to `impls` if one is requested
|
/// Add the impl of QueryDescription for the query to `impls` if one is requested
|
||||||
fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
|
fn add_query_description_impl(
|
||||||
|
query: &Query,
|
||||||
|
modifiers: QueryModifiers,
|
||||||
|
impls: &mut proc_macro2::TokenStream
|
||||||
|
) {
|
||||||
let name = &query.name;
|
let name = &query.name;
|
||||||
let arg = &query.arg;
|
let arg = &query.arg;
|
||||||
let key = &query.key.0;
|
let key = &query.key.0;
|
||||||
|
|
||||||
// Find custom code to load the query from disk
|
|
||||||
let load_cached = query.attrs.0.iter().find_map(|attr| match attr {
|
|
||||||
QueryModifier::LoadCached(tcx, id, block) => Some((tcx, id, block)),
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Find out if we should cache the query on disk
|
// Find out if we should cache the query on disk
|
||||||
let cache = query.attrs.0.iter().find_map(|attr| match attr {
|
let cache = modifiers.cache.as_ref().map(|(tcx, expr)| {
|
||||||
QueryModifier::Cache(tcx, expr) => Some((tcx, expr)),
|
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
|
||||||
_ => None,
|
// Use custom code to load the query from disk
|
||||||
}).map(|(tcx, expr)| {
|
|
||||||
let try_load_from_disk = if let Some((tcx, id, block)) = load_cached {
|
|
||||||
quote! {
|
quote! {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_load_from_disk(
|
fn try_load_from_disk(
|
||||||
|
@ -202,6 +253,7 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Use the default code to load the query from disk
|
||||||
quote! {
|
quote! {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_load_from_disk(
|
fn try_load_from_disk(
|
||||||
|
@ -224,14 +276,11 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if cache.is_none() && load_cached.is_some() {
|
if cache.is_none() && modifiers.load_cached.is_some() {
|
||||||
panic!("load_cached modifier on query `{}` without a cache modifier", name);
|
panic!("load_cached modifier on query `{}` without a cache modifier", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let desc = query.attrs.0.iter().find_map(|attr| match attr {
|
let desc = modifiers.desc.as_ref().map(|(tcx, desc)| {
|
||||||
QueryModifier::Desc(tcx, desc) => Some((tcx, desc)),
|
|
||||||
_ => None,
|
|
||||||
}).map(|(tcx, desc)| {
|
|
||||||
let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
|
let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
|
||||||
quote! {
|
quote! {
|
||||||
fn describe(
|
fn describe(
|
||||||
|
@ -266,7 +315,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
for group in groups.0 {
|
for group in groups.0 {
|
||||||
let mut group_stream = quote! {};
|
let mut group_stream = quote! {};
|
||||||
for query in &group.queries.0 {
|
for mut query in group.queries.0 {
|
||||||
|
let modifiers = process_modifiers(&mut query);
|
||||||
let name = &query.name;
|
let name = &query.name;
|
||||||
let arg = &query.arg;
|
let arg = &query.arg;
|
||||||
let result_full = &query.result;
|
let result_full = &query.result;
|
||||||
|
@ -275,18 +325,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
||||||
_ => quote! { #result_full },
|
_ => quote! { #result_full },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Look for a fatal_cycle modifier to pass on
|
// Pass on the fatal_cycle modifier
|
||||||
let fatal_cycle = query.attrs.0.iter().find_map(|attr| match attr {
|
let fatal_cycle = if modifiers.fatal_cycle {
|
||||||
QueryModifier::FatalCycle => Some(()),
|
quote! { fatal_cycle }
|
||||||
_ => None,
|
} else {
|
||||||
}).map(|_| quote! { fatal_cycle }).unwrap_or(quote! {});
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
// Add the query to the group
|
// Add the query to the group
|
||||||
group_stream.extend(quote! {
|
group_stream.extend(quote! {
|
||||||
[#fatal_cycle] fn #name: #name(#arg) #result,
|
[#fatal_cycle] fn #name: #name(#arg) #result,
|
||||||
});
|
});
|
||||||
|
|
||||||
add_query_description_impl(query, &mut query_description_stream);
|
add_query_description_impl(&query, modifiers, &mut query_description_stream);
|
||||||
|
|
||||||
// Create a dep node for the query
|
// Create a dep node for the query
|
||||||
dep_node_def_stream.extend(quote! {
|
dep_node_def_stream.extend(quote! {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue