Skip to content

Commit

Permalink
Avoid calculating spans eagerly in Spanned derives
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Aug 21, 2023
1 parent b8fd316 commit 354b1ee
Show file tree
Hide file tree
Showing 19 changed files with 885 additions and 558 deletions.
2 changes: 1 addition & 1 deletion crates/rune-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ categories = ["parser-implementations"]
rune-core = { version = "=0.12.3", path = "../rune-core" }
syn = { version = "2.0.16", features = ["full"] }
quote = "1.0.27"
proc-macro2 = { version = "1.0.56", features = ["span-locations"] }
proc-macro2 = "1.0.56"

[lib]
proc-macro = true
Expand Down
124 changes: 14 additions & 110 deletions crates/rune-macros/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub(crate) struct FieldAttrs {
/// `#[rune(iter)]`
pub(crate) iter: Option<Span>,
/// `#[rune(skip)]`
skip: Option<Span>,
pub(crate) skip: Option<Span>,
/// `#[rune(optional)]`
pub(crate) optional: Option<Span>,
/// `#[rune(meta)]`
Expand Down Expand Up @@ -147,6 +147,11 @@ impl Context {
self.errors.borrow_mut().push(error)
}

/// Test if context has any errors.
pub(crate) fn has_errors(&self) -> bool {
!self.errors.borrow().is_empty()
}

/// Get a field identifier.
pub(crate) fn field_ident<'a>(&self, field: &'a syn::Field) -> Result<&'a syn::Ident, ()> {
let Some(ident) = &field.ident else {
Expand Down Expand Up @@ -525,115 +530,6 @@ impl Context {
Ok(Some(parse_path_compat(input)?))
}

/// Build an inner spanned decoder from an iterator.
pub(crate) fn build_spanned_iter<'a>(
&self,
tokens: &Tokens,
back: bool,
mut it: impl Iterator<Item = (Result<TokenStream, ()>, &'a syn::Field)>,
) -> Result<(bool, Option<TokenStream>), ()> {
let mut quote = None::<TokenStream>;

loop {
let (var, field) = match it.next() {
Some((var, field)) => (var?, field),
None => {
return Ok((true, quote));
}
};

let attrs = self.field_attrs(&field.attrs)?;

let spanned = &tokens.spanned;

if attrs.skip() {
continue;
}

if attrs.optional.is_some() {
let option_spanned = &tokens.option_spanned;
let next = quote_spanned! {
field.span() => #option_spanned::option_span(#var)
};

if quote.is_some() {
quote = Some(quote_spanned! {
field.span() => #quote.or_else(|| #next)
});
} else {
quote = Some(next);
}

continue;
}

if attrs.iter.is_some() {
let next = if back {
quote_spanned!(field.span() => next_back)
} else {
quote_spanned!(field.span() => next)
};

let spanned = &tokens.spanned;
let next = quote_spanned! {
field.span() => IntoIterator::into_iter(#var).#next().map(#spanned::span)
};

if quote.is_some() {
quote = Some(quote_spanned! {
field.span() => #quote.or_else(|| #next)
});
} else {
quote = Some(next);
}

continue;
}

if quote.is_some() {
quote = Some(quote_spanned! {
field.span() => #quote.unwrap_or_else(|| #spanned::span(#var))
});
} else {
quote = Some(quote_spanned! {
field.span() => #spanned::span(#var)
});
}

return Ok((false, quote));
}
}

/// Explicit span for fields.
pub(crate) fn explicit_span(
&self,
named: &syn::FieldsNamed,
) -> Result<Option<TokenStream>, ()> {
let mut explicit_span = None;

for field in &named.named {
let attrs = self.field_attrs(&field.attrs)?;

if let Some(span) = attrs.span {
if explicit_span.is_some() {
self.error(syn::Error::new(
span,
"Only one field can be marked `#[rune(span)]`",
));
return Err(());
}

let ident = &field.ident;

explicit_span = Some(quote_spanned! {
field.span() => self.#ident
});
}
}

Ok(explicit_span)
}

pub(crate) fn tokens_with_module(&self, module: Option<&syn::Path>) -> Tokens {
let mut core = syn::Path {
leading_colon: Some(<Token![::]>::default()),
Expand Down Expand Up @@ -707,6 +603,10 @@ impl Context {
variant_data: path(m, ["runtime", "VariantData"]),
vm_error: path(m, ["runtime", "VmError"]),
vm_result: path(m, ["runtime", "VmResult"]),
into_iterator: path(&core, ["iter", "IntoIterator"]),
iterator: path(&core, ["iter", "Iterator"]),
double_ended_iterator: path(&core, ["iter", "DoubleEndedIterator"]),
option: path(&core, ["option", "Option"]),
}
}
}
Expand Down Expand Up @@ -784,6 +684,10 @@ pub(crate) struct Tokens {
pub(crate) variant_data: syn::Path,
pub(crate) vm_error: syn::Path,
pub(crate) vm_result: syn::Path,
pub(crate) into_iterator: syn::Path,
pub(crate) iterator: syn::Path,
pub(crate) double_ended_iterator: syn::Path,
pub(crate) option: syn::Path,
}

impl Tokens {
Expand Down
6 changes: 4 additions & 2 deletions crates/rune-macros/src/instrument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ impl Expander {
let _instrument_span = ::tracing::span!(::tracing::Level::TRACE, #ident);
let _instrument_enter = _instrument_span.enter();

if let Some(source) = #a.q.sources.source(#a.source_id, Spanned::span(&#span)) {
::tracing::trace!("{:?}", source);
if ::tracing::enabled!(::tracing::Level::TRACE) {
if let Some(source) = #a.q.sources.source(#a.source_id, Spanned::span(&#span)) {
::tracing::trace!("{:?}", source);
}
}
}),
None => Some(quote! {
Expand Down
29 changes: 13 additions & 16 deletions crates/rune-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ mod internals;
mod macro_;
mod module;
mod opaque;
mod option_spanned;
mod parse;
mod quote;
mod spanned;
Expand Down Expand Up @@ -139,14 +138,17 @@ pub fn parse(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
#[doc(hidden)]
pub fn spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let derive = syn::parse_macro_input!(input as spanned::Derive);
derive.expand().unwrap_or_else(to_compile_errors).into()
derive
.expand(false)
.unwrap_or_else(to_compile_errors)
.into()
}

#[proc_macro_derive(OptionSpanned, attributes(rune))]
#[doc(hidden)]
pub fn option_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let derive = syn::parse_macro_input!(input as option_spanned::Derive);
derive.expand().unwrap_or_else(to_compile_errors).into()
let derive = syn::parse_macro_input!(input as spanned::Derive);
derive.expand(true).unwrap_or_else(to_compile_errors).into()
}

#[proc_macro_derive(Opaque, attributes(rune))]
Expand Down Expand Up @@ -217,17 +219,12 @@ fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {

/// Adds the `path` as trait bound to each generic
fn add_trait_bounds(generics: &mut Generics, path: &Path) {
for p in &mut generics.params {
match p {
syn::GenericParam::Type(ty) => {
ty.bounds.push(syn::TypeParamBound::Trait(syn::TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: path.clone(),
}));
}
_ => continue,
}
for ty in &mut generics.type_params_mut() {
ty.bounds.push(syn::TypeParamBound::Trait(syn::TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: path.clone(),
}));
}
}
Loading

0 comments on commit 354b1ee

Please sign in to comment.